package middleware import ( "net/http" "code.nochebuena.dev/go/rbac" ) // Require guards a handler: it reads the rbac.Identity from context (set by Auth), // resolves the permission mask from the provider, and rejects the request with 403 // if any of the required permission bits are not set. // // Must be chained after Auth so that an identity is guaranteed in context. func Require(provider rbac.PermissionProvider, resource string, perms ...rbac.Permission) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { identity, ok := rbac.FromContext(r.Context()) if !ok { http.Error(w, `{"code":"PERMISSION_DENIED","message":"no identity in context"}`, http.StatusForbidden) return } mask, err := provider.ResolveMask(r.Context(), identity.UID, resource) if err != nil { http.Error(w, `{"code":"INTERNAL","message":"could not resolve permissions"}`, http.StatusInternalServerError) return } for _, p := range perms { if !mask.Has(p) { http.Error(w, `{"code":"PERMISSION_DENIED","message":"insufficient permissions"}`, http.StatusForbidden) return } } next.ServeHTTP(w, r) }) } }