2025-12-03 19:29:37 +00:00
package middleware
import (
2025-12-22 22:17:24 +00:00
"fmt"
chore: consolidate CI, E2E, backend and frontend updates
- CI: workflows updates (cd, ci), remove playwright.yml
- E2E: global-setup, auth/playlists/profile specs
- Remove playwright-report and test-results artifacts from tracking
- Backend: auth, handlers, services, workers, migrations
- Frontend: components, features, vite config
- Add e2e-results.json to gitignore
- Docs: REMEDIATION_PROGRESS, audit archive
- Rust: chat-server, stream-server updates
2026-02-17 15:43:21 +00:00
"os"
2025-12-22 22:17:24 +00:00
"strings"
2025-12-03 19:29:37 +00:00
"github.com/gin-gonic/gin"
2025-12-22 22:17:24 +00:00
"go.uber.org/zap"
2025-12-03 19:29:37 +00:00
)
2025-12-22 22:17:24 +00:00
// ValidateCORSConfiguration valide la configuration CORS pour éviter les problèmes de sécurité
2025-12-25 14:48:48 +00:00
// INT-018: Amélioration de la validation CORS pour la production
// - En production: retourne une erreur si wildcard est utilisé ou si CORS est vide
// - En développement: log un warning mais ne bloque pas
func ValidateCORSConfiguration ( allowedOrigins [ ] string , environment string , logger * zap . Logger ) error {
2025-12-22 22:17:24 +00:00
hasWildcard := false
weakOrigins := [ ] string { }
for _ , origin := range allowedOrigins {
// Détecter les wildcards
if origin == "*" || strings . Contains ( origin , "*" ) {
hasWildcard = true
weakOrigins = append ( weakOrigins , origin )
}
}
2025-12-25 14:48:48 +00:00
// INT-018: Validation stricte en production
if environment == "production" {
// 1. CORS ne doit pas être vide en production
if len ( allowedOrigins ) == 0 {
errMsg := "CORS_ALLOWED_ORIGINS is required in production environment. Empty CORS origins will reject all CORS requests, making the service inaccessible from frontend"
if logger != nil {
logger . Error ( errMsg ,
zap . String ( "environment" , environment ) ,
zap . String ( "recommendation" , "Set CORS_ALLOWED_ORIGINS with explicit origins (e.g., CORS_ALLOWED_ORIGINS=https://app.veza.com,https://www.veza.com)" ) ,
)
}
return fmt . Errorf ( "%s. Please set CORS_ALLOWED_ORIGINS with explicit origins" , errMsg )
}
2025-12-22 22:17:24 +00:00
2025-12-25 14:48:48 +00:00
// 2. CORS ne doit pas contenir de wildcard en production
// CORS spec: credentials=true ne peut pas être utilisé avec Access-Control-Allow-Origin: *
// C'est une faille de sécurité car cela permettrait à n'importe quel site d'accéder aux credentials
if hasWildcard {
errMsg := fmt . Sprintf (
"CORS wildcard origins (%v) are not allowed in production environment with credentials=true. " +
"This violates CORS specification and is a security risk. " +
"Use specific origins instead of wildcards." ,
weakOrigins ,
2025-12-22 22:17:24 +00:00
)
2025-12-25 14:48:48 +00:00
if logger != nil {
logger . Error ( errMsg ,
zap . Strings ( "weak_origins" , weakOrigins ) ,
zap . String ( "environment" , environment ) ,
zap . String ( "recommendation" , "Use specific origins instead of wildcards (e.g., CORS_ALLOWED_ORIGINS=https://app.veza.com,https://www.veza.com)" ) ,
)
}
return fmt . Errorf ( "%s" , errMsg )
2025-12-22 22:17:24 +00:00
}
2025-12-25 14:48:48 +00:00
} else {
// INT-018: En développement/staging, log un warning mais ne bloque pas
if hasWildcard {
warningMsg := fmt . Sprintf (
"SECURITY WARNING: CORS configuration allows wildcard origins (%v) with credentials=true. " +
"This is insecure and violates CORS specification. " +
"Use specific origins instead of wildcards when credentials=true. " +
"This will cause startup failure in production." ,
weakOrigins ,
)
2025-12-22 22:17:24 +00:00
2025-12-25 14:48:48 +00:00
if logger != nil {
logger . Warn ( warningMsg ,
zap . Strings ( "weak_origins" , weakOrigins ) ,
zap . String ( "environment" , environment ) ,
zap . String ( "recommendation" , "Use specific origins instead of wildcards for production" ) ,
)
} else {
// Fallback si logger n'est pas disponible
fmt . Printf ( "⚠️ %s\n" , warningMsg )
}
}
2025-12-22 22:17:24 +00:00
}
return nil
}
2025-12-03 19:29:37 +00:00
// CORS middleware pour gérer les en-têtes CORS avec whitelist d'origins configurable
// allowedOrigins: liste des origines autorisées (ex: []string{"http://localhost:3000", "https://example.com"})
// Si "*" est dans la liste, toutes les origines sont autorisées
2025-12-22 22:17:24 +00:00
// ATTENTION: L'utilisation de "*" avec credentials=true est interdite par la spec CORS
2025-12-03 19:29:37 +00:00
func CORS ( allowedOrigins [ ] string ) gin . HandlerFunc {
return func ( c * gin . Context ) {
origin := c . GetHeader ( "Origin" )
// Vérifier si l'origine est autorisée
if isAllowedOrigin ( origin , allowedOrigins ) {
c . Header ( "Access-Control-Allow-Origin" , origin )
}
2025-12-25 21:27:05 +00:00
c . Header ( "Access-Control-Allow-Methods" , "GET, POST, PUT, PATCH, DELETE, OPTIONS" )
2026-02-02 18:34:14 +00:00
c . Header ( "Access-Control-Allow-Headers" , "Authorization, Content-Type, X-Requested-With, X-CSRF-Token, X-API-Version, x-api-version" )
2025-12-03 19:29:37 +00:00
c . Header ( "Access-Control-Allow-Credentials" , "true" )
2025-12-25 21:27:05 +00:00
c . Header ( "Access-Control-Expose-Headers" , "X-CSRF-Token, X-Request-ID, Content-Range" )
2025-12-17 17:20:42 +00:00
c . Header ( "Access-Control-Max-Age" , "86400" ) // Cache preflight pour 24h
2025-12-03 19:29:37 +00:00
if c . Request . Method == "OPTIONS" {
c . AbortWithStatus ( 204 )
return
}
c . Next ( )
}
}
// isAllowedOrigin vérifie si une origine est dans la liste des origines autorisées
func isAllowedOrigin ( origin string , allowed [ ] string ) bool {
2025-12-13 02:34:34 +00:00
// Sécurité par défaut : si liste vide, on rejette tout
if len ( allowed ) == 0 {
return false
}
2025-12-03 19:29:37 +00:00
for _ , o := range allowed {
// Permettre toutes les origines si "*" est dans la liste
2025-12-13 02:34:34 +00:00
// ATTENTION: À utiliser seulement en dev
if o == "*" {
return true
}
if o == origin {
2025-12-03 19:29:37 +00:00
return true
}
}
return false
}
chore: consolidate CI, E2E, backend and frontend updates
- CI: workflows updates (cd, ci), remove playwright.yml
- E2E: global-setup, auth/playlists/profile specs
- Remove playwright-report and test-results artifacts from tracking
- Backend: auth, handlers, services, workers, migrations
- Frontend: components, features, vite config
- Add e2e-results.json to gitignore
- Docs: REMEDIATION_PROGRESS, audit archive
- Rust: chat-server, stream-server updates
2026-02-17 15:43:21 +00:00
// CORSDefault crée un middleware CORS avec une whitelist par défaut.
// SEC-016: DEPRECATED — DO NOT USE IN PRODUCTION. Panics if APP_ENV=production.
2025-12-03 19:29:37 +00:00
func CORSDefault ( ) gin . HandlerFunc {
chore: consolidate CI, E2E, backend and frontend updates
- CI: workflows updates (cd, ci), remove playwright.yml
- E2E: global-setup, auth/playlists/profile specs
- Remove playwright-report and test-results artifacts from tracking
- Backend: auth, handlers, services, workers, migrations
- Frontend: components, features, vite config
- Add e2e-results.json to gitignore
- Docs: REMEDIATION_PROGRESS, audit archive
- Rust: chat-server, stream-server updates
2026-02-17 15:43:21 +00:00
if os . Getenv ( "APP_ENV" ) == "production" {
panic ( "CORSDefault() must not be used in production - use CORS() with explicit origins" )
}
2025-12-03 19:29:37 +00:00
return CORS ( [ ] string { "*" } )
}