Shuffle/app/lib/features/auth/domain/resend_origin.dart
cschlaefke 7d094a6732 fix(auth): treat SMTP failures like success on enumeration-sensitive calls
Refs #37

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-03 12:03:04 +01:00

42 lines
1.7 KiB
Dart

import 'package:shuffle/features/auth/domain/auth_failure.dart';
/// Von wo „E-Mail erneut senden“ ausgelöst wird (Spec #1 § 4.4, F12).
enum ResendOrigin {
/// CheckEmailScreen: Die Adresse kann frei eingegeben sein.
checkEmail,
/// LoginScreen nach `email_not_confirmed`: Das Passwort war richtig.
login,
}
/// Wendet die Regel aus F12/F13 für „E-Mail erneut senden“ an.
///
/// `null` heißt: wie Erfolg behandeln. Sichtbar bleiben nur Eingabe- und
/// Transportfehler sowie die kontounabhängige IP-Drosselung (Allowlist);
/// alles andere (auch `unexpected`, z. B. SMTP-Ausfall) ist neutral, weil es
/// zwischen bekannter und unbekannter Adresse unterscheiden kann. Aus dem
/// LoginScreen wird `emailSendLimited` zum sichtbaren Drosselungshinweis
/// ([RateLimited]).
AuthFailure? resendFailureFor(AuthFailure failure, ResendOrigin origin) {
return switch (failure) {
EmailSendLimited() =>
origin == ResendOrigin.login ? const AuthFailure.rateLimited() : null,
InvalidEmail() || RateLimited() || NetworkFailure() => failure,
_ => null,
};
}
/// Registrierung und Passwort-Reset (freie Adresseingabe, F12/F13): Sichtbar
/// bleiben nur Eingabefehler (`invalidEmail`, `weakPassword`,
/// `registrationRejected` mit bekanntem Grund), Transportfehler und die
/// kontounabhängige IP-Drosselung (Allowlist). Alles andere, insbesondere
/// `emailSendLimited` und `unexpected` (SMTP-Ausfall), zählt wie Erfolg
/// (KTO-01 Kriterium 4). Liefert `null` für „wie Erfolg“, sonst den Fehler.
AuthFailure? openEmailInputFailureFor(AuthFailure failure) => switch (failure) {
InvalidEmail() ||
WeakPassword() ||
RegistrationRejected() ||
RateLimited() ||
NetworkFailure() => failure,
_ => null,
};