package middleware import ( "net/http" "strings" "github.com/ultisuite/ulti-backend/internal/api/apiresponse" "github.com/ultisuite/ulti-backend/internal/apitokens" ) func EnforceApiTokenPolicy() func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { auth := ApiTokenFromContext(r.Context()) if auth == nil { next.ServeHTTP(w, r) return } if strings.HasPrefix(r.URL.Path, "/api/v1/search") { reqs := apitokens.SearchRequirements(r.URL.Query().Get("types")) for _, req := range reqs { if !apitokens.AllowsRequirement(auth, req) { apiresponse.WriteError(w, r, http.StatusForbidden, apiresponse.CodeAuthForbidden, "insufficient api token permission", nil) return } } accountID := apitokens.ExtractMailAccountID(r.URL.Path, r.URL.Query().Get("account_id")) if accountID != "" && !apitokens.AllowsMailAccount(auth, accountID) { apiresponse.WriteError(w, r, http.StatusForbidden, apiresponse.CodeAuthForbidden, "mail account out of token scope", nil) return } next.ServeHTTP(w, r) return } req, ok := apitokens.RequirementForRequest(r.Method, r.URL.Path, r.URL.Query().Get("types")) if !ok { apiresponse.WriteError(w, r, http.StatusForbidden, apiresponse.CodeAuthForbidden, "route not allowed for api token", nil) return } if !apitokens.AllowsRequirement(auth, req) { apiresponse.WriteError(w, r, http.StatusForbidden, apiresponse.CodeAuthForbidden, "insufficient api token permission", nil) return } switch req.ScopeHint { case apitokens.ScopeMailAccountQuery, apitokens.ScopeMailAccountPath: accountID := apitokens.ExtractMailAccountID(r.URL.Path, r.URL.Query().Get("account_id")) if accountID != "" && !apitokens.AllowsMailAccount(auth, accountID) { apiresponse.WriteError(w, r, http.StatusForbidden, apiresponse.CodeAuthForbidden, "mail account out of token scope", nil) return } case apitokens.ScopeDrivePathFromURL: drivePath := apitokens.ExtractDrivePathFromURL(r.URL.Path) if drivePath != "" && !apitokens.AllowsDrivePath(auth, drivePath) { apiresponse.WriteError(w, r, http.StatusForbidden, apiresponse.CodeAuthForbidden, "drive path out of token scope", nil) return } } next.ServeHTTP(w, r) }) } }