From f437bcabf31fb4a28ccef817fbf90b0c03b42e06 Mon Sep 17 00:00:00 2001 From: ladddder <151469127+ladddder@users.noreply.github.com> Date: Tue, 5 Dec 2023 16:00:31 +0100 Subject: [PATCH 1/4] move auth and favicon form main to handlers, linting --- cmd/main.go | 25 +- handlers/auth.go | 25 ++ handlers/favicon.go | 18 ++ {cmd => handlers}/favicon.ico | Bin handlers/proxy.go | 8 +- proxychain/codegen/codegen.go | 8 +- .../modify_path_with_regex.go | 3 +- .../patch_google_analytics.go | 3 +- .../patch_tracker_scripts.go | 3 +- proxychain/ruleset/rule.go | 3 +- proxychain/ruleset/rule_reqmod_types.gen.go | 251 +++++++++--------- proxychain/ruleset/rule_resmod_types.gen.go | 125 +++++---- proxychain/ruleset/rule_test.go | 3 +- 13 files changed, 249 insertions(+), 226 deletions(-) create mode 100644 handlers/auth.go create mode 100644 handlers/favicon.go rename {cmd => handlers}/favicon.ico (100%) diff --git a/cmd/main.go b/cmd/main.go index daaa7a8..cf22557 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -6,7 +6,6 @@ import ( "html/template" "log" "os" - "strings" "ladder/handlers" "ladder/internal/cli" @@ -14,14 +13,9 @@ import ( "github.com/akamensky/argparse" "github.com/gofiber/fiber/v2" - "github.com/gofiber/fiber/v2/middleware/basicauth" - "github.com/gofiber/fiber/v2/middleware/favicon" "github.com/gofiber/template/html/v2" ) -//go:embed favicon.ico -var faviconData string - //go:embed styles.css var cssData embed.FS @@ -151,23 +145,8 @@ func main() { }, ) - // TODO: move to cmd/auth.go - userpass := os.Getenv("USERPASS") - if userpass != "" { - userpass := strings.Split(userpass, ":") - - app.Use(basicauth.New(basicauth.Config{ - Users: map[string]string{ - userpass[0]: userpass[1], - }, - })) - } - - // TODO: move to handlers/favicon.go - app.Use(favicon.New(favicon.Config{ - Data: []byte(faviconData), - URL: "/favicon.ico", - })) + app.Use(handlers.Auth()) + app.Use(handlers.Favicon()) if os.Getenv("NOLOGS") != "true" { app.Use(func(c *fiber.Ctx) error { diff --git a/handlers/auth.go b/handlers/auth.go new file mode 100644 index 0000000..5eaf455 --- /dev/null +++ b/handlers/auth.go @@ -0,0 +1,25 @@ +package handlers + +import ( + "os" + "strings" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/basicauth" +) + +func Auth() fiber.Handler { + userpass := os.Getenv("USERPASS") + if userpass != "" { + userpass := strings.Split(userpass, ":") + return basicauth.New(basicauth.Config{ + Users: map[string]string{ + userpass[0]: userpass[1], + }, + }) + } + + return func(c *fiber.Ctx) error { + return c.Next() + } +} diff --git a/handlers/favicon.go b/handlers/favicon.go new file mode 100644 index 0000000..1c93d68 --- /dev/null +++ b/handlers/favicon.go @@ -0,0 +1,18 @@ +package handlers + +import ( + _ "embed" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/favicon" +) + +//go:embed favicon.ico +var faviconData string + +func Favicon() fiber.Handler { + return favicon.New(favicon.Config{ + Data: []byte(faviconData), + URL: "/favicon.ico", + }) +} diff --git a/cmd/favicon.ico b/handlers/favicon.ico similarity index 100% rename from cmd/favicon.ico rename to handlers/favicon.ico diff --git a/handlers/proxy.go b/handlers/proxy.go index ce5e57c..d22678f 100644 --- a/handlers/proxy.go +++ b/handlers/proxy.go @@ -33,13 +33,13 @@ func NewProxySiteHandler(opts *ProxyOptions) fiber.Handler { SetRequestModifications( // rx.SpoofJA3fingerprint(ja3, "Googlebot"), // rx.MasqueradeAsFacebookBot(), - //rx.MasqueradeAsGoogleBot(), + // rx.MasqueradeAsGoogleBot(), rx.DeleteOutgoingCookies(), rx.ForwardRequestHeaders(), - //rx.SpoofReferrerFromGoogleSearch(), + // rx.SpoofReferrerFromGoogleSearch(), rx.SpoofReferrerFromLinkedInPost(), - //rx.RequestWaybackMachine(), - //rx.RequestArchiveIs(), + // rx.RequestWaybackMachine(), + // rx.RequestArchiveIs(), ). AddResponseModifications( tx.ForwardResponseHeaders(), diff --git a/proxychain/codegen/codegen.go b/proxychain/codegen/codegen.go index 016b5c0..dacca5a 100644 --- a/proxychain/codegen/codegen.go +++ b/proxychain/codegen/codegen.go @@ -83,7 +83,7 @@ func init() { %s }`, strings.Join(factoryMaps, "\n")) - //fmt.Println(code) + // fmt.Println(code) return code, nil } @@ -155,7 +155,7 @@ func init() { %s }`, strings.Join(factoryMaps, "\n")) - //fmt.Println(code) + // fmt.Println(code) return code, nil } @@ -177,7 +177,7 @@ func main() { if err != nil { panic(err) } - //fmt.Println(rqmCode) + // fmt.Println(rqmCode) fq, err := os.Create("../ruleset/rule_reqmod_types.gen.go") if err != nil { @@ -192,7 +192,7 @@ func main() { if err != nil { panic(err) } - //fmt.Println(rsmCode) + // fmt.Println(rsmCode) fs, err := os.Create("../ruleset/rule_resmod_types.gen.go") if err != nil { diff --git a/proxychain/requestmodifiers/modify_path_with_regex.go b/proxychain/requestmodifiers/modify_path_with_regex.go index f9624fe..c2514a3 100644 --- a/proxychain/requestmodifiers/modify_path_with_regex.go +++ b/proxychain/requestmodifiers/modify_path_with_regex.go @@ -2,8 +2,9 @@ package requestmodifiers import ( "fmt" - "ladder/proxychain" "regexp" + + "ladder/proxychain" ) func ModifyPathWithRegex(matchRegex string, replacement string) proxychain.RequestModification { diff --git a/proxychain/responsemodifiers/patch_google_analytics.go b/proxychain/responsemodifiers/patch_google_analytics.go index 793d9ab..51e8639 100644 --- a/proxychain/responsemodifiers/patch_google_analytics.go +++ b/proxychain/responsemodifiers/patch_google_analytics.go @@ -3,8 +3,9 @@ package responsemodifiers import ( _ "embed" "io" - "ladder/proxychain" "strings" + + "ladder/proxychain" ) //go:embed patch_google_analytics.js diff --git a/proxychain/responsemodifiers/patch_tracker_scripts.go b/proxychain/responsemodifiers/patch_tracker_scripts.go index 7d4abcb..1d1aaa7 100644 --- a/proxychain/responsemodifiers/patch_tracker_scripts.go +++ b/proxychain/responsemodifiers/patch_tracker_scripts.go @@ -4,9 +4,10 @@ import ( "embed" "encoding/json" "io" - "ladder/proxychain" "log" "regexp" + + "ladder/proxychain" ) //go:embed vendor/ddg-tracker-surrogates/mapping.json diff --git a/proxychain/ruleset/rule.go b/proxychain/ruleset/rule.go index 0d15c69..ccc8bc6 100644 --- a/proxychain/ruleset/rule.go +++ b/proxychain/ruleset/rule.go @@ -3,6 +3,7 @@ package ruleset_v2 import ( "encoding/json" "fmt" + "gopkg.in/yaml.v3" "ladder/proxychain" ) @@ -84,7 +85,6 @@ func (rule *Rule) MarshalJSON() ([]byte, error) { // implement type yaml marshaller func (rule *Rule) UnmarshalYAML(unmarshal func(interface{}) error) error { - type Aux struct { Domains []string `yaml:"domains"` RequestModifications []_rqm `yaml:"requestmodifications"` @@ -122,7 +122,6 @@ func (rule *Rule) UnmarshalYAML(unmarshal func(interface{}) error) error { } func (rule *Rule) MarshalYAML() (interface{}, error) { - type Aux struct { Domains []string `yaml:"domains"` RequestModifications []_rqm `yaml:"requestmodifications"` diff --git a/proxychain/ruleset/rule_reqmod_types.gen.go b/proxychain/ruleset/rule_reqmod_types.gen.go index 7f22c3e..f055d28 100644 --- a/proxychain/ruleset/rule_reqmod_types.gen.go +++ b/proxychain/ruleset/rule_reqmod_types.gen.go @@ -1,5 +1,5 @@ - package ruleset_v2 + // DO NOT EDIT THIS FILE. It is automatically generated by ladder/proxychain/codegen/codegen.go // The purpose of this is serialization of rulesets from JSON or YAML into functional options suitable // for use in proxychains. @@ -16,168 +16,167 @@ var rqmModMap map[string]RequestModifierFactory func init() { rqmModMap = make(map[string]RequestModifierFactory) - rqmModMap["ForwardRequestHeaders"] = func(_ ...string) proxychain.RequestModification { - return rx.ForwardRequestHeaders() - } + rqmModMap["ForwardRequestHeaders"] = func(_ ...string) proxychain.RequestModification { + return rx.ForwardRequestHeaders() + } - rqmModMap["MasqueradeAsGoogleBot"] = func(_ ...string) proxychain.RequestModification { - return rx.MasqueradeAsGoogleBot() - } + rqmModMap["MasqueradeAsGoogleBot"] = func(_ ...string) proxychain.RequestModification { + return rx.MasqueradeAsGoogleBot() + } - rqmModMap["MasqueradeAsBingBot"] = func(_ ...string) proxychain.RequestModification { - return rx.MasqueradeAsBingBot() - } + rqmModMap["MasqueradeAsBingBot"] = func(_ ...string) proxychain.RequestModification { + return rx.MasqueradeAsBingBot() + } - rqmModMap["MasqueradeAsWaybackMachineBot"] = func(_ ...string) proxychain.RequestModification { - return rx.MasqueradeAsWaybackMachineBot() - } + rqmModMap["MasqueradeAsWaybackMachineBot"] = func(_ ...string) proxychain.RequestModification { + return rx.MasqueradeAsWaybackMachineBot() + } - rqmModMap["MasqueradeAsFacebookBot"] = func(_ ...string) proxychain.RequestModification { - return rx.MasqueradeAsFacebookBot() - } + rqmModMap["MasqueradeAsFacebookBot"] = func(_ ...string) proxychain.RequestModification { + return rx.MasqueradeAsFacebookBot() + } - rqmModMap["MasqueradeAsYandexBot"] = func(_ ...string) proxychain.RequestModification { - return rx.MasqueradeAsYandexBot() - } + rqmModMap["MasqueradeAsYandexBot"] = func(_ ...string) proxychain.RequestModification { + return rx.MasqueradeAsYandexBot() + } - rqmModMap["MasqueradeAsBaiduBot"] = func(_ ...string) proxychain.RequestModification { - return rx.MasqueradeAsBaiduBot() - } + rqmModMap["MasqueradeAsBaiduBot"] = func(_ ...string) proxychain.RequestModification { + return rx.MasqueradeAsBaiduBot() + } - rqmModMap["MasqueradeAsDuckDuckBot"] = func(_ ...string) proxychain.RequestModification { - return rx.MasqueradeAsDuckDuckBot() - } + rqmModMap["MasqueradeAsDuckDuckBot"] = func(_ ...string) proxychain.RequestModification { + return rx.MasqueradeAsDuckDuckBot() + } - rqmModMap["MasqueradeAsYahooBot"] = func(_ ...string) proxychain.RequestModification { - return rx.MasqueradeAsYahooBot() - } + rqmModMap["MasqueradeAsYahooBot"] = func(_ ...string) proxychain.RequestModification { + return rx.MasqueradeAsYahooBot() + } - rqmModMap["ModifyDomainWithRegex"] = func(params ...string) proxychain.RequestModification { - return rx.ModifyDomainWithRegex(params[0], params[1]) - } + rqmModMap["ModifyDomainWithRegex"] = func(params ...string) proxychain.RequestModification { + return rx.ModifyDomainWithRegex(params[0], params[1]) + } - rqmModMap["SetOutgoingCookie"] = func(params ...string) proxychain.RequestModification { - return rx.SetOutgoingCookie(params[0], params[1]) - } + rqmModMap["SetOutgoingCookie"] = func(params ...string) proxychain.RequestModification { + return rx.SetOutgoingCookie(params[0], params[1]) + } - rqmModMap["SetOutgoingCookies"] = func(params ...string) proxychain.RequestModification { - return rx.SetOutgoingCookies(params[0]) - } + rqmModMap["SetOutgoingCookies"] = func(params ...string) proxychain.RequestModification { + return rx.SetOutgoingCookies(params[0]) + } - rqmModMap["DeleteOutgoingCookie"] = func(params ...string) proxychain.RequestModification { - return rx.DeleteOutgoingCookie(params[0]) - } + rqmModMap["DeleteOutgoingCookie"] = func(params ...string) proxychain.RequestModification { + return rx.DeleteOutgoingCookie(params[0]) + } - rqmModMap["DeleteOutgoingCookies"] = func(_ ...string) proxychain.RequestModification { - return rx.DeleteOutgoingCookies() - } + rqmModMap["DeleteOutgoingCookies"] = func(_ ...string) proxychain.RequestModification { + return rx.DeleteOutgoingCookies() + } - rqmModMap["DeleteOutgoingCookiesExcept"] = func(params ...string) proxychain.RequestModification { - return rx.DeleteOutgoingCookiesExcept(params[0]) - } + rqmModMap["DeleteOutgoingCookiesExcept"] = func(params ...string) proxychain.RequestModification { + return rx.DeleteOutgoingCookiesExcept(params[0]) + } - rqmModMap["ModifyPathWithRegex"] = func(params ...string) proxychain.RequestModification { - return rx.ModifyPathWithRegex(params[0], params[1]) - } + rqmModMap["ModifyPathWithRegex"] = func(params ...string) proxychain.RequestModification { + return rx.ModifyPathWithRegex(params[0], params[1]) + } - rqmModMap["ModifyQueryParams"] = func(params ...string) proxychain.RequestModification { - return rx.ModifyQueryParams(params[0], params[1]) - } + rqmModMap["ModifyQueryParams"] = func(params ...string) proxychain.RequestModification { + return rx.ModifyQueryParams(params[0], params[1]) + } - rqmModMap["SetRequestHeader"] = func(params ...string) proxychain.RequestModification { - return rx.SetRequestHeader(params[0], params[1]) - } + rqmModMap["SetRequestHeader"] = func(params ...string) proxychain.RequestModification { + return rx.SetRequestHeader(params[0], params[1]) + } - rqmModMap["DeleteRequestHeader"] = func(params ...string) proxychain.RequestModification { - return rx.DeleteRequestHeader(params[0]) - } + rqmModMap["DeleteRequestHeader"] = func(params ...string) proxychain.RequestModification { + return rx.DeleteRequestHeader(params[0]) + } - rqmModMap["RequestArchiveIs"] = func(_ ...string) proxychain.RequestModification { - return rx.RequestArchiveIs() - } + rqmModMap["RequestArchiveIs"] = func(_ ...string) proxychain.RequestModification { + return rx.RequestArchiveIs() + } - rqmModMap["RequestGoogleCache"] = func(_ ...string) proxychain.RequestModification { - return rx.RequestGoogleCache() - } + rqmModMap["RequestGoogleCache"] = func(_ ...string) proxychain.RequestModification { + return rx.RequestGoogleCache() + } - rqmModMap["RequestWaybackMachine"] = func(_ ...string) proxychain.RequestModification { - return rx.RequestWaybackMachine() - } + rqmModMap["RequestWaybackMachine"] = func(_ ...string) proxychain.RequestModification { + return rx.RequestWaybackMachine() + } - rqmModMap["ResolveWithGoogleDoH"] = func(_ ...string) proxychain.RequestModification { - return rx.ResolveWithGoogleDoH() - } + rqmModMap["ResolveWithGoogleDoH"] = func(_ ...string) proxychain.RequestModification { + return rx.ResolveWithGoogleDoH() + } - rqmModMap["SpoofOrigin"] = func(params ...string) proxychain.RequestModification { - return rx.SpoofOrigin(params[0]) - } + rqmModMap["SpoofOrigin"] = func(params ...string) proxychain.RequestModification { + return rx.SpoofOrigin(params[0]) + } - rqmModMap["HideOrigin"] = func(_ ...string) proxychain.RequestModification { - return rx.HideOrigin() - } + rqmModMap["HideOrigin"] = func(_ ...string) proxychain.RequestModification { + return rx.HideOrigin() + } - rqmModMap["SpoofReferrer"] = func(params ...string) proxychain.RequestModification { - return rx.SpoofReferrer(params[0]) - } + rqmModMap["SpoofReferrer"] = func(params ...string) proxychain.RequestModification { + return rx.SpoofReferrer(params[0]) + } - rqmModMap["HideReferrer"] = func(_ ...string) proxychain.RequestModification { - return rx.HideReferrer() - } + rqmModMap["HideReferrer"] = func(_ ...string) proxychain.RequestModification { + return rx.HideReferrer() + } - rqmModMap["SpoofReferrerFromBaiduSearch"] = func(_ ...string) proxychain.RequestModification { - return rx.SpoofReferrerFromBaiduSearch() - } + rqmModMap["SpoofReferrerFromBaiduSearch"] = func(_ ...string) proxychain.RequestModification { + return rx.SpoofReferrerFromBaiduSearch() + } - rqmModMap["SpoofReferrerFromBingSearch"] = func(_ ...string) proxychain.RequestModification { - return rx.SpoofReferrerFromBingSearch() - } + rqmModMap["SpoofReferrerFromBingSearch"] = func(_ ...string) proxychain.RequestModification { + return rx.SpoofReferrerFromBingSearch() + } - rqmModMap["SpoofReferrerFromGoogleSearch"] = func(_ ...string) proxychain.RequestModification { - return rx.SpoofReferrerFromGoogleSearch() - } + rqmModMap["SpoofReferrerFromGoogleSearch"] = func(_ ...string) proxychain.RequestModification { + return rx.SpoofReferrerFromGoogleSearch() + } - rqmModMap["SpoofReferrerFromLinkedInPost"] = func(_ ...string) proxychain.RequestModification { - return rx.SpoofReferrerFromLinkedInPost() - } + rqmModMap["SpoofReferrerFromLinkedInPost"] = func(_ ...string) proxychain.RequestModification { + return rx.SpoofReferrerFromLinkedInPost() + } - rqmModMap["SpoofReferrerFromNaverSearch"] = func(_ ...string) proxychain.RequestModification { - return rx.SpoofReferrerFromNaverSearch() - } + rqmModMap["SpoofReferrerFromNaverSearch"] = func(_ ...string) proxychain.RequestModification { + return rx.SpoofReferrerFromNaverSearch() + } - rqmModMap["SpoofReferrerFromPinterestPost"] = func(_ ...string) proxychain.RequestModification { - return rx.SpoofReferrerFromPinterestPost() - } + rqmModMap["SpoofReferrerFromPinterestPost"] = func(_ ...string) proxychain.RequestModification { + return rx.SpoofReferrerFromPinterestPost() + } - rqmModMap["SpoofReferrerFromQQPost"] = func(_ ...string) proxychain.RequestModification { - return rx.SpoofReferrerFromQQPost() - } + rqmModMap["SpoofReferrerFromQQPost"] = func(_ ...string) proxychain.RequestModification { + return rx.SpoofReferrerFromQQPost() + } - rqmModMap["SpoofReferrerFromRedditPost"] = func(_ ...string) proxychain.RequestModification { - return rx.SpoofReferrerFromRedditPost() - } + rqmModMap["SpoofReferrerFromRedditPost"] = func(_ ...string) proxychain.RequestModification { + return rx.SpoofReferrerFromRedditPost() + } - rqmModMap["SpoofReferrerFromTumblrPost"] = func(_ ...string) proxychain.RequestModification { - return rx.SpoofReferrerFromTumblrPost() - } + rqmModMap["SpoofReferrerFromTumblrPost"] = func(_ ...string) proxychain.RequestModification { + return rx.SpoofReferrerFromTumblrPost() + } - rqmModMap["SpoofReferrerFromTwitterPost"] = func(_ ...string) proxychain.RequestModification { - return rx.SpoofReferrerFromTwitterPost() - } + rqmModMap["SpoofReferrerFromTwitterPost"] = func(_ ...string) proxychain.RequestModification { + return rx.SpoofReferrerFromTwitterPost() + } - rqmModMap["SpoofReferrerFromVkontaktePost"] = func(_ ...string) proxychain.RequestModification { - return rx.SpoofReferrerFromVkontaktePost() - } + rqmModMap["SpoofReferrerFromVkontaktePost"] = func(_ ...string) proxychain.RequestModification { + return rx.SpoofReferrerFromVkontaktePost() + } - rqmModMap["SpoofReferrerFromWeiboPost"] = func(_ ...string) proxychain.RequestModification { - return rx.SpoofReferrerFromWeiboPost() - } + rqmModMap["SpoofReferrerFromWeiboPost"] = func(_ ...string) proxychain.RequestModification { + return rx.SpoofReferrerFromWeiboPost() + } - rqmModMap["SpoofUserAgent"] = func(params ...string) proxychain.RequestModification { - return rx.SpoofUserAgent(params[0]) - } + rqmModMap["SpoofUserAgent"] = func(params ...string) proxychain.RequestModification { + return rx.SpoofUserAgent(params[0]) + } - rqmModMap["SpoofXForwardedFor"] = func(params ...string) proxychain.RequestModification { - return rx.SpoofXForwardedFor(params[0]) - } - -} \ No newline at end of file + rqmModMap["SpoofXForwardedFor"] = func(params ...string) proxychain.RequestModification { + return rx.SpoofXForwardedFor(params[0]) + } +} diff --git a/proxychain/ruleset/rule_resmod_types.gen.go b/proxychain/ruleset/rule_resmod_types.gen.go index f6ec8c0..ea869a3 100644 --- a/proxychain/ruleset/rule_resmod_types.gen.go +++ b/proxychain/ruleset/rule_resmod_types.gen.go @@ -1,5 +1,5 @@ - package ruleset_v2 + // DO NOT EDIT THIS FILE. It is automatically generated by ladder/proxychain/codegen/codegen.go // The purpose of this is serialization of rulesets from JSON or YAML into functional options suitable // for use in proxychains. @@ -16,84 +16,83 @@ var rsmModMap map[string]ResponseModifierFactory func init() { rsmModMap = make(map[string]ResponseModifierFactory) - rsmModMap["APIContent"] = func(_ ...string) proxychain.ResponseModification { - return tx.APIContent() - } + rsmModMap["APIContent"] = func(_ ...string) proxychain.ResponseModification { + return tx.APIContent() + } - rsmModMap["BlockElementRemoval"] = func(params ...string) proxychain.ResponseModification { - return tx.BlockElementRemoval(params[0]) - } + rsmModMap["BlockElementRemoval"] = func(params ...string) proxychain.ResponseModification { + return tx.BlockElementRemoval(params[0]) + } - rsmModMap["BypassCORS"] = func(_ ...string) proxychain.ResponseModification { - return tx.BypassCORS() - } + rsmModMap["BypassCORS"] = func(_ ...string) proxychain.ResponseModification { + return tx.BypassCORS() + } - rsmModMap["BypassContentSecurityPolicy"] = func(_ ...string) proxychain.ResponseModification { - return tx.BypassContentSecurityPolicy() - } + rsmModMap["BypassContentSecurityPolicy"] = func(_ ...string) proxychain.ResponseModification { + return tx.BypassContentSecurityPolicy() + } - rsmModMap["SetContentSecurityPolicy"] = func(params ...string) proxychain.ResponseModification { - return tx.SetContentSecurityPolicy(params[0]) - } + rsmModMap["SetContentSecurityPolicy"] = func(params ...string) proxychain.ResponseModification { + return tx.SetContentSecurityPolicy(params[0]) + } - rsmModMap["ForwardResponseHeaders"] = func(_ ...string) proxychain.ResponseModification { - return tx.ForwardResponseHeaders() - } + rsmModMap["ForwardResponseHeaders"] = func(_ ...string) proxychain.ResponseModification { + return tx.ForwardResponseHeaders() + } - rsmModMap["GenerateReadableOutline"] = func(_ ...string) proxychain.ResponseModification { - return tx.GenerateReadableOutline() - } + rsmModMap["GenerateReadableOutline"] = func(_ ...string) proxychain.ResponseModification { + return tx.GenerateReadableOutline() + } - rsmModMap["InjectScriptBeforeDOMContentLoaded"] = func(params ...string) proxychain.ResponseModification { - return tx.InjectScriptBeforeDOMContentLoaded(params[0]) - } + rsmModMap["InjectScriptBeforeDOMContentLoaded"] = func(params ...string) proxychain.ResponseModification { + return tx.InjectScriptBeforeDOMContentLoaded(params[0]) + } - rsmModMap["InjectScriptAfterDOMContentLoaded"] = func(params ...string) proxychain.ResponseModification { - return tx.InjectScriptAfterDOMContentLoaded(params[0]) - } + rsmModMap["InjectScriptAfterDOMContentLoaded"] = func(params ...string) proxychain.ResponseModification { + return tx.InjectScriptAfterDOMContentLoaded(params[0]) + } - rsmModMap["InjectScriptAfterDOMIdle"] = func(params ...string) proxychain.ResponseModification { - return tx.InjectScriptAfterDOMIdle(params[0]) - } + rsmModMap["InjectScriptAfterDOMIdle"] = func(params ...string) proxychain.ResponseModification { + return tx.InjectScriptAfterDOMIdle(params[0]) + } - rsmModMap["DeleteIncomingCookies"] = func(params ...string) proxychain.ResponseModification { - return tx.DeleteIncomingCookies(params[0]) - } + rsmModMap["DeleteIncomingCookies"] = func(params ...string) proxychain.ResponseModification { + return tx.DeleteIncomingCookies(params[0]) + } - rsmModMap["DeleteIncomingCookiesExcept"] = func(params ...string) proxychain.ResponseModification { - return tx.DeleteIncomingCookiesExcept(params[0]) - } + rsmModMap["DeleteIncomingCookiesExcept"] = func(params ...string) proxychain.ResponseModification { + return tx.DeleteIncomingCookiesExcept(params[0]) + } - rsmModMap["SetIncomingCookies"] = func(params ...string) proxychain.ResponseModification { - return tx.SetIncomingCookies(params[0]) - } + rsmModMap["SetIncomingCookies"] = func(params ...string) proxychain.ResponseModification { + return tx.SetIncomingCookies(params[0]) + } - rsmModMap["SetIncomingCookie"] = func(params ...string) proxychain.ResponseModification { - return tx.SetIncomingCookie(params[0], params[1]) - } + rsmModMap["SetIncomingCookie"] = func(params ...string) proxychain.ResponseModification { + return tx.SetIncomingCookie(params[0], params[1]) + } - rsmModMap["SetResponseHeader"] = func(params ...string) proxychain.ResponseModification { - return tx.SetResponseHeader(params[0], params[1]) - } + rsmModMap["SetResponseHeader"] = func(params ...string) proxychain.ResponseModification { + return tx.SetResponseHeader(params[0], params[1]) + } - rsmModMap["DeleteResponseHeader"] = func(params ...string) proxychain.ResponseModification { - return tx.DeleteResponseHeader(params[0]) - } + rsmModMap["DeleteResponseHeader"] = func(params ...string) proxychain.ResponseModification { + return tx.DeleteResponseHeader(params[0]) + } - rsmModMap["PatchDynamicResourceURLs"] = func(_ ...string) proxychain.ResponseModification { - return tx.PatchDynamicResourceURLs() - } + rsmModMap["PatchDynamicResourceURLs"] = func(_ ...string) proxychain.ResponseModification { + return tx.PatchDynamicResourceURLs() + } - rsmModMap["PatchGoogleAnalytics"] = func(_ ...string) proxychain.ResponseModification { - return tx.PatchGoogleAnalytics() - } + rsmModMap["PatchGoogleAnalytics"] = func(_ ...string) proxychain.ResponseModification { + return tx.PatchGoogleAnalytics() + } - rsmModMap["PatchTrackerScripts"] = func(_ ...string) proxychain.ResponseModification { - return tx.PatchTrackerScripts() - } + rsmModMap["PatchTrackerScripts"] = func(_ ...string) proxychain.ResponseModification { + return tx.PatchTrackerScripts() + } - rsmModMap["RewriteHTMLResourceURLs"] = func(_ ...string) proxychain.ResponseModification { - return tx.RewriteHTMLResourceURLs() - } - -} \ No newline at end of file + rsmModMap["RewriteHTMLResourceURLs"] = func(_ ...string) proxychain.ResponseModification { + return tx.RewriteHTMLResourceURLs() + } +} diff --git a/proxychain/ruleset/rule_test.go b/proxychain/ruleset/rule_test.go index 98f7bc9..eed5959 100644 --- a/proxychain/ruleset/rule_test.go +++ b/proxychain/ruleset/rule_test.go @@ -3,8 +3,9 @@ package ruleset_v2 import ( "encoding/json" "fmt" - "gopkg.in/yaml.v3" "testing" + + "gopkg.in/yaml.v3" ) // unmarshalRule is a helper function to unmarshal a Rule from a JSON string. From 7fd2b2b3c3c0d7a798146a33a4fd030162b7e352 Mon Sep 17 00:00:00 2001 From: ladddder <151469127+ladddder@users.noreply.github.com> Date: Tue, 5 Dec 2023 16:32:42 +0100 Subject: [PATCH 2/4] move script from main to handlers --- cmd/main.go | 15 +-- handlers/script.go | 23 ++++ handlers/script.js | 296 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 320 insertions(+), 14 deletions(-) create mode 100644 handlers/script.go create mode 100644 handlers/script.js diff --git a/cmd/main.go b/cmd/main.go index cf22557..397ba9a 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -19,9 +19,6 @@ import ( //go:embed styles.css var cssData embed.FS -//go:embed script.js -var scriptData embed.FS - //go:embed VERSION var version string @@ -169,17 +166,7 @@ func main() { return c.Send(cssData) }) - // TODO: move to handlers/script.go - app.Get("/script.js", func(c *fiber.Ctx) error { - scriptData, err := scriptData.ReadFile("script.js") - if err != nil { - return c.Status(fiber.StatusInternalServerError).SendString("Internal Server Error") - } - - c.Set("Content-Type", "text/javascript") - - return c.Send(scriptData) - }) + app.Get("/script.js", handlers.Script) app.Get("ruleset", handlers.Ruleset) app.Get("raw/*", handlers.Raw) diff --git a/handlers/script.go b/handlers/script.go new file mode 100644 index 0000000..c35e6ca --- /dev/null +++ b/handlers/script.go @@ -0,0 +1,23 @@ +package handlers + +import ( + "embed" + + "github.com/gofiber/fiber/v2" +) + +//go:embed script.js +var scriptData embed.FS + +func Script(c *fiber.Ctx) error { + + scriptData, err := scriptData.ReadFile("script.js") + if err != nil { + return c.Status(fiber.StatusInternalServerError).SendString("Internal Server Error") + } + + c.Set("Content-Type", "text/javascript") + + return c.Send(scriptData) + +} diff --git a/handlers/script.js b/handlers/script.js new file mode 100644 index 0000000..c430c4e --- /dev/null +++ b/handlers/script.js @@ -0,0 +1,296 @@ +const labels = document.querySelectorAll("label"); +const inputs = document.querySelectorAll('input[type="radio"]'); +const mainElement = document.querySelector("main"); + +const handleDOMContentLoaded = () => { + handleFontChange(); + handleFontSizeChange(); + inputs.forEach((input) => { + const storedValue = localStorage.getItem(input.name); + if (storedValue === input.value) { + input.checked = true; + } + }); + window.removeEventListener("DOMContentLoaded", handleDOMContentLoaded); +}; + +function focusable_children(node) { + const nodes = Array.from( + node.querySelectorAll( + 'a[href], button, input, textarea, select, details, [tabindex]:not([tabindex="-1"])' + ) + ).filter((s) => s.offsetParent !== null); + const index = nodes.indexOf(document.activeElement); + const update = (d) => { + let i = index + d; + i += nodes.length; + i %= nodes.length; + nodes[i].focus(); + }; + return { + next: (selector) => { + const reordered = [ + ...nodes.slice(index + 1), + ...nodes.slice(0, index + 1), + ]; + for (let i = 0; i < reordered.length; i += 1) { + if (!selector || reordered[i].matches(selector)) { + reordered[i].focus(); + return; + } + } + }, + prev: (selector) => { + const reordered = [ + ...nodes.slice(index + 1), + ...nodes.slice(0, index + 1), + ]; + for (let i = reordered.length - 2; i >= 0; i -= 1) { + if (!selector || reordered[i].matches(selector)) { + reordered[i].focus(); + return; + } + } + }, + update, + }; +} + +function trap(node) { + const handle_keydown = (e) => { + if (e.key === "Tab") { + e.preventDefault(); + const group = focusable_children(node); + if (e.shiftKey) { + group.prev(); + } else { + group.next(); + } + } + }; + node.addEventListener("keydown", handle_keydown); + return { + destroy: () => { + node.removeEventListener("keydown", handle_keydown); + }, + }; +} + +const toggleDropdown = () => { + const dropdown = document.getElementById("dropdown"); + const dropdown_panel = document.getElementById("dropdown_panel"); + const focusTrap = trap(dropdown); + + const closeDropdown = () => { + dropdown_panel.classList.add("hidden"); + focusTrap.destroy(); + dropdown.removeEventListener("keydown", handleEscapeKey); + document.removeEventListener("click", handleClickOutside); + inputs.forEach((input) => { + input.removeEventListener("change", handleInputChange); + }); + labels.forEach((label) => { + label.removeEventListener("click", handleLabelSelection); + }); + }; + + const handleClickOutside = (e) => { + if (!dropdown.contains(e.target)) { + closeDropdown(); + } + }; + + const handleEscapeKey = (e) => { + if (e.key === "Escape") { + dropdown_panel.classList.add("hidden"); + closeDropdown(); + } + }; + + const handleInputChange = (e) => { + if (e.target.checked) { + localStorage.setItem(e.target.name, e.target.value); + switch (e.target.name) { + case "theme": { + handleThemeChange(); + break; + } + case "font": { + handleFontChange(); + break; + } + case "fontsize": { + handleFontSizeChange(); + break; + } + default: { + console.error("Unknown event"); + break; + } + } + } + }; + + const handleLabelSelection = (e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + const input = document.getElementById(e.target.getAttribute("for")); + input.checked = true; + input.dispatchEvent(new Event("change", { bubbles: true })); + } + }; + + if (dropdown_panel.classList.contains("hidden")) { + dropdown_panel.classList.remove("hidden"); + dropdown.addEventListener("keydown", handleEscapeKey); + inputs.forEach((input) => { + input.addEventListener("change", handleInputChange); + }); + labels.forEach((label) => { + label.addEventListener("keydown", handleLabelSelection); + }); + document.addEventListener("click", handleClickOutside); + } else { + closeDropdown(); + } +}; + +const handleFontChange = () => { + if (mainElement === null) { + return; + } + let font = localStorage.getItem("font"); + if (font === null) { + localStorage.setItem("font", "sans-serif"); + font = "sans-serif"; + } + if (font === "serif") { + mainElement.classList.add("font-serif"); + mainElement.classList.remove("font-sans"); + } else { + mainElement.classList.add("font-sans"); + mainElement.classList.remove("font-serif"); + } +}; + +const changeFontSize = (node, classes) => { + const sizes = [ + "text-xs", + "text-sm", + "text-base", + "text-lg", + "text-xl", + "text-2xl", + "text-3xl", + "text-4xl", + "text-5xl", + "lg:text-4xl", + "lg:text-5xl", + "lg:text-6xl", + ]; + const currentClasses = sizes.filter((size) => node.classList.contains(size)); + node.classList.remove(...currentClasses); + node.classList.add(...classes); +}; + +const handleFontSizeChange = () => { + if (mainElement === null) { + return; + } + let fontSize = localStorage.getItem("fontsize"); + if (fontSize === null) { + localStorage.setItem("fontsize", "text-base"); + fontSize = "text-base"; + } + if (fontSize === "text-sm") { + changeFontSize(document.querySelector("body"), ["text-sm"]); + } else if (fontSize === "text-lg") { + changeFontSize(document.querySelector("body"), ["text-lg"]); + } else { + changeFontSize(document.querySelector("body"), ["text-base"]); + } + + const nodes = document.querySelectorAll( + "h1, h2, h3, h4, h5, h6, code, pre, kbd, table" + ); + if (fontSize === "text-sm") { + changeFontSize(mainElement, ["text-sm"]); + } else if (fontSize === "text-lg") { + changeFontSize(mainElement, ["text-lg"]); + } else { + changeFontSize(mainElement, ["text-base"]); + } + nodes.forEach((node) => { + let classes = ""; + switch (node.tagName) { + case "H1": { + if (fontSize === "text-sm") { + classes = ["text-3xl", "lg:text-4xl"]; + } else if (fontSize === "text-lg") { + classes = ["text-5xl", "lg:text-6xl"]; + } else { + classes = ["text-4xl", "lg:text-5xl"]; + } + break; + } + case "H2": { + if (fontSize === "text-sm") { + classes = ["text-2xl"]; + } else if (fontSize === "text-lg") { + classes = ["text-4xl"]; + } else { + classes = ["text-3xl"]; + } + break; + } + case "H3": { + if (fontSize === "text-sm") { + classes = ["text-xl"]; + } else if (fontSize === "text-lg") { + classes = ["text-3xl"]; + } else { + classes = ["text-2xl"]; + } + break; + } + case "H4": + case "H5": + case "H6": { + if (fontSize === "text-sm") { + classes = ["text-lg"]; + } else if (fontSize === "text-lg") { + classes = ["text-2xl"]; + } else { + classes = ["text-xl"]; + } + break; + } + case "CODE": + case "PRE": + case "KBD": + case "TABLE": { + if (fontSize === "text-sm") { + classes = ["text-xs"]; + } else if (fontSize === "text-lg") { + classes = ["text-base"]; + } else { + classes = ["text-sm"]; + } + break; + } + default: { + if (fontSize === "text-sm") { + classes = ["text-sm"]; + } else if (fontSize === "text-lg") { + classes = ["text-lg"]; + } else { + classes = ["text-base"]; + } + break; + } + } + changeFontSize(node, classes); + }); +}; + +window.addEventListener("DOMContentLoaded", handleDOMContentLoaded); From eef6061d93035162c5a9fa467c5dde9c7608457e Mon Sep 17 00:00:00 2001 From: ladddder <151469127+ladddder@users.noreply.github.com> Date: Tue, 5 Dec 2023 16:39:30 +0100 Subject: [PATCH 3/4] moved styles css from main to handlers --- cmd/main.go | 20 +-- cmd/script.js | 296 ----------------------------------- {cmd => handlers}/styles.css | 0 handlers/styles.go | 23 +++ 4 files changed, 26 insertions(+), 313 deletions(-) delete mode 100644 cmd/script.js rename {cmd => handlers}/styles.css (100%) create mode 100644 handlers/styles.go diff --git a/cmd/main.go b/cmd/main.go index 397ba9a..4af5534 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,7 +1,7 @@ package main import ( - "embed" + _ "embed" "fmt" "html/template" "log" @@ -16,9 +16,6 @@ import ( "github.com/gofiber/template/html/v2" ) -//go:embed styles.css -var cssData embed.FS - //go:embed VERSION var version string @@ -155,19 +152,8 @@ func main() { app.Get("/", handlers.Form) - app.Get("/styles.css", func(c *fiber.Ctx) error { - cssData, err := cssData.ReadFile("styles.css") - if err != nil { - return c.Status(fiber.StatusInternalServerError).SendString("Internal Server Error") - } - - c.Set("Content-Type", "text/css") - - return c.Send(cssData) - }) - - app.Get("/script.js", handlers.Script) - + app.Get("styles.css", handlers.Styles) + app.Get("script.js", handlers.Script) app.Get("ruleset", handlers.Ruleset) app.Get("raw/*", handlers.Raw) diff --git a/cmd/script.js b/cmd/script.js deleted file mode 100644 index c430c4e..0000000 --- a/cmd/script.js +++ /dev/null @@ -1,296 +0,0 @@ -const labels = document.querySelectorAll("label"); -const inputs = document.querySelectorAll('input[type="radio"]'); -const mainElement = document.querySelector("main"); - -const handleDOMContentLoaded = () => { - handleFontChange(); - handleFontSizeChange(); - inputs.forEach((input) => { - const storedValue = localStorage.getItem(input.name); - if (storedValue === input.value) { - input.checked = true; - } - }); - window.removeEventListener("DOMContentLoaded", handleDOMContentLoaded); -}; - -function focusable_children(node) { - const nodes = Array.from( - node.querySelectorAll( - 'a[href], button, input, textarea, select, details, [tabindex]:not([tabindex="-1"])' - ) - ).filter((s) => s.offsetParent !== null); - const index = nodes.indexOf(document.activeElement); - const update = (d) => { - let i = index + d; - i += nodes.length; - i %= nodes.length; - nodes[i].focus(); - }; - return { - next: (selector) => { - const reordered = [ - ...nodes.slice(index + 1), - ...nodes.slice(0, index + 1), - ]; - for (let i = 0; i < reordered.length; i += 1) { - if (!selector || reordered[i].matches(selector)) { - reordered[i].focus(); - return; - } - } - }, - prev: (selector) => { - const reordered = [ - ...nodes.slice(index + 1), - ...nodes.slice(0, index + 1), - ]; - for (let i = reordered.length - 2; i >= 0; i -= 1) { - if (!selector || reordered[i].matches(selector)) { - reordered[i].focus(); - return; - } - } - }, - update, - }; -} - -function trap(node) { - const handle_keydown = (e) => { - if (e.key === "Tab") { - e.preventDefault(); - const group = focusable_children(node); - if (e.shiftKey) { - group.prev(); - } else { - group.next(); - } - } - }; - node.addEventListener("keydown", handle_keydown); - return { - destroy: () => { - node.removeEventListener("keydown", handle_keydown); - }, - }; -} - -const toggleDropdown = () => { - const dropdown = document.getElementById("dropdown"); - const dropdown_panel = document.getElementById("dropdown_panel"); - const focusTrap = trap(dropdown); - - const closeDropdown = () => { - dropdown_panel.classList.add("hidden"); - focusTrap.destroy(); - dropdown.removeEventListener("keydown", handleEscapeKey); - document.removeEventListener("click", handleClickOutside); - inputs.forEach((input) => { - input.removeEventListener("change", handleInputChange); - }); - labels.forEach((label) => { - label.removeEventListener("click", handleLabelSelection); - }); - }; - - const handleClickOutside = (e) => { - if (!dropdown.contains(e.target)) { - closeDropdown(); - } - }; - - const handleEscapeKey = (e) => { - if (e.key === "Escape") { - dropdown_panel.classList.add("hidden"); - closeDropdown(); - } - }; - - const handleInputChange = (e) => { - if (e.target.checked) { - localStorage.setItem(e.target.name, e.target.value); - switch (e.target.name) { - case "theme": { - handleThemeChange(); - break; - } - case "font": { - handleFontChange(); - break; - } - case "fontsize": { - handleFontSizeChange(); - break; - } - default: { - console.error("Unknown event"); - break; - } - } - } - }; - - const handleLabelSelection = (e) => { - if (e.key === "Enter" || e.key === " ") { - e.preventDefault(); - const input = document.getElementById(e.target.getAttribute("for")); - input.checked = true; - input.dispatchEvent(new Event("change", { bubbles: true })); - } - }; - - if (dropdown_panel.classList.contains("hidden")) { - dropdown_panel.classList.remove("hidden"); - dropdown.addEventListener("keydown", handleEscapeKey); - inputs.forEach((input) => { - input.addEventListener("change", handleInputChange); - }); - labels.forEach((label) => { - label.addEventListener("keydown", handleLabelSelection); - }); - document.addEventListener("click", handleClickOutside); - } else { - closeDropdown(); - } -}; - -const handleFontChange = () => { - if (mainElement === null) { - return; - } - let font = localStorage.getItem("font"); - if (font === null) { - localStorage.setItem("font", "sans-serif"); - font = "sans-serif"; - } - if (font === "serif") { - mainElement.classList.add("font-serif"); - mainElement.classList.remove("font-sans"); - } else { - mainElement.classList.add("font-sans"); - mainElement.classList.remove("font-serif"); - } -}; - -const changeFontSize = (node, classes) => { - const sizes = [ - "text-xs", - "text-sm", - "text-base", - "text-lg", - "text-xl", - "text-2xl", - "text-3xl", - "text-4xl", - "text-5xl", - "lg:text-4xl", - "lg:text-5xl", - "lg:text-6xl", - ]; - const currentClasses = sizes.filter((size) => node.classList.contains(size)); - node.classList.remove(...currentClasses); - node.classList.add(...classes); -}; - -const handleFontSizeChange = () => { - if (mainElement === null) { - return; - } - let fontSize = localStorage.getItem("fontsize"); - if (fontSize === null) { - localStorage.setItem("fontsize", "text-base"); - fontSize = "text-base"; - } - if (fontSize === "text-sm") { - changeFontSize(document.querySelector("body"), ["text-sm"]); - } else if (fontSize === "text-lg") { - changeFontSize(document.querySelector("body"), ["text-lg"]); - } else { - changeFontSize(document.querySelector("body"), ["text-base"]); - } - - const nodes = document.querySelectorAll( - "h1, h2, h3, h4, h5, h6, code, pre, kbd, table" - ); - if (fontSize === "text-sm") { - changeFontSize(mainElement, ["text-sm"]); - } else if (fontSize === "text-lg") { - changeFontSize(mainElement, ["text-lg"]); - } else { - changeFontSize(mainElement, ["text-base"]); - } - nodes.forEach((node) => { - let classes = ""; - switch (node.tagName) { - case "H1": { - if (fontSize === "text-sm") { - classes = ["text-3xl", "lg:text-4xl"]; - } else if (fontSize === "text-lg") { - classes = ["text-5xl", "lg:text-6xl"]; - } else { - classes = ["text-4xl", "lg:text-5xl"]; - } - break; - } - case "H2": { - if (fontSize === "text-sm") { - classes = ["text-2xl"]; - } else if (fontSize === "text-lg") { - classes = ["text-4xl"]; - } else { - classes = ["text-3xl"]; - } - break; - } - case "H3": { - if (fontSize === "text-sm") { - classes = ["text-xl"]; - } else if (fontSize === "text-lg") { - classes = ["text-3xl"]; - } else { - classes = ["text-2xl"]; - } - break; - } - case "H4": - case "H5": - case "H6": { - if (fontSize === "text-sm") { - classes = ["text-lg"]; - } else if (fontSize === "text-lg") { - classes = ["text-2xl"]; - } else { - classes = ["text-xl"]; - } - break; - } - case "CODE": - case "PRE": - case "KBD": - case "TABLE": { - if (fontSize === "text-sm") { - classes = ["text-xs"]; - } else if (fontSize === "text-lg") { - classes = ["text-base"]; - } else { - classes = ["text-sm"]; - } - break; - } - default: { - if (fontSize === "text-sm") { - classes = ["text-sm"]; - } else if (fontSize === "text-lg") { - classes = ["text-lg"]; - } else { - classes = ["text-base"]; - } - break; - } - } - changeFontSize(node, classes); - }); -}; - -window.addEventListener("DOMContentLoaded", handleDOMContentLoaded); diff --git a/cmd/styles.css b/handlers/styles.css similarity index 100% rename from cmd/styles.css rename to handlers/styles.css diff --git a/handlers/styles.go b/handlers/styles.go new file mode 100644 index 0000000..cd326dd --- /dev/null +++ b/handlers/styles.go @@ -0,0 +1,23 @@ +package handlers + +import ( + "embed" + + "github.com/gofiber/fiber/v2" +) + +//go:embed styles.css +var cssData embed.FS + +func Styles(c *fiber.Ctx) error { + + cssData, err := cssData.ReadFile("styles.css") + if err != nil { + return c.Status(fiber.StatusInternalServerError).SendString("Internal Server Error") + } + + c.Set("Content-Type", "text/css") + + return c.Send(cssData) + +} From f2543d261ebbfee32822d441a4cec23e27088c24 Mon Sep 17 00:00:00 2001 From: ladddder <151469127+ladddder@users.noreply.github.com> Date: Tue, 5 Dec 2023 16:54:41 +0100 Subject: [PATCH 4/4] move minified tailwind css build to handler folder --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ebe7d42..3f49903 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "scripts": { - "build": "pnpx tailwindcss -i ./styles/input.css -o ./styles/output.css --build && pnpx minify ./styles/output.css > ./cmd/styles.css" + "build": "pnpx tailwindcss -i ./styles/input.css -o ./styles/output.css --build && pnpx minify ./styles/output.css > ./handlers/styles.css" }, "devDependencies": { "minify": "^10.5.2",