diff --git a/go.mod b/go.mod index 8ba878b..03acc8d 100644 --- a/go.mod +++ b/go.mod @@ -97,6 +97,7 @@ require ( github.com/goreleaser/chglog v0.7.0 // indirect github.com/goreleaser/fileglob v1.3.0 // indirect github.com/goreleaser/nfpm/v2 v2.42.1 // indirect + github.com/gorilla/mux v1.8.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/huandu/xstrings v1.5.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect diff --git a/go.sum b/go.sum index 61be2e6..fa1f835 100644 --- a/go.sum +++ b/go.sum @@ -212,6 +212,8 @@ github.com/goreleaser/fileglob v1.3.0 h1:/X6J7U8lbDpQtBvGcwwPS6OpzkNVlVEsFUVRx9+ github.com/goreleaser/fileglob v1.3.0/go.mod h1:Jx6BoXv3mbYkEzwm9THo7xbr5egkAraxkGorbJb4RxU= github.com/goreleaser/nfpm/v2 v2.42.1 h1:xu2pLRgQuz2ab+YZFoeIzwU/M5jjjCKDGwv1lRbVGvk= github.com/goreleaser/nfpm/v2 v2.42.1/go.mod h1:dY53KWYKebkOocxgkmpM7SRX0Nv5hU+jEu2kIaM4/LI= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 h1:sGm2vDRFUrQJO/Veii4h4zG2vvqG6uWNkBHSTqXOZk0= diff --git a/lib/anubis.go b/lib/anubis.go index a3b9338..947abae 100644 --- a/lib/anubis.go +++ b/lib/anubis.go @@ -18,6 +18,7 @@ import ( "github.com/golang-jwt/jwt/v5" "github.com/google/cel-go/common/types" "github.com/google/uuid" + "github.com/gorilla/mux" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -68,7 +69,7 @@ var ( type Server struct { next http.Handler - mux *http.ServeMux + mux *mux.Router policy *policy.ParsedConfig OGTags *ogtags.OGTagCache ed25519Priv ed25519.PrivateKey diff --git a/lib/challenge/interface.go b/lib/challenge/interface.go index 963d6ca..296600a 100644 --- a/lib/challenge/interface.go +++ b/lib/challenge/interface.go @@ -10,6 +10,7 @@ import ( "github.com/TecharoHQ/anubis/lib/policy/config" "github.com/TecharoHQ/anubis/lib/store" "github.com/a-h/templ" + "github.com/gorilla/mux" ) var ( @@ -58,7 +59,7 @@ type ValidateInput struct { type Impl interface { // Setup registers any additional routes with the Impl for assets or API routes. - Setup(mux *http.ServeMux) + Setup(r *mux.Router) // Issue a new challenge to the user, called by the Anubis. Issue(r *http.Request, lg *slog.Logger, in *IssueInput) (templ.Component, error) diff --git a/lib/challenge/metarefresh/metarefresh.go b/lib/challenge/metarefresh/metarefresh.go index db6fcc6..a66f1e8 100644 --- a/lib/challenge/metarefresh/metarefresh.go +++ b/lib/challenge/metarefresh/metarefresh.go @@ -11,6 +11,7 @@ import ( "github.com/TecharoHQ/anubis/lib/localization" "github.com/TecharoHQ/anubis/web" "github.com/a-h/templ" + "github.com/gorilla/mux" ) //go:generate go tool github.com/a-h/templ/cmd/templ generate @@ -21,7 +22,7 @@ func init() { type Impl struct{} -func (i *Impl) Setup(mux *http.ServeMux) {} +func (i *Impl) Setup(r *mux.Router) {} func (i *Impl) Issue(r *http.Request, lg *slog.Logger, in *challenge.IssueInput) (templ.Component, error) { u, err := r.URL.Parse(anubis.BasePrefix + "/.within.website/x/cmd/anubis/api/pass-challenge") diff --git a/lib/challenge/proofofwork/proofofwork.go b/lib/challenge/proofofwork/proofofwork.go index a24a4f5..a74999d 100644 --- a/lib/challenge/proofofwork/proofofwork.go +++ b/lib/challenge/proofofwork/proofofwork.go @@ -13,6 +13,7 @@ import ( "github.com/TecharoHQ/anubis/lib/localization" "github.com/TecharoHQ/anubis/web" "github.com/a-h/templ" + "github.com/gorilla/mux" ) func init() { @@ -24,7 +25,7 @@ type Impl struct { Algorithm string } -func (i *Impl) Setup(mux *http.ServeMux) { +func (i *Impl) Setup(r *mux.Router) { /* no implementation required */ } diff --git a/lib/challenge/proofofwork/proofofwork_test.go b/lib/challenge/proofofwork/proofofwork_test.go index 4e71bcf..020749c 100644 --- a/lib/challenge/proofofwork/proofofwork_test.go +++ b/lib/challenge/proofofwork/proofofwork_test.go @@ -9,6 +9,7 @@ import ( "github.com/TecharoHQ/anubis/lib/challenge" "github.com/TecharoHQ/anubis/lib/policy" "github.com/TecharoHQ/anubis/lib/policy/config" + "github.com/gorilla/mux" ) func mkRequest(t *testing.T, values map[string]string) *http.Request { @@ -124,7 +125,7 @@ func TestBasic(t *testing.T) { t.Run(cs.name, func(t *testing.T) { lg := slog.With() - i.Setup(http.NewServeMux()) + i.Setup(mux.NewRouter()) inp := &challenge.IssueInput{ Rule: bot, diff --git a/lib/config.go b/lib/config.go index 9c6708f..a34149f 100644 --- a/lib/config.go +++ b/lib/config.go @@ -24,6 +24,7 @@ import ( "github.com/TecharoHQ/anubis/web" "github.com/TecharoHQ/anubis/xess" "github.com/a-h/templ" + "github.com/gorilla/mux" ) type Options struct { @@ -110,25 +111,33 @@ func New(opts Options) (*Server, error) { store: opts.Policy.Store, } - mux := http.NewServeMux() - xess.Mount(mux) + r := mux.NewRouter() + xess.Mount(r) // Helper to add global prefix registerWithPrefix := func(pattern string, handler http.Handler, method string) { - if method != "" { - method = method + " " // methods must end with a space to register with them - } - // Ensure there's no double slash when concatenating BasePrefix and pattern basePrefix := strings.TrimSuffix(anubis.BasePrefix, "/") - prefix := method + basePrefix // If pattern doesn't start with a slash, add one if !strings.HasPrefix(pattern, "/") { pattern = "/" + pattern } - mux.Handle(prefix+pattern, handler) + var route *mux.Route + + switch strings.HasSuffix(pattern, "/") { + case true: + route = r.PathPrefix(basePrefix + pattern) + case false: + route = r.Path(basePrefix + pattern) + } + + if method != "" { + route = route.Methods(method) + } + + route.Handler(handler) } // Ensure there's no double slash when concatenating BasePrefix and StaticPath @@ -164,10 +173,10 @@ func New(opts Options) (*Server, error) { for _, implKind := range challenge.Methods() { impl, _ := challenge.Get(implKind) - impl.Setup(mux) + impl.Setup(r) } - result.mux = mux + result.mux = r return result, nil } diff --git a/xess/xess.go b/xess/xess.go index efdd5bc..fe803e6 100644 --- a/xess/xess.go +++ b/xess/xess.go @@ -10,6 +10,7 @@ import ( "github.com/TecharoHQ/anubis" "github.com/TecharoHQ/anubis/internal" + "github.com/gorilla/mux" ) var ( @@ -20,8 +21,6 @@ var ( ) func init() { - Mount(http.DefaultServeMux) - //goland:noinspection GoBoolExpressions if anubis.Version != "devel" { URL = filepath.Join(filepath.Dir(URL), "xess.min.css") @@ -31,8 +30,10 @@ func init() { } // Mount registers the xess static file handlers on the given mux -func Mount(mux *http.ServeMux) { +func Mount(r *mux.Router) { prefix := anubis.BasePrefix + "/.within.website/x/xess/" - mux.Handle(prefix, internal.UnchangingCache(http.StripPrefix(prefix, http.FileServerFS(Static)))) + r.PathPrefix(prefix). + Handler(internal.UnchangingCache(http.StripPrefix(prefix, http.FileServerFS(Static)))). + Name("xess") }