veza/veza-backend-api/internal/middleware/webhook_api_key.go

78 lines
1.8 KiB
Go

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 <api_key>
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
}