ultisuite-backend/internal/api/middleware/apitoken_policy.go
R3D347HR4Y bd7534658a Refactor and enhance unified frontend and API features
- Updated environment configuration to unify frontend for mail and drive under a single service.
- Revised README to reflect changes in frontend setup and routing for the unified application.
- Introduced new API documentation endpoints for better accessibility of API specifications.
- Enhanced drive and mail services with improved handling of file uploads and metadata enrichment.
- Implemented new API token management features, including creation, listing, and revocation of tokens.
- Added tests for new functionalities in drive and mail services to ensure reliability and correctness.
2026-06-07 15:44:30 +02:00

66 lines
2.3 KiB
Go

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)
})
}
}