diff --git a/cmd/main.go b/cmd/main.go index c1d9c5a..7ef2af2 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -167,7 +167,7 @@ func main() { app.Get("styles.css", handlers.Styles) app.Get("script.js", handlers.Script) - app.Get("ruleset", handlers.Ruleset) + app.Get("ruleset/*", handlers.NewRulesetSiteHandler(proxyOpts)) app.All("raw/*", handlers.NewRawProxySiteHandler(proxyOpts)) diff --git a/handlers/raw.go b/handlers/raw.go index 6ccfdd0..3895a1e 100644 --- a/handlers/raw.go +++ b/handlers/raw.go @@ -1,7 +1,6 @@ package handlers import ( - "fmt" "ladder/proxychain" rx "ladder/proxychain/requestmodifiers" tx "ladder/proxychain/responsemodifiers" diff --git a/handlers/ruleset.go b/handlers/ruleset.go index 0239fff..daa2e0d 100644 --- a/handlers/ruleset.go +++ b/handlers/ruleset.go @@ -1,9 +1,93 @@ package handlers import ( + "encoding/json" + "fmt" "github.com/gofiber/fiber/v2" + "gopkg.in/yaml.v3" + "net/url" + "strings" ) -func Ruleset(c *fiber.Ctx) error { - return nil +func NewRulesetSiteHandler(opts *ProxyOptions) fiber.Handler { + + return func(c *fiber.Ctx) error { + if opts == nil { + c.SendStatus(404) + c.SendString("No ruleset specified. Set the RULESET environment variable or use the --ruleset flag.") + } + + // no specific rule requested, return the entire ruleset + if c.Params("*") == "" { + switch c.Get("accept") { + case "application/json": + jsn, err := opts.Ruleset.JSON() + if err != nil { + return err + } + c.Set("content-type", "application/json") + return c.Send([]byte(jsn)) + + default: + // TODO: the ruleset.MarshalYAML() method is currently broken and panics + yml, err := opts.Ruleset.YAML() + if err != nil { + return err + } + c.Set("content-type", "application/yaml") + return c.Send([]byte(yml)) + } + } + + // a specific rule was requested by path /ruleset/https://example.com + // return only that particular rule + reqURL, err := extractURLFromContext(c, "ruleset/") + if err != nil { + return err + } + rule, exists := opts.Ruleset.GetRule(reqURL) + if !exists { + c.SendStatus(404) + c.SendString(fmt.Sprintf("A rule that matches '%s' was not found in the ruleset.", reqURL)) + } + + switch c.Get("accept") { + case "application/json": + jsn, err := json.MarshalIndent(rule, "", " ") + if err != nil { + return err + } + c.Set("content-type", "application/json") + return c.Send(jsn) + default: + yml, err := yaml.Marshal(rule) + if err != nil { + return err + } + c.Set("content-type", "application/yaml") + return c.Send(yml) + } + } +} + +// extractURLFromContext extracts a URL from the request ctx. +func extractURLFromContext(ctx *fiber.Ctx, apiPrefix string) (*url.URL, error) { + reqURL := ctx.Params("*") + + reqURL = strings.TrimPrefix(reqURL, apiPrefix) + + // sometimes client requests doubleroot '//' + // there is a bug somewhere else, but this is a workaround until we find it + if strings.HasPrefix(reqURL, "/") || strings.HasPrefix(reqURL, `%2F`) { + reqURL = strings.TrimPrefix(reqURL, "/") + reqURL = strings.TrimPrefix(reqURL, `%2F`) + } + + // unescape url query + uReqURL, err := url.QueryUnescape(reqURL) + if err == nil { + reqURL = uReqURL + } + + return url.Parse(reqURL) } diff --git a/proxychain/proxychain.go b/proxychain/proxychain.go index ac33475..8d8a51d 100644 --- a/proxychain/proxychain.go +++ b/proxychain/proxychain.go @@ -283,10 +283,6 @@ func (chain *ProxyChain) extractURLFromSubdomain() (*url.URL, error) { func (chain *ProxyChain) extractURLFromPath() (*url.URL, error) { reqURL := chain.Context.Params("*") - fmt.Println("XXXXXXXXXXXXXXXX") - fmt.Println(reqURL) - fmt.Println(chain.APIPrefix) - reqURL = strings.TrimPrefix(reqURL, chain.APIPrefix) // sometimes client requests doubleroot '//' @@ -530,7 +526,6 @@ func (chain *ProxyChain) Execute() error { } // in case api user did not set or forward content-type, we do it for them - // warning: the fiber method chain.Context.Get() doesn't seem to work as described ct := chain.Context.Response().Header.Peek("content-type") CT := chain.Context.Response().Header.Peek("Content-Type") if ct == nil && CT == nil { diff --git a/tmp/main b/tmp/main new file mode 100755 index 0000000..9f91f2c Binary files /dev/null and b/tmp/main differ