103 lines
2.5 KiB
Go
103 lines
2.5 KiB
Go
package router
|
|
|
|
import (
|
|
"github.com/atlasos/calypso/internal/common/config"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// securityHeadersMiddleware adds security headers to responses
|
|
func securityHeadersMiddleware(cfg *config.Config) gin.HandlerFunc {
|
|
if !cfg.Security.SecurityHeaders.Enabled {
|
|
return func(c *gin.Context) {
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
return func(c *gin.Context) {
|
|
// Prevent clickjacking
|
|
c.Header("X-Frame-Options", "DENY")
|
|
|
|
// Prevent MIME type sniffing
|
|
c.Header("X-Content-Type-Options", "nosniff")
|
|
|
|
// Enable XSS protection
|
|
c.Header("X-XSS-Protection", "1; mode=block")
|
|
|
|
// Strict Transport Security (HSTS) - only if using HTTPS
|
|
// c.Header("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
|
|
|
|
// Content Security Policy (basic)
|
|
c.Header("Content-Security-Policy", "default-src 'self'")
|
|
|
|
// Referrer Policy
|
|
c.Header("Referrer-Policy", "strict-origin-when-cross-origin")
|
|
|
|
// Permissions Policy
|
|
c.Header("Permissions-Policy", "geolocation=(), microphone=(), camera=()")
|
|
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
// corsMiddleware creates configurable CORS middleware
|
|
func corsMiddleware(cfg *config.Config) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
origin := c.Request.Header.Get("Origin")
|
|
|
|
// Check if origin is allowed
|
|
allowed := false
|
|
for _, allowedOrigin := range cfg.Security.CORS.AllowedOrigins {
|
|
if allowedOrigin == "*" || allowedOrigin == origin {
|
|
allowed = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if allowed {
|
|
c.Writer.Header().Set("Access-Control-Allow-Origin", origin)
|
|
}
|
|
|
|
if cfg.Security.CORS.AllowCredentials {
|
|
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
|
}
|
|
|
|
// Set allowed methods
|
|
methods := cfg.Security.CORS.AllowedMethods
|
|
if len(methods) == 0 {
|
|
methods = []string{"GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"}
|
|
}
|
|
c.Writer.Header().Set("Access-Control-Allow-Methods", joinStrings(methods, ", "))
|
|
|
|
// Set allowed headers
|
|
headers := cfg.Security.CORS.AllowedHeaders
|
|
if len(headers) == 0 {
|
|
headers = []string{"Content-Type", "Authorization", "Accept", "Origin"}
|
|
}
|
|
c.Writer.Header().Set("Access-Control-Allow-Headers", joinStrings(headers, ", "))
|
|
|
|
// Handle preflight requests
|
|
if c.Request.Method == "OPTIONS" {
|
|
c.AbortWithStatus(204)
|
|
return
|
|
}
|
|
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
// joinStrings joins a slice of strings with a separator
|
|
func joinStrings(strs []string, sep string) string {
|
|
if len(strs) == 0 {
|
|
return ""
|
|
}
|
|
if len(strs) == 1 {
|
|
return strs[0]
|
|
}
|
|
result := strs[0]
|
|
for _, s := range strs[1:] {
|
|
result += sep + s
|
|
}
|
|
return result
|
|
}
|
|
|