Configuration SMTP et 2FA par code PIN e-mail

Paramètres du site :
- Nouvelle section "Serveur SMTP" avec host, port, chiffrement,
  identifiant, mot de passe, adresse/nom d'expéditeur
- Bouton "Envoyer un e-mail de test" (AJAX via Symfony EsmtpTransport) :
  tente la connexion + envoie un message réel à l'admin
- Badge "Configuré — 2FA actif" quand SMTP est en place
- Suppression de la configuration possible

Authentification 2FA :
- Si SMTP configuré : après validation identifiant/mot de passe,
  l'utilisateur est déconnecté, un PIN à 6 chiffres est généré,
  haché (bcrypt) et stocké en session, envoyé par e-mail (10 min)
- Page /2fa : saisie du PIN, bouton "Renvoyer le code", retour login
- Si l'envoi e-mail échoue : fallback sans 2FA (logue l'erreur)
- Si SMTP non configuré : login standard inchangé

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-04 18:59:18 +02:00
parent e6f4d0c565
commit 07ab2a7063
11 changed files with 564 additions and 19 deletions
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Code de connexion</title>
<style>
body { font-family: Arial, sans-serif; background: #f4f4f4; margin: 0; padding: 0; }
.wrapper { max-width: 480px; margin: 40px auto; background: #fff; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,.08); }
.header { background: #4f46e5; padding: 28px 32px; text-align: center; }
.header h1 { color: #fff; margin: 0; font-size: 20px; font-weight: 600; }
.body { padding: 32px; }
.body p { color: #374151; font-size: 15px; line-height: 1.6; margin: 0 0 16px; }
.pin-box { text-align: center; margin: 28px 0; }
.pin { display: inline-block; font-size: 40px; font-weight: 700; letter-spacing: 10px; color: #4f46e5;
background: #eef2ff; border: 2px dashed #a5b4fc; border-radius: 8px;
padding: 16px 32px; font-family: monospace; }
.expiry { font-size: 13px; color: #9ca3af; text-align: center; margin-top: 8px; }
.footer { background: #f9fafb; padding: 20px 32px; border-top: 1px solid #e5e7eb;
font-size: 12px; color: #9ca3af; text-align: center; }
.footer a { color: #6366f1; text-decoration: none; }
</style>
</head>
<body>
<div class="wrapper">
<div class="header">
<h1>{{ config('app.name') }}</h1>
</div>
<div class="body">
<p>Bonjour {{ $userName }},</p>
<p>Voici votre code de connexion à usage unique :</p>
<div class="pin-box">
<div class="pin">{{ $pin }}</div>
<p class="expiry">Ce code expire dans 10 minutes.</p>
</div>
<p>Si vous n'avez pas essayé de vous connecter, ignorez cet e-mail et votre compte restera sécurisé.</p>
</div>
<div class="footer">
Cet e-mail a été envoyé automatiquement par <a href="{{ config('app.url') }}">{{ config('app.name') }}</a>.<br>
Ne transmettez jamais ce code à quelqu'un d'autre.
</div>
</div>
</body>
</html>