chore: refacto
This commit is contained in:
@@ -47,11 +47,6 @@ type AdminClaims struct {
|
||||
var (
|
||||
userJWTSecret = []byte(os.Getenv("USER_JWT_SECRET")) // ✅ Pour clients
|
||||
adminJWTSecret = []byte(os.Getenv("ADMIN_JWT_SECRET")) // ✅ Pour admin/cabine/livreur
|
||||
roleHierarchy = map[string][]string{
|
||||
"admin": {"admin", "cabine", "livreur", "client"},
|
||||
"cabine": {"cabine", "livreur", "client"},
|
||||
"livreur": {"livreur", "client"},
|
||||
}
|
||||
)
|
||||
|
||||
// ============================================
|
||||
@@ -68,7 +63,7 @@ func validateClientToken(tokenString string, database *db.Database) (*ClientClai
|
||||
log.Printf("🔍 [VALIDATE-CLIENT] Validating client token...")
|
||||
|
||||
// Parser JWT EN PREMIER avec userJWTSecret (CLIENT)
|
||||
token, err := jwt.ParseWithClaims(tokenString, &ClientClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
token, err := jwt.ParseWithClaims(tokenString, &ClientClaims{}, func(token *jwt.Token) (any, error) {
|
||||
// Vérifier explicitement l'algorithme
|
||||
if token.Method.Alg() != jwt.SigningMethodHS256.Alg() {
|
||||
return nil, fmt.Errorf("unexpected signing algorithm: %v", token.Method.Alg())
|
||||
@@ -116,8 +111,7 @@ func validateAdminToken(tokenString string, database *db.Database) (*AdminClaims
|
||||
|
||||
log.Printf("🔍 [VALIDATE-ADMIN] Validating admin token...")
|
||||
|
||||
// Parser JWT EN PREMIER avec adminJWTSecret (ADMIN/CABINE/LIVREUR)
|
||||
token, err := jwt.ParseWithClaims(tokenString, &AdminClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
token, err := jwt.ParseWithClaims(tokenString, &AdminClaims{}, func(token *jwt.Token) (any, error) {
|
||||
if token.Method.Alg() != jwt.SigningMethodHS256.Alg() {
|
||||
return nil, fmt.Errorf("unexpected signing algorithm: %v", token.Method.Alg())
|
||||
}
|
||||
@@ -155,11 +149,6 @@ func validateAdminToken(tokenString string, database *db.Database) (*AdminClaims
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// MIDDLEWARE AUTHENTIFICATION CLIENT
|
||||
// ============================================
|
||||
|
||||
// ClientMiddleware valide le JWT d'un client
|
||||
func ClientMiddleware(c *gin.Context) {
|
||||
authHeader := c.GetHeader("Authorization")
|
||||
if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") {
|
||||
@@ -180,7 +169,6 @@ func ClientMiddleware(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// ✅ NOUVEAU : Vérifier que le token n'a pas été révoqué
|
||||
valid, err := database.IsTokenValid(tokenStr)
|
||||
if err != nil {
|
||||
log.Printf("❌ [CLIENT-MWARE] Erreur vérification token DB: %v", err)
|
||||
@@ -195,7 +183,6 @@ func ClientMiddleware(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Stocker les infos du client dans le contexte
|
||||
c.Set("client_id", claims.ClientID)
|
||||
c.Set("username", claims.Username)
|
||||
c.Set("role", claims.Role)
|
||||
@@ -206,12 +193,6 @@ func ClientMiddleware(c *gin.Context) {
|
||||
c.Next()
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// MIDDLEWARE AUTHENTIFICATION ADMIN
|
||||
// ============================================
|
||||
|
||||
// AdminMiddleware valide le JWT d'un admin (role == "admin" SEULEMENT)
|
||||
// ✅ Remplace le AdminMiddleware de handlers/auth.go
|
||||
func AdminMiddleware(c *gin.Context) {
|
||||
authHeader := c.GetHeader("Authorization")
|
||||
if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") {
|
||||
@@ -232,7 +213,6 @@ func AdminMiddleware(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// ✅ Check révocation
|
||||
valid, err := database.IsTokenValid(tokenStr)
|
||||
if err != nil {
|
||||
log.Printf("❌ [ADMIN-MWARE] Erreur vérification token DB: %v", err)
|
||||
@@ -247,23 +227,14 @@ func AdminMiddleware(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Vérifier rôle
|
||||
validRoles := []string{"admin", "cabine", "livreur"}
|
||||
isValid := false
|
||||
for _, role := range validRoles {
|
||||
if claims.Role == role {
|
||||
isValid = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isValid {
|
||||
log.Printf("❌ [ADMIN-MWARE] Role invalide: %s", claims.Role)
|
||||
// Vérifier rôle — admin uniquement
|
||||
if claims.Role != "admin" {
|
||||
log.Printf("❌ [ADMIN-MWARE] Role invalide: %s (admin requis)", claims.Role)
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "Droits insuffisants - Accès admin requis"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// Stocker les infos de l'admin dans le contexte
|
||||
c.Set("user_id", claims.UserID)
|
||||
c.Set("username", claims.Username)
|
||||
c.Set("role", claims.Role)
|
||||
@@ -275,12 +246,6 @@ func AdminMiddleware(c *gin.Context) {
|
||||
c.Next()
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// MIDDLEWARE AUTHENTIFICATION CABINE
|
||||
// ============================================
|
||||
|
||||
// CabineMiddleware valide que l'utilisateur a accès à la cabine
|
||||
// ✅ Remplace le CabineMiddleware de handlers/auth.go
|
||||
func CabineMiddleware(c *gin.Context) {
|
||||
authHeader := c.GetHeader("Authorization")
|
||||
if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") {
|
||||
@@ -316,22 +281,10 @@ func CabineMiddleware(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Vérifier hiérarchie des rôles
|
||||
allowedRoles := roleHierarchy[claims.Role]
|
||||
authorized := false
|
||||
for _, r := range allowedRoles {
|
||||
if r == "cabine" {
|
||||
authorized = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !authorized {
|
||||
// Vérifier rôle — admin ou cabine uniquement
|
||||
if claims.Role != "admin" && claims.Role != "cabine" {
|
||||
log.Printf("❌ [CABINE-MWARE] Role non autorisé: %s", claims.Role)
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": "Droits insuffisants - Accès cabine requis",
|
||||
"your_role": claims.Role,
|
||||
"allowed_roles": "admin, cabine",
|
||||
})
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "Droits insuffisants - Accès cabine requis"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
@@ -347,12 +300,6 @@ func CabineMiddleware(c *gin.Context) {
|
||||
c.Next()
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// MIDDLEWARE AUTHENTIFICATION LIVREUR
|
||||
// ============================================
|
||||
|
||||
// LivreurMiddleware valide que l'utilisateur est livreur
|
||||
// ✅ Remplace le LivreurMiddleware de handlers/auth.go
|
||||
func LivreurMiddleware(c *gin.Context) {
|
||||
authHeader := c.GetHeader("Authorization")
|
||||
if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") {
|
||||
@@ -388,22 +335,10 @@ func LivreurMiddleware(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Vérifier hiérarchie des rôles
|
||||
allowedRoles := roleHierarchy[claims.Role]
|
||||
authorized := false
|
||||
for _, r := range allowedRoles {
|
||||
if r == "livreur" {
|
||||
authorized = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !authorized {
|
||||
// Vérifier rôle — admin ou livreur uniquement
|
||||
if claims.Role != "admin" && claims.Role != "livreur" {
|
||||
log.Printf("❌ [LIVREUR-MWARE] Role non autorisé: %s", claims.Role)
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": "Droits insuffisants - Accès livreur requis",
|
||||
"your_role": claims.Role,
|
||||
"allowed_roles": "admin, livreur",
|
||||
})
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "Droits insuffisants - Accès livreur requis"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
@@ -419,11 +354,6 @@ func LivreurMiddleware(c *gin.Context) {
|
||||
c.Next()
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// SESSION MIDDLEWARE CLIENT (Existant)
|
||||
// ============================================
|
||||
|
||||
// ClientSessionMiddleware valide la session Redis du client
|
||||
func ClientSessionMiddleware(c *gin.Context) {
|
||||
database := c.MustGet("database").(*db.Database)
|
||||
|
||||
@@ -507,17 +437,10 @@ func ClientSessionMiddleware(c *gin.Context) {
|
||||
c.Next()
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// RATE LIMITING MIDDLEWARE
|
||||
// ============================================
|
||||
|
||||
// RateLimitMiddleware limite le nombre de requêtes par client
|
||||
// Config: 100 requêtes par minute par client
|
||||
func RateLimitMiddleware(c *gin.Context) {
|
||||
// Récupérer le client_id
|
||||
clientID, ok := c.Get("client_id")
|
||||
if !ok {
|
||||
// Pas de client_id (requête publique), pas de rate limit
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
@@ -533,12 +456,10 @@ func RateLimitMiddleware(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Initialiser le TTL à la première requête
|
||||
if count == 1 {
|
||||
db.Redis.Expire(db.RedisCtx, rateLimitKey, 60*time.Second) // 1 minute
|
||||
}
|
||||
|
||||
// Vérifier si dépassement (100 requêtes/min)
|
||||
if count > 100 {
|
||||
log.Printf("❌ [RATELIMIT] Client %d dépassé le limite: %d requêtes/min", clientIDInt, count)
|
||||
c.JSON(http.StatusTooManyRequests, gin.H{
|
||||
@@ -548,7 +469,6 @@ func RateLimitMiddleware(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Ajouter le header du remaining
|
||||
c.Header("X-RateLimit-Remaining", strconv.FormatInt(100-count, 10))
|
||||
|
||||
log.Printf("📊 [RATELIMIT] Client %d: %d/%d requêtes", clientIDInt, count, 100)
|
||||
@@ -556,6 +476,40 @@ func RateLimitMiddleware(c *gin.Context) {
|
||||
c.Next()
|
||||
}
|
||||
|
||||
// LoginRateLimitMiddleware limite les tentatives de connexion par IP.
|
||||
// Config: 10 tentatives par 15 minutes.
|
||||
func LoginRateLimitMiddleware(c *gin.Context) {
|
||||
ip := c.GetHeader("X-Real-IP")
|
||||
if ip == "" {
|
||||
ip = c.ClientIP()
|
||||
}
|
||||
|
||||
rateLimitKey := "ratelimit:login:" + ip
|
||||
|
||||
count, err := db.Redis.Incr(db.RedisCtx, rateLimitKey).Result()
|
||||
if err != nil {
|
||||
log.Printf("⚠️ [LOGIN-RATELIMIT] Erreur Redis: %v", err)
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
if count == 1 {
|
||||
db.Redis.Expire(db.RedisCtx, rateLimitKey, 15*time.Minute)
|
||||
}
|
||||
|
||||
if count > 10 {
|
||||
log.Printf("❌ [LOGIN-RATELIMIT] IP %s bloquée: %d tentatives/15min", ip, count)
|
||||
c.JSON(http.StatusTooManyRequests, gin.H{
|
||||
"error": "Trop de tentatives de connexion - Réessayez dans 15 minutes",
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Header("X-RateLimit-Remaining", strconv.FormatInt(10-count, 10))
|
||||
c.Next()
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// HELPER MIDDLEWARE
|
||||
// ============================================
|
||||
@@ -640,11 +594,6 @@ func LoadClientContext(c *gin.Context, database *db.Database) (*db.SessionData,
|
||||
return session, nil
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// DATABASE MIDDLEWARE
|
||||
// ============================================
|
||||
|
||||
// DatabaseMiddleware injecte la base de données dans le contexte
|
||||
func DatabaseMiddleware(db *db.Database) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
c.Set("database", db)
|
||||
|
||||
Reference in New Issue
Block a user