// Package http provides HTTP middleware and utilities. package http import ( "net/http" "strings" ) // CORSMiddleware handles Cross-Origin Resource Sharing func CORSMiddleware(allowedOrigins []string) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { origin := r.Header.Get("Origin") allowed := false // If no allowed origins configured, allow all (development mode usually) if len(allowedOrigins) == 0 { allowed = true } else { for _, o := range allowedOrigins { if o == "*" || o == origin { allowed = true break } } } // Safe default if we want to allow everything if allowed { // If origin is present, use it, otherwise * if origin != "" { w.Header().Set("Access-Control-Allow-Origin", origin) } else { w.Header().Set("Access-Control-Allow-Origin", "*") } w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-Client-ID, X-API-Key") w.Header().Set("Access-Control-Allow-Credentials", "true") } if r.Method == "OPTIONS" { w.WriteHeader(http.StatusOK) return } next.ServeHTTP(w, r) }) } } // RequestValidationMiddleware performs basic request validation func RequestValidationMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Check Content-Type for POST requests to /query if r.Method == "POST" && r.URL.Path == "/query" { ct := r.Header.Get("Content-Type") // GraphQL clients might send application/json; charset=utf-8 if !strings.Contains(ct, "application/json") { // Some clients might send no content type or something else? // Strictly enforcing application/json is good for security. // But we should be careful not to break existing clients if they are sloppy. // For now, let's enforce it as requested. http.Error(w, "Content-Type must be application/json", http.StatusUnsupportedMediaType) return } } next.ServeHTTP(w, r) }) } // APIKeyMiddleware checks for X-API-Key header // This is a placeholder for future external integrations. // It allows requests with a valid API key to bypass other auth or strictly enforce it. // Currently it is a pass-through as we don't have defined API keys in config yet. func APIKeyMiddleware(validAPIKeys []string) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // If we had keys, we would check them here. // apiKey := r.Header.Get("X-API-Key") // validate(apiKey) next.ServeHTTP(w, r) }) } }