diff --git a/veza-backend-api/internal/api/router.go b/veza-backend-api/internal/api/router.go index 6162eb284..2756dabcc 100644 --- a/veza-backend-api/internal/api/router.go +++ b/veza-backend-api/internal/api/router.go @@ -89,17 +89,18 @@ func getUploadConfigWithEnv() *services.UploadConfig { // Lire ENABLE_CLAMAV depuis l'environnement (défaut: true pour sécurité en production) envValue := os.Getenv("ENABLE_CLAMAV") - fmt.Printf("🔍 [ROUTER] ENABLE_CLAMAV depuis env: '%s'\n", envValue) + zap.L().Debug("ENABLE_CLAMAV from env", zap.String("value", envValue)) clamAVEnabled := getEnvBool("ENABLE_CLAMAV", true) - fmt.Printf("🔍 [ROUTER] ENABLE_CLAMAV parsé: %v\n", clamAVEnabled) + zap.L().Debug("ENABLE_CLAMAV parsed", zap.Bool("value", clamAVEnabled)) uploadConfig.ClamAVEnabled = clamAVEnabled // Lire CLAMAV_REQUIRED depuis l'environnement (défaut: true pour sécurité) clamAVRequired := getEnvBool("CLAMAV_REQUIRED", true) uploadConfig.ClamAVRequired = clamAVRequired - fmt.Printf("🔧 [ROUTER] Configuration finale - ClamAVEnabled=%v, ClamAVRequired=%v\n", - uploadConfig.ClamAVEnabled, uploadConfig.ClamAVRequired) + zap.L().Info("Upload config final", + zap.Bool("clamav_enabled", uploadConfig.ClamAVEnabled), + zap.Bool("clamav_required", uploadConfig.ClamAVRequired)) return uploadConfig } @@ -108,17 +109,17 @@ func getUploadConfigWithEnv() *services.UploadConfig { func getEnvBool(key string, defaultValue bool) bool { value := os.Getenv(key) if value == "" { - fmt.Printf("🔍 [ROUTER] Variable %s non définie, utilisation défaut: %v\n", key, defaultValue) + zap.L().Debug("Env var undefined, using default", zap.String("key", key), zap.Bool("default", defaultValue)) return defaultValue } // Nettoyer la valeur (trim spaces) value = strings.TrimSpace(value) - fmt.Printf("🔍 [ROUTER] Variable %s='%s' (trimmed)\n", key, value) + zap.L().Debug("Env var trimmed", zap.String("key", key), zap.String("value", value)) if boolValue, err := strconv.ParseBool(value); err == nil { - fmt.Printf("🔍 [ROUTER] Variable %s parsée: %v\n", key, boolValue) + zap.L().Debug("Env var parsed", zap.String("key", key), zap.Bool("value", boolValue)) return boolValue } - fmt.Printf("⚠️ [ROUTER] Erreur parsing %s='%s', utilisation défaut: %v\n", key, value, defaultValue) + zap.L().Warn("Env var parse error, using default", zap.String("key", key), zap.String("value", value), zap.Bool("default", defaultValue)) return defaultValue } diff --git a/veza-backend-api/internal/core/track/service.go b/veza-backend-api/internal/core/track/service.go index a329f82d1..21ed7ba96 100644 --- a/veza-backend-api/internal/core/track/service.go +++ b/veza-backend-api/internal/core/track/service.go @@ -227,19 +227,19 @@ func (s *TrackService) UploadTrack(ctx context.Context, userID uuid.UUID, fileHe } // Créer le répertoire d'upload s'il n'existe pas - fmt.Printf("📁 [UPLOAD] Vérification dossier upload: %s\n", s.uploadDir) + s.logger.Debug("Checking upload directory", zap.String("upload_dir", s.uploadDir)) if err := os.MkdirAll(s.uploadDir, 0755); err != nil { - fmt.Printf("❌ [UPLOAD] Erreur création dossier: %v\n", err) + s.logger.Error("Failed to create upload directory", zap.String("upload_dir", s.uploadDir), zap.Error(err)) return nil, fmt.Errorf("%w: failed to create upload directory: %w", ErrStorageError, err) } - fmt.Printf("✅ [UPLOAD] Dossier upload créé/vérifié: %s\n", s.uploadDir) + s.logger.Debug("Upload directory created/verified", zap.String("upload_dir", s.uploadDir)) // Générer un nom de fichier unique timestamp := uuid.New() ext := filepath.Ext(fileHeader.Filename) filename := fmt.Sprintf("%s_%s%s", userID.String(), timestamp.String(), ext) // Fixed format to use strings for UUID filePath := filepath.Join(s.uploadDir, filename) - fmt.Printf("💾 [UPLOAD] Chemin fichier de destination: %s\n", filePath) + s.logger.Debug("Upload destination path", zap.String("file_path", filePath)) // Déterminer le format depuis l'extension format := strings.TrimPrefix(strings.ToUpper(ext), ".") @@ -274,14 +274,14 @@ func (s *TrackService) UploadTrack(ctx context.Context, userID uuid.UUID, fileHe } if err := s.db.WithContext(ctx).Create(track).Error; err != nil { - fmt.Printf("❌ [UPLOAD] Erreur création enregistrement track: %v\n", err) + s.logger.Error("Failed to create track record", zap.Error(err)) return nil, fmt.Errorf("failed to create track record: %w", err) } - fmt.Printf("✅ [UPLOAD] Enregistrement track créé en DB (ID: %s)\n", track.ID.String()) + s.logger.Debug("Track record created in DB", zap.String("track_id", track.ID.String())) // MOD-P2-008: Lancer la copie fichier en goroutine avec suivi (context + cancellation) // La goroutine mettra à jour le Status quand terminé - fmt.Printf("🚀 [UPLOAD] Lancement copie fichier en asynchrone...\n") + s.logger.Debug("Starting async file copy") go s.copyFileAsync(ctx, track.ID, fileHeader, filePath, userID) // MOD-P2-003: Enregistrer la métrique business @@ -305,39 +305,39 @@ func (s *TrackService) copyFileAsync(ctx context.Context, trackID uuid.UUID, fil defer cancel() // Ouvrir le fichier source - fmt.Printf("📂 [UPLOAD ASYNC] Ouverture fichier source...\n") + s.logger.Debug("Opening source file for async copy") src, err := fileHeader.Open() if err != nil { - fmt.Printf("❌ [UPLOAD ASYNC] Erreur ouverture fichier source: %v\n", err) + s.logger.Error("Failed to open source file for async copy", zap.Error(err)) s.updateTrackStatus(copyCtx, trackID, models.TrackStatusFailed, fmt.Sprintf("Failed to open uploaded file: %v", err)) s.cleanupFailedUpload(filePath, trackID, "failed to open source file") return } defer src.Close() - fmt.Printf("✅ [UPLOAD ASYNC] Fichier source ouvert\n") + s.logger.Debug("Source file opened for async copy") // Créer le fichier de destination - fmt.Printf("💾 [UPLOAD ASYNC] Création fichier destination: %s\n", filePath) + s.logger.Debug("Creating destination file", zap.String("file_path", filePath)) dst, err := os.Create(filePath) if err != nil { - fmt.Printf("❌ [UPLOAD ASYNC] Erreur création fichier destination: %v\n", err) + s.logger.Error("Failed to create destination file", zap.String("file_path", filePath), zap.Error(err)) s.updateTrackStatus(copyCtx, trackID, models.TrackStatusFailed, fmt.Sprintf("Failed to create destination file: %v", err)) s.cleanupFailedUpload(filePath, trackID, "failed to create destination file") return } defer dst.Close() - fmt.Printf("✅ [UPLOAD ASYNC] Fichier destination créé\n") + s.logger.Debug("Destination file created") // Copier le fichier avec gestion d'erreurs - fmt.Printf("📋 [UPLOAD ASYNC] Début copie fichier...\n") + s.logger.Debug("Starting file copy") bytesWritten, err := io.Copy(dst, src) if err != nil { - fmt.Printf("❌ [UPLOAD ASYNC] Erreur copie fichier: %v\n", err) + s.logger.Error("File copy failed", zap.Error(err)) s.updateTrackStatus(copyCtx, trackID, models.TrackStatusFailed, fmt.Sprintf("Failed to save file: %v", err)) s.cleanupFailedUpload(filePath, trackID, fmt.Sprintf("copy failed: %v", err)) return } - fmt.Printf("✅ [UPLOAD ASYNC] Fichier copié avec succès (%d bytes écrits)\n", bytesWritten) + s.logger.Debug("File copied successfully", zap.Int64("bytes_written", bytesWritten)) // Vérifier si le contexte a été annulé select { diff --git a/veza-backend-api/internal/handlers/playlist_handler.go b/veza-backend-api/internal/handlers/playlist_handler.go index 769836bd4..6c0b8f578 100644 --- a/veza-backend-api/internal/handlers/playlist_handler.go +++ b/veza-backend-api/internal/handlers/playlist_handler.go @@ -2,7 +2,6 @@ package handlers import ( "errors" - "fmt" "net/http" "strconv" "time" @@ -163,14 +162,14 @@ func (h *PlaylistHandler) GetPlaylists(c *gin.Context) { // Get current user ID var currentUserID *uuid.UUID if uidInterface, exists := c.Get("user_id"); exists { - fmt.Printf("🔍 [HANDLER] GetPlaylists: user_id found in context: %v (Type: %T)\n", uidInterface, uidInterface) + h.commonHandler.logger.Debug("GetPlaylists: user_id found in context", zap.Any("value", uidInterface)) if uid, ok := uidInterface.(uuid.UUID); ok { currentUserID = &uid } else { - fmt.Printf("❌ [HANDLER] GetPlaylists: user_id type assertion failed\n") + h.commonHandler.logger.Debug("GetPlaylists: user_id type assertion failed") } } else { - fmt.Printf("❌ [HANDLER] GetPlaylists: user_id NOT found in context\n") + h.commonHandler.logger.Debug("GetPlaylists: user_id not found in context") } // MOD-P1-004: Ajouter timeout context pour opération DB diff --git a/veza-backend-api/internal/middleware/cors.go b/veza-backend-api/internal/middleware/cors.go index 70c52d15f..04ab88d0e 100644 --- a/veza-backend-api/internal/middleware/cors.go +++ b/veza-backend-api/internal/middleware/cors.go @@ -79,7 +79,11 @@ func ValidateCORSConfiguration(allowedOrigins []string, environment string, logg ) } else { // Fallback si logger n'est pas disponible - fmt.Printf("⚠️ %s\n", warningMsg) + zap.L().Warn(warningMsg, + zap.Strings("weak_origins", weakOrigins), + zap.String("environment", environment), + zap.String("recommendation", "Use specific origins instead of wildcards for production"), + ) } } } diff --git a/veza-backend-api/internal/security/mfa.go b/veza-backend-api/internal/security/mfa.go index 0dcca8c45..580002dd8 100644 --- a/veza-backend-api/internal/security/mfa.go +++ b/veza-backend-api/internal/security/mfa.go @@ -7,6 +7,7 @@ import ( "time" "github.com/pquerna/otp/totp" + "go.uber.org/zap" ) // MFAMethod représente une méthode MFA @@ -188,7 +189,7 @@ func (mfa *MFAManager) SendSMSCode(methodID string) (string, error) { // Dans un vrai système, on enverrait le SMS via un service // Ici on simule l'envoi - fmt.Printf("SMS code sent to %s: %s\n", method.Phone, code) + zap.L().Info("SMS MFA code sent", zap.String("phone", method.Phone)) return code, nil } @@ -248,7 +249,7 @@ func (mfa *MFAManager) SendEmailCode(methodID string) (string, error) { // Dans un vrai système, on enverrait l'email via un service // Ici on simule l'envoi - fmt.Printf("Email code sent to %s: %s\n", method.Email, code) + zap.L().Info("Email MFA code sent", zap.String("email", method.Email)) return code, nil } diff --git a/veza-backend-api/internal/services/upload_validator.go b/veza-backend-api/internal/services/upload_validator.go index 4983d21e7..ecf793c32 100644 --- a/veza-backend-api/internal/services/upload_validator.go +++ b/veza-backend-api/internal/services/upload_validator.go @@ -91,11 +91,12 @@ func DefaultUploadConfig() *UploadConfig { // MOD-P1-001-REFINEMENT: Fail-secure localisé - serveur démarre même si ClamAV down, // mais uploads seront rejetés lors de la validation func NewUploadValidator(config *UploadConfig, logger *zap.Logger) (*UploadValidator, error) { - fmt.Printf("🔧 [UPLOAD VALIDATOR] Initialisation - ClamAVEnabled=%v, ClamAVRequired=%v\n", config.ClamAVEnabled, config.ClamAVRequired) + logger.Info("Upload validator initialization", + zap.Bool("clamav_enabled", config.ClamAVEnabled), + zap.Bool("clamav_required", config.ClamAVRequired)) // EARLY RETURN: Si ClamAV est désactivé, ne JAMAIS toucher à clamdscan if !config.ClamAVEnabled { - fmt.Printf("✅ [UPLOAD VALIDATOR] ClamAV désactivé - Aucun scan antivirus\n") logger.Info("ClamAV is disabled - virus scanning will be skipped", zap.Bool("clamav_enabled", config.ClamAVEnabled), zap.Bool("clamav_required", config.ClamAVRequired), @@ -114,7 +115,7 @@ func NewUploadValidator(config *UploadConfig, logger *zap.Logger) (*UploadValida if clamdPath == "" { clamdPath = "clamdscan" } - fmt.Printf("🛡️ [UPLOAD VALIDATOR] ClamAV activé - Utilisation de %s (exec)\n", clamdPath) + logger.Info("ClamAV enabled, using exec", zap.String("clamd_path", clamdPath)) // Config pour connexion TCP distante (ex: clamav:3310 en Docker) clamAVConfigPath := "" @@ -127,7 +128,7 @@ func NewUploadValidator(config *UploadConfig, logger *zap.Logger) (*UploadValida _, _ = tmpFile.WriteString(configContent) _ = tmpFile.Close() clamAVConfigPath = tmpFile.Name() - fmt.Printf("🛡️ [UPLOAD VALIDATOR] Config TCP: %s -> %s\n", config.ClamAVAddress, clamAVConfigPath) + logger.Info("ClamAV TCP config created", zap.String("address", config.ClamAVAddress), zap.String("config_path", clamAVConfigPath)) } } @@ -136,7 +137,6 @@ func NewUploadValidator(config *UploadConfig, logger *zap.Logger) (*UploadValida pingCtx, pingCancel := context.WithTimeout(context.Background(), 2*time.Second) defer pingCancel() if err := exec.CommandContext(pingCtx, clamdPath, "--version").Run(); err != nil { - fmt.Printf("⚠️ [UPLOAD VALIDATOR] clamdscan non disponible: %v\n", err) if config.ClamAVRequired { logger.Warn("ClamAV is enabled and required but clamdscan unavailable - uploads will be rejected", zap.Error(err), @@ -150,7 +150,6 @@ func NewUploadValidator(config *UploadConfig, logger *zap.Logger) (*UploadValida ) } } else { - fmt.Printf("✅ [UPLOAD VALIDATOR] clamdscan disponible - OK\n") logger.Info("ClamAV (clamdscan) available for virus scanning") } @@ -177,14 +176,17 @@ type ValidationResult struct { // ValidateFile valide un fichier uploadé // MOD-P1-001: Le scan ClamAV se fait AVANT toute persistance func (uv *UploadValidator) ValidateFile(ctx context.Context, fileHeader *multipart.FileHeader, fileType string) (*ValidationResult, error) { - // DEBUG: Log de début de validation - fmt.Printf("🚀 [UPLOAD VALIDATE] Début validation fichier: %s (taille: %d bytes, type: %s)\n", fileHeader.Filename, fileHeader.Size, fileType) - fmt.Printf("🔍 [UPLOAD VALIDATE] État ClamAV - enabled=%v, required=%v, requiredButUnavailable=%v\n", - uv.clamdPath != "", uv.clamAVRequired, uv.clamAVRequiredButUnavailable) + uv.logger.Debug("Validation started", + zap.String("filename", fileHeader.Filename), + zap.Int64("size", fileHeader.Size), + zap.String("file_type", fileType), + zap.Bool("clamav_enabled", uv.clamdPath != ""), + zap.Bool("clamav_required", uv.clamAVRequired), + zap.Bool("clamav_required_but_unavailable", uv.clamAVRequiredButUnavailable)) // EARLY CHECK: Si ClamAV est complètement désactivé, on skip immédiatement if uv.clamdPath == "" { - fmt.Printf("⏭️ [UPLOAD VALIDATE] ClamAV désactivé - scan antivirus ignoré\n") + uv.logger.Debug("ClamAV disabled - virus scan skipped") } result := &ValidationResult{ @@ -194,12 +196,12 @@ func (uv *UploadValidator) ValidateFile(ctx context.Context, fileHeader *multipa // Ouvrir le fichier file, err := fileHeader.Open() if err != nil { - fmt.Printf("❌ [UPLOAD] Erreur ouverture fichier: %v\n", err) + uv.logger.Error("Failed to open file for validation", zap.String("filename", fileHeader.Filename), zap.Error(err)) result.Error = "Failed to open file" return result, err } defer file.Close() - fmt.Printf("✅ [UPLOAD] Fichier ouvert avec succès\n") + uv.logger.Debug("File opened successfully", zap.String("filename", fileHeader.Filename)) // BE-SEC-010: Enhanced file validation - read magic bytes for robust type detection header := make([]byte, 512) @@ -268,11 +270,10 @@ func (uv *UploadValidator) ValidateFile(ctx context.Context, fileHeader *multipa // Scanner avec ClamAV si disponible (clamdscan exec) if uv.clamdPath != "" { - fmt.Printf("🛡️ [UPLOAD VALIDATE] ClamAV activé - Début scan antivirus...\n") + uv.logger.Debug("ClamAV scan starting", zap.String("filename", fileHeader.Filename)) file.Seek(0, 0) infected, err := uv.scanWithClamAV(ctx, file) if err != nil { - fmt.Printf("❌ [UPLOAD] Erreur scan ClamAV: %v\n", err) uv.logger.Error("ClamAV scan failed", zap.Error(err), zap.String("filename", fileHeader.Filename), @@ -284,7 +285,6 @@ func (uv *UploadValidator) ValidateFile(ctx context.Context, fileHeader *multipa // MOD-P1-001: Si virus détecté, rejeter immédiatement (code 422) if infected { - fmt.Printf("⚠️ [UPLOAD] Virus détecté\n") result.Quarantined = true result.Error = "Virus detected" uv.logger.Warn("Virus detected in uploaded file", @@ -293,13 +293,12 @@ func (uv *UploadValidator) ValidateFile(ctx context.Context, fileHeader *multipa return result, fmt.Errorf("clamav_infected: virus detected") } - fmt.Printf("✅ [UPLOAD VALIDATE] Scan ClamAV réussi - fichier propre\n") uv.logger.Info("File scanned successfully with ClamAV", zap.String("filename", fileHeader.Filename), zap.String("status", "clean"), ) } else { - fmt.Printf("⏭️ [UPLOAD VALIDATE] ClamAV désactivé - scan ignoré, validation continue\n") + uv.logger.Debug("ClamAV disabled - scan skipped, validation continues") } // Valider l'extension du fichier @@ -310,7 +309,7 @@ func (uv *UploadValidator) ValidateFile(ctx context.Context, fileHeader *multipa } result.Valid = true - fmt.Printf("✅ [UPLOAD VALIDATE] Validation complète - fichier accepté (Valid=true)\n") + uv.logger.Debug("Validation complete - file accepted", zap.String("filename", fileHeader.Filename)) return result, nil }