package security import ( "net/http" "github.com/missionworkforce/missionmatch/internal/platform/tenant" ) // RequireCapability gates a route on a capability. The role is read from the validated session in // context (set by the auth middleware), never from the request body or a header, so authorization // cannot be spoofed and is enforced at the API rather than by hiding a control in the UI. A caller // without the capability gets 403 before the handler runs. func RequireCapability(cap Capability) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { p, ok := tenant.UserFromContext(r.Context()) if !ok || !Has(Role(p.Role), cap) { http.Error(w, "forbidden", http.StatusForbidden) return } next.ServeHTTP(w, r) }) } } // RequireRole gates a route on a minimum role in the hierarchy. func RequireRole(min Role) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { p, ok := tenant.UserFromContext(r.Context()) if !ok || !AtLeast(Role(p.Role), min) { http.Error(w, "forbidden", http.StatusForbidden) return } next.ServeHTTP(w, r) }) } }