// codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/interface/http/middleware/utils.go package middleware import ( "regexp" "go.uber.org/zap" ) type protectedRoute struct { pattern string regex *regexp.Regexp } var ( exactPaths = make(map[string]bool) patternRoutes []protectedRoute ) func init() { // Exact matches exactPaths = map[string]bool{ "/api/v1/me": true, "/api/v1/me/delete": true, "/api/v1/me/blocked-emails": true, "/api/v1/me/email/change-request": true, // Email change step 1: request "/api/v1/me/email/change-verify": true, // Email change step 2: verify "/api/v1/dashboard": true, "/api/v1/collections": true, "/api/v1/collections/filtered": true, "/api/v1/collections/root": true, "/api/v1/collections/shared": true, "/api/v1/collections/sync": true, // Sync collections endpoint "/api/v1/files": true, "/api/v1/files/pending": true, // Three-step workflow file-create endpoint: Start "/api/v1/files/recent": true, "/api/v1/files/sync": true, // Sync files endpoint "/api/v1/files/delete-multiple": true, // Delete multiple files endpoint "/api/v1/invites/send-email": true, // Send invitation email to non-registered user "/api/v1/tags": true, // List and create tags "/api/v1/tags/search": true, // Search by tags "/iam/api/v1/users/lookup": true, // User public key lookup (requires auth) } // Pattern matches patterns := []string{ // Blocked Email patterns "^/api/v1/me/blocked-emails/[^/]+$", // Delete specific blocked email // Collection patterns (plural routes) "^/api/v1/collections/[a-zA-Z0-9-]+$", // Individual collection operations "^/api/v1/collections/[a-zA-Z0-9-]+/move$", // Move collection "^/api/v1/collections/[a-zA-Z0-9-]+/share$", // Share collection "^/api/v1/collections/[a-zA-Z0-9-]+/members$", // Collection members "^/api/v1/collections/[a-zA-Z0-9-]+/members/[a-zA-Z0-9-]+$", // Remove specific member "^/api/v1/collections/[a-zA-Z0-9-]+/archive$", // Archive collection "^/api/v1/collections/[a-zA-Z0-9-]+/restore$", // Restore collection "^/api/v1/collections-by-parent/[a-zA-Z0-9-]+$", // Collections by parent // Collection patterns (singular routes for files) "^/api/v1/collection/[a-zA-Z0-9-]+/files$", // Collection files (singular) // File patterns (singular routes) "^/api/v1/file/[a-zA-Z0-9-]+$", // Individual file operations "^/api/v1/file/[a-zA-Z0-9-]+/data$", // File data "^/api/v1/file/[a-zA-Z0-9-]+/upload-url$", // File upload URL "^/api/v1/file/[a-zA-Z0-9-]+/download-url$", // File download URL "^/api/v1/file/[a-zA-Z0-9-]+/complete$", // Complete file upload "^/api/v1/file/[a-zA-Z0-9-]+/archive$", // Archive file "^/api/v1/file/[a-zA-Z0-9-]+/restore$", // Restore file // Tag patterns "^/api/v1/tags/[a-zA-Z0-9-]+$", // Individual tag operations (GET, PUT, DELETE) "^/api/v1/tags/[a-zA-Z0-9-]+/assign$", // Assign tag to entity "^/api/v1/tags/[a-zA-Z0-9-]+/entities/[a-zA-Z0-9-]+$", // Unassign tag from entity "^/api/v1/tags/for/collection/[a-zA-Z0-9-]+$", // Get tags for collection "^/api/v1/tags/for/file/[a-zA-Z0-9-]+$", // Get tags for file "^/api/v1/tags/collections$", // List collections by tag "^/api/v1/tags/files$", // List files by tag } // Precompile patterns patternRoutes = make([]protectedRoute, len(patterns)) for i, pattern := range patterns { patternRoutes[i] = protectedRoute{ pattern: pattern, regex: regexp.MustCompile(pattern), } } } func isProtectedPath(logger *zap.Logger, path string) bool { // Check exact matches first (O(1) lookup) if exactPaths[path] { logger.Debug("✅ found via map - url is protected", zap.String("path", path)) return true } // Check patterns for _, route := range patternRoutes { if route.regex.MatchString(path) { logger.Debug("✅ found via regex - url is protected", zap.String("path", path)) return true } } logger.Debug("❌ not found", zap.String("path", path)) return false }