package middleware import ( "RenewCMS/api/pkg/access" "RenewCMS/internal/domain/builtintype" "RenewCMS/internal/domain/role" "RenewCMS/internal/domain/user" "RenewCMS/internal/infrastructure/useCases" "github.com/go-chi/chi/v5" "net/http" ) type grantCheck func(account user.User, r *http.Request) (role.GrantSet, error) func ArticleTypeKey(*http.Request) string { return builtintype.KeyArticle } func PathTypeKey(r *http.Request) string { return chi.URLParam(r, "key") } func RequirePermission(getUser *useCases.GetUserUseCase, check *useCases.CheckPermissionUseCase, key string) func(http.Handler) http.Handler { return enforce(getUser, func(account user.User, _ *http.Request) (role.GrantSet, error) { return check.Require(account, key) }) } func RequireFullScope(getUser *useCases.GetUserUseCase, check *useCases.CheckPermissionUseCase, key string) func(http.Handler) http.Handler { return enforce(getUser, func(account user.User, _ *http.Request) (role.GrantSet, error) { return check.RequireAll(account, key) }) } func RequireTypedPermission(getUser *useCases.GetUserUseCase, check *useCases.CheckPermissionUseCase, key string, typeKey func(r *http.Request) string) func(http.Handler) http.Handler { return enforce(getUser, func(account user.User, r *http.Request) (role.GrantSet, error) { return check.RequireFor(account, key, typeKey(r)) }) } func enforce(getUser *useCases.GetUserUseCase, verify grantCheck) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { r = access.WithCurrentUser(r) currentUser, ok := resolveCurrentUser(getUser, w, r) if !ok { return } grants, err := verify(currentUser, r) if err != nil { if !access.WriteIfMissingPermission(w, err) { http.Error(w, "Internal server error", http.StatusInternalServerError) } return } caller := access.Caller{UserID: currentUser.ID, Grants: grants} next.ServeHTTP(w, r.WithContext(access.WithCaller(r.Context(), caller))) }) } }