summaryrefslogtreecommitdiff
path: root/internal/middleware/cors.go
diff options
context:
space:
mode:
authorexatombe <jeremy27.clara22@gmail.com>2025-11-02 23:12:12 +0100
committerexatombe <jeremy27.clara22@gmail.com>2025-11-02 23:12:12 +0100
commit549a8b6b8c97c357495c9df198c21e940f56b6a5 (patch)
tree373c2dee7182dacf69179a85e7863bd4f913a991 /internal/middleware/cors.go
parent8a5090a0ada81d8a46c6fad1f36316b6415ff651 (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.go122
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)
+ })
+ }
+}