refactor(recover_password): type API errors and hide email enumeration

Map PUT /auth/reset-password and PUT /auth/recovery-password failures
into LegacyRecoverPasswordErrorEvent. Reset-password now treats 404
(email not found) as success and surfaces a generic sent-if-exists
flow, closing an account enumeration vector. Recovery-password
differentiates 401 (tokenExpired), 404 (tokenNotFound), 403+Property
(invalidField) from 403 without Property (weakPassword). The view
state splits validation vs API errors with a displayErrorKey extension
for the inline error text.
This commit is contained in:
2026-04-17 11:12:14 +02:00
parent 73d9de45a2
commit fad2c8792c
13 changed files with 198 additions and 42 deletions

View File

@@ -84,6 +84,11 @@
"authErrorTooManyAttempts": "Zu viele Versuche. Bitte warten Sie einige Minuten und versuchen Sie es erneut.",
"authErrorNetwork": "Keine Verbindung. Überprüfen Sie Ihr Netzwerk und versuchen Sie es erneut.",
"signupErrorInvalidField": "Eines der Felder ist ungültig. Bitte überprüfen Sie es und versuchen Sie es erneut.",
"recoverPasswordErrorInvalidEmail": "Das E-Mail-Format ist ungültig.",
"recoverPasswordErrorWeakPassword": "Das Passwort erfüllt die Sicherheitsanforderungen nicht.",
"recoverPasswordErrorInvalidField": "Eines der Felder ist ungültig. Bitte überprüfen Sie es und versuchen Sie es erneut.",
"recoverPasswordErrorTokenExpired": "Der Wiederherstellungslink ist abgelaufen. Bitte fordern Sie einen neuen an.",
"recoverPasswordErrorTokenNotFound": "Der Wiederherstellungslink ist ungültig. Bitte fordern Sie einen neuen an.",
"stepUserContactSupertitle": "Benutzer und Kontakt",
"stepUserContactTitle": "Erstelle dein Konto",
"stepUserContactSubtitle": "Mit deiner E-Mail und deiner Telefonnummer können wir dich jederzeit informieren",

View File

@@ -84,6 +84,11 @@
"authErrorTooManyAttempts": "Too many attempts. Please wait a few minutes and try again.",
"authErrorNetwork": "No connection. Check your network and try again.",
"signupErrorInvalidField": "One of the fields is invalid. Please check and try again.",
"recoverPasswordErrorInvalidEmail": "The email format is not valid.",
"recoverPasswordErrorWeakPassword": "The password does not meet the security requirements.",
"recoverPasswordErrorInvalidField": "One of the fields is invalid. Please check and try again.",
"recoverPasswordErrorTokenExpired": "The recovery link has expired. Please request a new one.",
"recoverPasswordErrorTokenNotFound": "The recovery link is not valid. Please request a new one.",
"stepUserContactSupertitle": "User & contact",
"stepUserContactTitle": "Create your account",
"stepUserContactSubtitle": "With your email and phone number we can keep you informed at all times",

View File

@@ -84,6 +84,11 @@
"authErrorTooManyAttempts": "Demasiados intentos. Espera unos minutos e inténtalo de nuevo.",
"authErrorNetwork": "No hay conexión. Comprueba tu red e inténtalo de nuevo.",
"signupErrorInvalidField": "Alguno de los campos no es válido. Revísalos e inténtalo de nuevo.",
"recoverPasswordErrorInvalidEmail": "El email no tiene un formato válido.",
"recoverPasswordErrorWeakPassword": "La contraseña no cumple los requisitos de seguridad.",
"recoverPasswordErrorInvalidField": "Alguno de los campos no es válido. Revísalos e inténtalo de nuevo.",
"recoverPasswordErrorTokenExpired": "El enlace de recuperación ha caducado. Solicita uno nuevo.",
"recoverPasswordErrorTokenNotFound": "El enlace de recuperación no es válido. Solicita uno nuevo.",
"stepUserContactSupertitle": "Usuario y contacto",
"stepUserContactTitle": "Crea tu usuario",
"stepUserContactSubtitle": "Con tu email y tu número podremos mantenerte siempre informado",

View File

@@ -84,6 +84,11 @@
"authErrorTooManyAttempts": "Trop de tentatives. Patientez quelques minutes avant de réessayer.",
"authErrorNetwork": "Pas de connexion. Vérifiez votre réseau et réessayez.",
"signupErrorInvalidField": "L'un des champs n'est pas valide. Vérifiez et réessayez.",
"recoverPasswordErrorInvalidEmail": "Le format de l'e-mail n'est pas valide.",
"recoverPasswordErrorWeakPassword": "Le mot de passe ne respecte pas les exigences de sécurité.",
"recoverPasswordErrorInvalidField": "L'un des champs n'est pas valide. Vérifiez et réessayez.",
"recoverPasswordErrorTokenExpired": "Le lien de récupération a expiré. Demandez-en un nouveau.",
"recoverPasswordErrorTokenNotFound": "Le lien de récupération n'est pas valide. Demandez-en un nouveau.",
"stepUserContactSupertitle": "Utilisateur et contact",
"stepUserContactTitle": "Crée ton compte",
"stepUserContactSubtitle": "Avec ton e-mail et ton numéro, nous pourrons te tenir informé à tout moment",

View File

@@ -84,6 +84,11 @@
"authErrorTooManyAttempts": "Troppi tentativi. Attendi qualche minuto e riprova.",
"authErrorNetwork": "Nessuna connessione. Controlla la tua rete e riprova.",
"signupErrorInvalidField": "Uno dei campi non è valido. Controlla e riprova.",
"recoverPasswordErrorInvalidEmail": "Il formato dell'email non è valido.",
"recoverPasswordErrorWeakPassword": "La password non soddisfa i requisiti di sicurezza.",
"recoverPasswordErrorInvalidField": "Uno dei campi non è valido. Controlla e riprova.",
"recoverPasswordErrorTokenExpired": "Il link di recupero è scaduto. Richiedine uno nuovo.",
"recoverPasswordErrorTokenNotFound": "Il link di recupero non è valido. Richiedine uno nuovo.",
"stepUserContactSupertitle": "Utente e contatti",
"stepUserContactTitle": "Crea il tuo account",
"stepUserContactSubtitle": "Con la tua email e il tuo numero potremo tenerti sempre informato",

View File

@@ -84,6 +84,11 @@
"authErrorTooManyAttempts": "Demasiadas tentativas. Aguarda alguns minutos e tenta novamente.",
"authErrorNetwork": "Sem ligação. Verifica a tua rede e tenta novamente.",
"signupErrorInvalidField": "Um dos campos não é válido. Verifica e tenta novamente.",
"recoverPasswordErrorInvalidEmail": "O formato do email não é válido.",
"recoverPasswordErrorWeakPassword": "A palavra-passe não cumpre os requisitos de segurança.",
"recoverPasswordErrorInvalidField": "Um dos campos não é válido. Verifica e tenta novamente.",
"recoverPasswordErrorTokenExpired": "O link de recuperação expirou. Solicita um novo.",
"recoverPasswordErrorTokenNotFound": "O link de recuperação não é válido. Solicita um novo.",
"stepUserContactSupertitle": "Utilizador e contacto",
"stepUserContactTitle": "Cria a tua conta",
"stepUserContactSubtitle": "Com o teu email e o teu número poderemos manter-te sempre informado",

View File

@@ -424,6 +424,16 @@ class I18n {
static const String authErrorTooManyAttempts = 'authErrorTooManyAttempts';
static const String authErrorNetwork = 'authErrorNetwork';
static const String signupErrorInvalidField = 'signupErrorInvalidField';
static const String recoverPasswordErrorInvalidEmail =
'recoverPasswordErrorInvalidEmail';
static const String recoverPasswordErrorWeakPassword =
'recoverPasswordErrorWeakPassword';
static const String recoverPasswordErrorInvalidField =
'recoverPasswordErrorInvalidField';
static const String recoverPasswordErrorTokenExpired =
'recoverPasswordErrorTokenExpired';
static const String recoverPasswordErrorTokenNotFound =
'recoverPasswordErrorTokenNotFound';
static const String errorGeofenceCreate = 'errorGeofenceCreate';
static const String errorGeofenceDelete = 'errorGeofenceDelete';
static const String errorGeofenceUpdate = 'errorGeofenceUpdate';