Phase 2: changement d'email avec vérification de possession hors-bande (suite #145) #64
Labels
No labels
bug
enhancement
pr-split
question
security
transaction-matcher
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
momsse/octant#64
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Contexte
Suite de #63 (fermé par #146). La Phase 1 a fermé la faille de prise de compte sans dépendance mail : un changement d'email self-service n'est plus marqué « vérifié » et n'entre plus dans la surface de merge fédéré (
read.user_email_lookup). La Phase 2 rétablit un vrai changement d'email vérifié via une preuve de possession hors-bande.Objectif
Permettre à un utilisateur de changer son email et de le faire re-devenir une adresse vérifiée (donc ré-éligible au merge fédéré et à l'unicité forte), sur preuve de possession de la nouvelle adresse.
Périmètre
MailSender(service applicatif) + un adaptateur infra (choix de provider à trancher : SMTP / API transactionnelle).requestEmailChangegénère un token à usage unique, CSPRNG, TTL borné (Duration), stocké côté agrégat en hash uniquement (jamais en clair), envoyé hors-bande à la nouvelle adresse.confirmEmailChange(token): le payload porte le token, comparaison constant-time dans l'agrégat, usage unique + expiration. ÉmettreUserEmailVerifiedEventuniquement sur cette preuve.read.user_email_lookup(le projecteur consommeUserEmailVerifiedEvent), rétablissant :Dette technique adjacente (remontée en review de #146)
post-decide / pre-appenddansexecuteCommand(@octant/event-sourcing) pour queRequestEmailChangeUseCasecesse de réimplémenter le pipeline load→decide→append inline (le dedup doit s'intercaler entredecideetappend). Réintègre le short-circuitdecidedEvents.length === 0.Limitations Phase 1 levées par cette issue
EmailAlreadyInUseErrorest en Phase 1 un garde UX best-effort (lecture d'une projection éventuellement cohérente) ; la vérification Phase 2 apporte la garantie d'unicité réelle sur les emails vérifiés.Ajout au périmètre (remonté en review de #146) : normalisation de casse des emails.
findUserByEmail/EmailAlreadyInUseErrorcomparent aujourd'hui les emails comme des chaînes opaques, sans lowercasing. Inoffensif en Phase 1 (les emails non vérifiés n'entrent pas dans la surface de merge), mais dès que la Phase 2 réinsère les emails vérifiés dansread.user_email_lookup, des variantes de casse (Victim@Corp.comvsvictim@corp.com) produiraient deux lignes pour une même boîte. Normaliser (au minimum lowercasing) avant insertion/lookup.