package middleware import ( "net/http" "strings" "veza-backend-api/internal/services" "github.com/gin-gonic/gin" "go.uber.org/zap" ) // WebhookAPIKeyMiddleware crée un middleware pour valider les clés API de webhook (BE-SEC-012) func WebhookAPIKeyMiddleware(webhookService *services.WebhookService, logger *zap.Logger) gin.HandlerFunc { return func(c *gin.Context) { // Extraire la clé API depuis les headers apiKey := extractAPIKey(c) if apiKey == "" { c.JSON(http.StatusUnauthorized, gin.H{ "error": "API key required", }) c.Abort() return } // Valider la clé API webhook, err := webhookService.ValidateAPIKey(c.Request.Context(), apiKey) if err != nil { logger.Warn("Invalid webhook API key", zap.String("api_key_prefix", apiKey[:min(8, len(apiKey))]+"..."), zap.Error(err)) c.JSON(http.StatusUnauthorized, gin.H{ "error": "Invalid API key", }) c.Abort() return } // Stocker le webhook dans le contexte pour utilisation ultérieure c.Set("webhook", webhook) c.Set("webhook_id", webhook.ID) c.Set("user_id", webhook.UserID) c.Next() } } // extractAPIKey extrait la clé API depuis les headers // Supporte X-API-Key et Authorization: Bearer func extractAPIKey(c *gin.Context) string { // Essayer X-API-Key header if apiKey := c.GetHeader("X-API-Key"); apiKey != "" { return apiKey } // Essayer Authorization header avec Bearer authHeader := c.GetHeader("Authorization") if authHeader != "" { parts := strings.SplitN(authHeader, " ", 2) if len(parts) == 2 && strings.ToLower(parts[0]) == "bearer" { return parts[1] } // Si pas de "Bearer", essayer directement la valeur if len(parts) == 1 { return parts[0] } } return "" } // min retourne le minimum de deux entiers func min(a, b int) int { if a < b { return a } return b }