package http import ( "context" "encoding/json" "log" "net/http" "strings" "time" ) // CORSMiddleware handles Cross-Origin Resource Sharing func CORSMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Set CORS headers w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") 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", "86400") // Handle preflight OPTIONS requests if r.Method == "OPTIONS" { w.WriteHeader(http.StatusOK) return } next.ServeHTTP(w, r) }) } // LogsMiddleware logs HTTP requests with timing information func LogsMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() next.ServeHTTP(w, r) log.Printf("%s %s %s", r.Method, r.RequestURI, time.Since(start)) }) } // AuthMiddleware handles JWT token validation, API keys, and basic auth func AuthMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Skip auth for swagger endpoints and health checks if strings.HasPrefix(r.URL.Path, "/swagger/") || r.URL.Path == "/health" { next.ServeHTTP(w, r) return } // Try Bearer token authentication first authHeader := r.Header.Get("Authorization") if authHeader != "" { if strings.HasPrefix(authHeader, "Bearer ") { token := strings.TrimPrefix(authHeader, "Bearer ") if token != "" { userID, err := validateJWTToken(token) if err == nil { ctx := context.WithValue(r.Context(), "user_id", userID) next.ServeHTTP(w, r.WithContext(ctx)) return } } } } // Try API Key authentication apiKey := r.Header.Get("X-API-Key") if apiKey != "" { if isValidAPIKey(apiKey) { ctx := context.WithValue(r.Context(), "user_id", getUserIDFromAPIKey(apiKey)) next.ServeHTTP(w, r.WithContext(ctx)) return } } // Try Basic authentication username, password, ok := r.BasicAuth() if ok { if isValidCredentials(username, password) { ctx := context.WithValue(r.Context(), "username", username) next.ServeHTTP(w, r.WithContext(ctx)) return } } // Fallback to cookie-based auth (existing behavior) token, err := r.Cookie("token") if err == nil && token.Value == "123" { next.ServeHTTP(w, r) return } // No valid authentication found response := map[string]interface{}{ "error": "Unauthorized", "message": "Valid authentication required. Use Bearer token, API key, or basic auth.", "code": http.StatusUnauthorized, } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusUnauthorized) json.NewEncoder(w).Encode(response) }) } // Helper functions for authentication validation func validateJWTToken(token string) (string, error) { // TODO: Implement JWT validation logic with your preferred JWT library // For demonstration, accept a demo token if token == "valid-jwt-token" { return "user-123", nil } return "", http.ErrAbortHandler } func isValidAPIKey(apiKey string) bool { // TODO: Implement API key validation logic // For demonstration, accept a demo API key return apiKey == "demo-api-key-123" } func getUserIDFromAPIKey(apiKey string) string { // TODO: Implement logic to get user ID from API key // For demonstration, return a mock user ID return "api-user-123" } func isValidCredentials(username, password string) bool { // TODO: Implement credential validation logic // For demonstration, accept demo credentials return username == "admin" && password == "password" } // GetUserIDFromContext extracts user ID from request context func GetUserIDFromContext(ctx context.Context) (string, bool) { userID, ok := ctx.Value("user_id").(string) return userID, ok } // GetUsernameFromContext extracts username from request context func GetUsernameFromContext(ctx context.Context) (string, bool) { username, ok := ctx.Value("username").(string) return username, ok }