package middleware import ( "net/http" "strings" "bugulma/backend/internal/service" "github.com/gin-gonic/gin" ) // MaintenanceMiddleware blocks requests when maintenance mode is enabled. // Whitelisted path prefixes are allowed through (e.g., /api/v1/admin, /health). func MaintenanceMiddleware(settingsSvc *service.SettingsService, whitelistPrefixes []string) gin.HandlerFunc { return func(c *gin.Context) { // Get current maintenance setting m, err := settingsSvc.GetMaintenanceCached(c.Request.Context()) if err != nil { // On error, be conservative and allow request (avoid taking down the site due to a read error) c.Next() return } // Always set headers so clients can show a banner if desired if m.Enabled { c.Header("X-Maintenance", "true") c.Header("X-Maintenance-Message", m.Message) } else { c.Header("X-Maintenance", "false") c.Header("X-Maintenance-Message", "") } // If not enabled, nothing to do if !m.Enabled { c.Next() return } // If path is whitelisted, allow through path := c.Request.URL.Path for _, p := range whitelistPrefixes { if strings.HasPrefix(path, p) { c.Next() return } } // Allow if client's IP is in allowed list clientIP := c.ClientIP() xReal := c.GetHeader("X-Real-IP") xForwarded := c.GetHeader("X-Forwarded-For") for _, a := range m.AllowedIPs { if a == clientIP || a == xReal || (xForwarded != "" && strings.HasPrefix(xForwarded, a)) { c.Next() return } } // Block the request with 503 c.AbortWithStatusJSON(http.StatusServiceUnavailable, gin.H{"message": m.Message, "maintenance": true}) } }