turash/bugulma/backend/internal/middleware/maintenance.go
2025-12-15 10:06:41 +01:00

63 lines
1.6 KiB
Go

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