69 lines
2.1 KiB
Go
69 lines
2.1 KiB
Go
package middleware
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"goaresv3/app/settings/models"
|
|
"goaresv3/config"
|
|
)
|
|
|
|
// DynamicCORS applies CORS policy from DB-backed whitelist/blacklist tables.
|
|
func DynamicCORS() gin.HandlerFunc {
|
|
debug := envBool("CORS_DEBUG", false)
|
|
|
|
return func(c *gin.Context) {
|
|
// Defaults for downstream middlewares (e.g. rate limit)
|
|
c.Set("origin_whitelisted", false)
|
|
c.Set("origin_blacklisted", false)
|
|
|
|
origin := strings.TrimSpace(c.GetHeader("Origin"))
|
|
if origin == "" {
|
|
policyLogf(debug, "[cors] skip: no origin method=%s path=%s", c.Request.Method, c.Request.URL.Path)
|
|
c.Next()
|
|
return
|
|
}
|
|
|
|
if config.DB == nil {
|
|
c.AbortWithStatusJSON(http.StatusServiceUnavailable, gin.H{"error": "database is not connected"})
|
|
return
|
|
}
|
|
|
|
var blocked models.CorsBlacklist
|
|
if err := config.DB.
|
|
Where("origin = ? AND is_active = ?", origin, true).
|
|
First(&blocked).Error; err == nil {
|
|
c.Set("origin_blacklisted", true)
|
|
policyLogf(debug, "[cors] blocked origin=%s method=%s path=%s", origin, c.Request.Method, c.Request.URL.Path)
|
|
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "origin is blocked"})
|
|
return
|
|
}
|
|
|
|
var whitelisted models.CorsWhitelist
|
|
if err := config.DB.
|
|
Where("origin = ? AND is_active = ?", origin, true).
|
|
First(&whitelisted).Error; err == nil {
|
|
c.Set("origin_whitelisted", true)
|
|
policyLogf(debug, "[cors] whitelisted origin=%s method=%s path=%s", origin, c.Request.Method, c.Request.URL.Path)
|
|
} else {
|
|
policyLogf(debug, "[cors] pass(non-listed) origin=%s method=%s path=%s", origin, c.Request.Method, c.Request.URL.Path)
|
|
}
|
|
|
|
c.Header("Access-Control-Allow-Origin", origin)
|
|
c.Header("Vary", "Origin")
|
|
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
|
|
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept")
|
|
c.Header("Access-Control-Allow-Credentials", "true")
|
|
|
|
if c.Request.Method == http.MethodOptions {
|
|
policyLogf(debug, "[cors] preflight origin=%s path=%s", origin, c.Request.URL.Path)
|
|
c.AbortWithStatus(http.StatusNoContent)
|
|
return
|
|
}
|
|
|
|
c.Next()
|
|
}
|
|
}
|