diff --git a/app/src/main/java/app/closer/data/remote/FirebaseAuthDataSource.kt b/app/src/main/java/app/closer/data/remote/FirebaseAuthDataSource.kt index d82144e3..3d6c9cb2 100644 --- a/app/src/main/java/app/closer/data/remote/FirebaseAuthDataSource.kt +++ b/app/src/main/java/app/closer/data/remote/FirebaseAuthDataSource.kt @@ -3,8 +3,11 @@ package app.closer.data.remote import app.closer.BuildConfig import app.closer.domain.model.AuthState import app.closer.domain.model.GoogleSignInResult +import app.closer.domain.repository.PasswordResetException import com.google.firebase.auth.EmailAuthProvider import com.google.firebase.auth.FirebaseAuth +import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException +import com.google.firebase.auth.FirebaseAuthInvalidUserException import com.google.firebase.auth.GoogleAuthProvider import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow @@ -88,7 +91,28 @@ class FirebaseAuthDataSource @Inject constructor() { .addOnFailureListener { cont.resumeWithException(it) } } - suspend fun sendPasswordResetEmail(email: String): Unit = + /** + * Sends a password-reset email, translating Firebase specifics into typed [PasswordResetException]s + * (robust across SDK/locale wording, unlike matching on error message strings). + * + * This project has Firebase **email-enumeration protection enabled**, so a reset request for an + * address that isn't registered — or is Google-sign-in-only — still returns success with no error, + * by design (revealing existence/provider here would be an enumeration leak). We therefore do NOT + * pre-look-up sign-in methods; the Google-only case is handled by enumeration-safe confirmation copy + * in the UI. [PasswordResetException.NoAccount] is only reachable if that protection is ever disabled; + * [PasswordResetException.InvalidEmail] (a pure format check) always applies. + */ + suspend fun sendPasswordResetEmail(email: String) { + try { + sendResetEmail(email) + } catch (e: FirebaseAuthInvalidUserException) { + throw PasswordResetException.NoAccount() + } catch (e: FirebaseAuthInvalidCredentialsException) { + throw PasswordResetException.InvalidEmail() + } + } + + private suspend fun sendResetEmail(email: String): Unit = suspendCancellableCoroutine { cont -> auth.sendPasswordResetEmail(email) .addOnSuccessListener { cont.resume(Unit) }