feat: Réinitialisation de mot de passe avec tokens sécurisés
Implémentation complète du flux de réinitialisation de mot de passe (Story 1.5): Backend: - Aggregate PasswordResetToken avec TTL 1h, UUID v7, usage unique - Endpoint POST /api/password/forgot avec rate limiting (3/h par email, 10/h par IP) - Endpoint POST /api/password/reset avec validation token - Templates email (demande + confirmation) - Repository Redis avec TTL 2h pour distinguer expiré/invalide Frontend: - Page /mot-de-passe-oublie avec message générique (anti-énumération) - Page /reset-password/[token] avec validation temps réel des critères - Gestion erreurs: token invalide, expiré, déjà utilisé Tests: - 14 tests unitaires PasswordResetToken - 7 tests unitaires RequestPasswordResetHandler - 7 tests unitaires ResetPasswordHandler - Tests E2E Playwright pour le flux complet
This commit is contained in:
113
backend/templates/emails/password_reset.html.twig
Normal file
113
backend/templates/emails/password_reset.html.twig
Normal file
@@ -0,0 +1,113 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Réinitialisation de mot de passe - Classeo</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
padding: 20px 0;
|
||||
border-bottom: 2px solid #4f46e5;
|
||||
}
|
||||
.header h1 {
|
||||
color: #4f46e5;
|
||||
margin: 0;
|
||||
font-size: 28px;
|
||||
}
|
||||
.content {
|
||||
padding: 30px 0;
|
||||
}
|
||||
.info-box {
|
||||
background-color: #fef3c7;
|
||||
border: 1px solid #f59e0b;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.info-box p {
|
||||
margin: 0;
|
||||
color: #92400e;
|
||||
}
|
||||
.button {
|
||||
display: inline-block;
|
||||
background-color: #4f46e5;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
padding: 12px 24px;
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.button:hover {
|
||||
background-color: #4338ca;
|
||||
}
|
||||
.expiry-notice {
|
||||
background-color: #f3f4f6;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
margin: 20px 0;
|
||||
text-align: center;
|
||||
}
|
||||
.expiry-notice p {
|
||||
margin: 0;
|
||||
color: #6b7280;
|
||||
font-size: 14px;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
padding: 20px 0;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
color: #6b7280;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>Classeo</h1>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<h2>Réinitialisation de votre mot de passe</h2>
|
||||
|
||||
<p>Bonjour,</p>
|
||||
|
||||
<p>Nous avons reçu une demande de réinitialisation du mot de passe de votre compte Classeo associé à l'adresse <strong>{{ email }}</strong>.</p>
|
||||
|
||||
<p>Si vous êtes à l'origine de cette demande, cliquez sur le bouton ci-dessous pour définir un nouveau mot de passe :</p>
|
||||
|
||||
<p style="text-align: center; margin: 30px 0;">
|
||||
<a href="{{ resetUrl }}" class="button">Réinitialiser mon mot de passe</a>
|
||||
</p>
|
||||
|
||||
<div class="expiry-notice">
|
||||
<p>Ce lien est valide pendant <strong>1 heure</strong> et ne peut être utilisé qu'une seule fois.</p>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<p><strong>Vous n'avez pas demandé cette réinitialisation ?</strong><br>
|
||||
Ignorez simplement cet email. Votre mot de passe ne sera pas modifié et le lien expirera automatiquement.</p>
|
||||
</div>
|
||||
|
||||
<p><strong>Conseils de sécurité :</strong></p>
|
||||
<ul>
|
||||
<li>Ne partagez jamais ce lien avec d'autres personnes</li>
|
||||
<li>Choisissez un mot de passe fort et unique</li>
|
||||
<li>Si vous suspectez une activité suspecte, contactez votre établissement</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>Cet email a été envoyé automatiquement par Classeo.</p>
|
||||
<p>Si vous n'avez pas demandé cette réinitialisation, vous pouvez ignorer cet email.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user