Skip to content

Commit 4875af5

Browse files
committed
feat: Email provider integration
1 parent 7f73bcf commit 4875af5

File tree

18 files changed

+2205
-368
lines changed

18 files changed

+2205
-368
lines changed

auth/src/main/java/com/firebase/ui/auth/compose/AuthException.kt

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
package com.firebase.ui.auth.compose
1616

17+
import com.firebase.ui.auth.compose.AuthException.Companion.from
1718
import com.google.firebase.FirebaseException
1819
import com.google.firebase.auth.FirebaseAuthException
1920
import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException
@@ -204,6 +205,38 @@ abstract class AuthException(
204205
cause: Throwable? = null
205206
) : AuthException(message, cause)
206207

208+
class InvalidEmailLinkException(
209+
cause: Throwable? = null
210+
) : AuthException("You are are attempting to sign in with an invalid email link", cause)
211+
212+
class EmailLinkWrongDeviceException(
213+
cause: Throwable? = null
214+
) : AuthException("You must open the email link on the same device.", cause)
215+
216+
class EmailLinkCrossDeviceLinkingException(
217+
cause: Throwable? = null
218+
) : AuthException(
219+
"You must determine if you want to continue linking or " +
220+
"complete the sign in", cause
221+
)
222+
223+
class EmailLinkPromptForEmailException(
224+
cause: Throwable? = null
225+
) : AuthException("Please enter your email to continue signing in", cause)
226+
227+
class EmailLinkDifferentAnonymousUserException(
228+
cause: Throwable? = null
229+
) : AuthException(
230+
"The session associated with this sign-in request has either expired or " +
231+
"was cleared", cause
232+
)
233+
234+
class EmailMismatchException(
235+
cause: Throwable? = null
236+
) : AuthException(
237+
"You are are attempting to sign in a different email than previously " +
238+
"provided", cause)
239+
207240
companion object {
208241
/**
209242
* Creates an appropriate [AuthException] instance from a Firebase authentication exception.
@@ -244,86 +277,111 @@ abstract class AuthException(
244277
cause = firebaseException
245278
)
246279
}
280+
247281
is FirebaseAuthInvalidUserException -> {
248282
when (firebaseException.errorCode) {
249283
"ERROR_USER_NOT_FOUND" -> UserNotFoundException(
250284
message = firebaseException.message ?: "User not found",
251285
cause = firebaseException
252286
)
287+
253288
"ERROR_USER_DISABLED" -> InvalidCredentialsException(
254289
message = firebaseException.message ?: "User account has been disabled",
255290
cause = firebaseException
256291
)
292+
257293
else -> UserNotFoundException(
258294
message = firebaseException.message ?: "User account error",
259295
cause = firebaseException
260296
)
261297
}
262298
}
299+
263300
is FirebaseAuthWeakPasswordException -> {
264301
WeakPasswordException(
265302
message = firebaseException.message ?: "Password is too weak",
266303
cause = firebaseException,
267304
reason = firebaseException.reason
268305
)
269306
}
307+
270308
is FirebaseAuthUserCollisionException -> {
271309
when (firebaseException.errorCode) {
272310
"ERROR_EMAIL_ALREADY_IN_USE" -> EmailAlreadyInUseException(
273-
message = firebaseException.message ?: "Email address is already in use",
311+
message = firebaseException.message
312+
?: "Email address is already in use",
274313
cause = firebaseException,
275314
email = firebaseException.email
276315
)
316+
277317
"ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL" -> AccountLinkingRequiredException(
278-
message = firebaseException.message ?: "Account already exists with different credentials",
318+
message = firebaseException.message
319+
?: "Account already exists with different credentials",
279320
cause = firebaseException
280321
)
322+
281323
"ERROR_CREDENTIAL_ALREADY_IN_USE" -> AccountLinkingRequiredException(
282-
message = firebaseException.message ?: "Credential is already associated with a different user account",
324+
message = firebaseException.message
325+
?: "Credential is already associated with a different user account",
283326
cause = firebaseException
284327
)
328+
285329
else -> AccountLinkingRequiredException(
286330
message = firebaseException.message ?: "Account collision error",
287331
cause = firebaseException
288332
)
289333
}
290334
}
335+
291336
is FirebaseAuthMultiFactorException -> {
292337
MfaRequiredException(
293-
message = firebaseException.message ?: "Multi-factor authentication required",
338+
message = firebaseException.message
339+
?: "Multi-factor authentication required",
294340
cause = firebaseException
295341
)
296342
}
343+
297344
is FirebaseAuthRecentLoginRequiredException -> {
298345
InvalidCredentialsException(
299-
message = firebaseException.message ?: "Recent login required for this operation",
346+
message = firebaseException.message
347+
?: "Recent login required for this operation",
300348
cause = firebaseException
301349
)
302350
}
351+
303352
is FirebaseAuthException -> {
304353
// Handle FirebaseAuthException and check for specific error codes
305354
when (firebaseException.errorCode) {
306355
"ERROR_TOO_MANY_REQUESTS" -> TooManyRequestsException(
307-
message = firebaseException.message ?: "Too many requests. Please try again later",
356+
message = firebaseException.message
357+
?: "Too many requests. Please try again later",
308358
cause = firebaseException
309359
)
360+
310361
else -> UnknownException(
311-
message = firebaseException.message ?: "An unknown authentication error occurred",
362+
message = firebaseException.message
363+
?: "An unknown authentication error occurred",
312364
cause = firebaseException
313365
)
314366
}
315367
}
368+
316369
is FirebaseException -> {
317370
// Handle general Firebase exceptions, which include network errors
318371
NetworkException(
319372
message = firebaseException.message ?: "Network error occurred",
320373
cause = firebaseException
321374
)
322375
}
376+
323377
else -> {
324378
// Check for common cancellation patterns
325-
if (firebaseException.message?.contains("cancelled", ignoreCase = true) == true ||
326-
firebaseException.message?.contains("canceled", ignoreCase = true) == true) {
379+
if (firebaseException.message?.contains(
380+
"cancelled",
381+
ignoreCase = true
382+
) == true ||
383+
firebaseException.message?.contains("canceled", ignoreCase = true) == true
384+
) {
327385
AuthCancelledException(
328386
message = firebaseException.message ?: "Authentication was cancelled",
329387
cause = firebaseException

auth/src/main/java/com/firebase/ui/auth/compose/AuthState.kt

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
package com.firebase.ui.auth.compose
1616

17+
import com.firebase.ui.auth.compose.configuration.auth_provider.AuthProvider
18+
import com.google.firebase.auth.AuthCredential
1719
import com.google.firebase.auth.AuthResult
1820
import com.google.firebase.auth.FirebaseUser
1921
import com.google.firebase.auth.MultiFactorResolver
@@ -204,6 +206,63 @@ abstract class AuthState private constructor() {
204206
"AuthState.RequiresProfileCompletion(user=$user, missingFields=$missingFields)"
205207
}
206208

209+
/**
210+
* The user needs to sign in with a different provider.
211+
*
212+
* Emitted when a user tries to sign up with an email that already exists
213+
* and needs to use the existing provider to sign in instead.
214+
*
215+
* @property provider The [AuthProvider] the user should sign in with
216+
* @property email The email address of the existing account
217+
*/
218+
class RequiresSignIn(
219+
val provider: AuthProvider,
220+
val email: String
221+
) : AuthState() {
222+
override fun equals(other: Any?): Boolean {
223+
if (this === other) return true
224+
if (other !is RequiresSignIn) return false
225+
return provider == other.provider &&
226+
email == other.email
227+
}
228+
229+
override fun hashCode(): Int {
230+
var result = provider.hashCode()
231+
result = 31 * result + email.hashCode()
232+
return result
233+
}
234+
235+
override fun toString(): String =
236+
"AuthState.RequiresSignIn(provider=$provider, email=$email)"
237+
}
238+
239+
/**
240+
* Pending credential for an anonymous upgrade merge conflict.
241+
*
242+
* Emitted when an anonymous user attempts to convert to a permanent account but
243+
* Firebase detects that the target email already belongs to another user. The UI can
244+
* prompt the user to resolve the conflict by signing in with the existing account and
245+
* later linking the stored [pendingCredential].
246+
*/
247+
class MergeConflict(
248+
val pendingCredential: AuthCredential
249+
) : AuthState() {
250+
override fun equals(other: Any?): Boolean {
251+
if (this === other) return true
252+
if (other !is MergeConflict) return false
253+
return pendingCredential == other.pendingCredential
254+
}
255+
256+
override fun hashCode(): Int {
257+
var result = pendingCredential.hashCode()
258+
result = 31 * result + pendingCredential.hashCode()
259+
return result
260+
}
261+
262+
override fun toString(): String =
263+
"AuthState.MergeConflict(pendingCredential=$pendingCredential)"
264+
}
265+
207266
companion object {
208267
/**
209268
* Creates an Idle state instance.
@@ -219,4 +278,4 @@ abstract class AuthState private constructor() {
219278
@JvmStatic
220279
val Cancelled: Cancelled = Cancelled()
221280
}
222-
}
281+
}

0 commit comments

Comments
 (0)