diff options
| author | exatombe <jeremy27.clara22@gmail.com> | 2025-11-02 23:12:12 +0100 |
|---|---|---|
| committer | exatombe <jeremy27.clara22@gmail.com> | 2025-11-02 23:12:12 +0100 |
| commit | 549a8b6b8c97c357495c9df198c21e940f56b6a5 (patch) | |
| tree | 373c2dee7182dacf69179a85e7863bd4f913a991 /internal/middleware/cors.go | |
| parent | 8a5090a0ada81d8a46c6fad1f36316b6415ff651 (diff) | |
feat: remove proto files and related gRPC code
- Deleted the generated proto file `sovrabase.proto` and its corresponding Go files `sovrabase.pb.go` and `sovrabase_grpc.pb.go`.
- Removed the test script `test_orchestrator_api.go` and added a new configuration file `config.yaml` for orchestrator settings.
- Introduced CORS middleware in `internal/middleware/cors.go` with comprehensive tests in `internal/middleware/cors_test.go`.
- Updated orchestrator tests in `internal/orchestrator/test_orchestrator_api.go` to ensure proper database lifecycle management.
Diffstat (limited to 'internal/middleware/cors.go')
| -rw-r--r-- | internal/middleware/cors.go | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/internal/middleware/cors.go b/internal/middleware/cors.go new file mode 100644 index 0000000..182f9fc --- /dev/null +++ b/internal/middleware/cors.go @@ -0,0 +1,122 @@ +package middleware + +import ( + "log" + "net/http" + "strings" +) + +// CORSConfig holds the configuration for CORS middleware +type CORSConfig struct { + Domain string // Domain principal de l'API (si configuré) + AllowedOrigins []string // Origins autorisées pour CORS +} + +// CORSMiddleware creates a middleware that validates the Host header +// and sets appropriate CORS headers based on the allowed origins +func CORSMiddleware(config *CORSConfig) func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Récupérer le Host header + host := r.Host + + // Récupérer l'Origin header (pour les requêtes CORS) + origin := r.Header.Get("Origin") + + // Extraire le hostname du Host (sans le port) + hostWithoutPort := strings.Split(host, ":")[0] + + // Vérification 1: Si un Domain principal est configuré, le Host doit correspondre + if config.Domain != "" { + // Autoriser localhost en développement même si un Domain est configuré + isLocalhost := hostWithoutPort == "localhost" || hostWithoutPort == "127.0.0.1" || strings.HasPrefix(host, "[::") + + if !isLocalhost && hostWithoutPort != config.Domain && host != config.Domain { + log.Printf("❌ Blocked request: host '%s' does not match configured domain '%s'", host, config.Domain) + http.Error(w, "Forbidden: Invalid domain", http.StatusForbidden) + return + } + + if isLocalhost { + log.Printf("⚠️ Allowing localhost/loopback address despite domain restriction: %s", host) + } + } + + // Vérification 2: CORS - vérifier les origins autorisées + // Si aucune restriction CORS n'est configurée, on autorise tout + if len(config.AllowedOrigins) == 0 { + if origin != "" { + log.Printf("⚠️ No CORS origins configured, allowing all origins") + } + log.Printf("✅ Allowed request from: %s (origin: %s)", host, origin) + next.ServeHTTP(w, r) + return + } + + // Vérifier les origins CORS (quand il y a un header Origin) + allowed := false + matchedOrigin := "" + + if origin != "" { + // Extraire le hostname de l'Origin (peut être avec protocole http:// ou https://) + originHost := strings.TrimPrefix(origin, "http://") + originHost = strings.TrimPrefix(originHost, "https://") + originHost = strings.Split(originHost, ":")[0] + + for _, allowedOrigin := range config.AllowedOrigins { + if originHost == allowedOrigin { + allowed = true + matchedOrigin = origin + break + } + } + + if !allowed { + log.Printf("❌ Blocked CORS request from unauthorized origin: %s (host: %s)", origin, host) + http.Error(w, "Forbidden: Invalid origin", http.StatusForbidden) + return + } + + // Définir les headers CORS appropriés + w.Header().Set("Access-Control-Allow-Origin", matchedOrigin) + w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH") + w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With") + w.Header().Set("Access-Control-Allow-Credentials", "true") + w.Header().Set("Access-Control-Max-Age", "3600") + + // Gérer les requêtes preflight OPTIONS + if r.Method == http.MethodOptions { + w.WriteHeader(http.StatusOK) + return + } + } else { + // Pas de header Origin - ce n'est pas une requête CORS + // Si un Domain est configuré, la vérification a déjà été faite plus haut + // Si pas de Domain, on vérifie que le Host correspond à un des AllowedOrigins + if config.Domain == "" { + for _, allowedOrigin := range config.AllowedOrigins { + if hostWithoutPort == allowedOrigin || host == allowedOrigin { + allowed = true + break + } + } + + // Si localhost est utilisé en développement, on peut l'autoriser + if !allowed && (hostWithoutPort == "localhost" || hostWithoutPort == "127.0.0.1" || strings.HasPrefix(host, "[::")) { + log.Printf("⚠️ Allowing localhost/loopback address: %s", host) + allowed = true + } + + if !allowed { + log.Printf("❌ Blocked request from unauthorized host: %s", host) + http.Error(w, "Forbidden: Invalid host", http.StatusForbidden) + return + } + } + } + + log.Printf("✅ Allowed request from: %s (origin: %s)", host, origin) + next.ServeHTTP(w, r) + }) + } +} |
