feat(auth): wire typed PasswordResetException into FirebaseAuthDataSource

This commit is contained in:
null 2026-07-01 01:50:32 -05:00
parent a1d2ea2db8
commit 885af0b9e4
1 changed files with 25 additions and 1 deletions

View File

@ -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) }