diff --git a/app/src/main/java/com/firebaseui/android/demo/HighLevelApiDemoActivity.kt b/app/src/main/java/com/firebaseui/android/demo/HighLevelApiDemoActivity.kt index 52427bba9..fcae3ea9c 100644 --- a/app/src/main/java/com/firebaseui/android/demo/HighLevelApiDemoActivity.kt +++ b/app/src/main/java/com/firebaseui/android/demo/HighLevelApiDemoActivity.kt @@ -14,10 +14,16 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.PlainTooltip import androidx.compose.material3.ShapeDefaults import androidx.compose.material3.Surface import androidx.compose.material3.Text +import androidx.compose.material3.TooltipAnchorPosition +import androidx.compose.material3.TooltipBox +import androidx.compose.material3.TooltipDefaults +import androidx.compose.material3.rememberTooltipState import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -57,6 +63,7 @@ class HighLevelApiDemoActivity : ComponentActivity() { tosUrl = "https://policies.google.com/terms" privacyPolicyUrl = "https://policies.google.com/privacy" isAnonymousUpgradeEnabled = false + isMfaEnabled = false transitions = AuthUITransitions( enterTransition = { slideInHorizontally { it } }, exitTransition = { slideOutHorizontally { -it } }, @@ -193,12 +200,14 @@ class HighLevelApiDemoActivity : ComponentActivity() { } } +@OptIn(ExperimentalMaterial3Api::class) @Composable private fun AppAuthenticatedContent( state: AuthState, uiContext: AuthSuccessUiContext ) { val stringProvider = uiContext.stringProvider + val configuration = uiContext.configuration when (state) { is AuthState.Success -> { val user = uiContext.authUI.getCurrentUser() @@ -226,8 +235,25 @@ private fun AppAuthenticatedContent( textAlign = TextAlign.Center ) Spacer(modifier = Modifier.height(16.dp)) - Button(onClick = uiContext.onManageMfa) { - Text(stringProvider.manageMfaAction) + TooltipBox( + positionProvider = TooltipDefaults.rememberTooltipPositionProvider( + TooltipAnchorPosition.Above + ), + tooltip = { + PlainTooltip { + Text(stringProvider.mfaDisabledTooltip) + } + }, + state = rememberTooltipState( + initialIsVisible = !configuration.isMfaEnabled + ) + ) { + Button( + onClick = uiContext.onManageMfa, + enabled = configuration.isMfaEnabled + ) { + Text(stringProvider.manageMfaAction) + } } Spacer(modifier = Modifier.height(8.dp)) Button(onClick = uiContext.onSignOut) { diff --git a/auth/README.md b/auth/README.md index ecc3208aa..6061eea06 100644 --- a/auth/README.md +++ b/auth/README.md @@ -138,6 +138,7 @@ If using Facebook Login, add your Facebook App ID to `strings.xml`: YOUR_FACEBOOK_APP_ID fbYOUR_FACEBOOK_APP_ID + CHANGE-ME ``` @@ -489,9 +490,6 @@ Configure Facebook Login with optional permissions: ```kotlin val facebookProvider = AuthProvider.Facebook( - // Optional: Facebook application ID (reads from strings.xml if not provided) - applicationId = "YOUR_FACEBOOK_APP_ID", - // Optional: Permissions to request (default: ["email", "public_profile"]) scopes = listOf("email", "public_profile", "user_friends"), diff --git a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/AuthProvider.kt b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/AuthProvider.kt index 1b659a8fc..5cf392a8c 100644 --- a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/AuthProvider.kt +++ b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/AuthProvider.kt @@ -485,7 +485,21 @@ abstract class AuthProvider(open val providerId: String, open val providerName: /** * The OAuth 2.0 client ID for your server. */ - val serverClientId: String?, + var serverClientId: String?, + + /** + * Whether to filter by authorized accounts. + * When true, only shows Google accounts that have previously authorized this app. + * Defaults to true, with automatic fallback to false if no authorized accounts found. + */ + val filterByAuthorizedAccounts: Boolean = true, + + /** + * Whether to enable auto-select for single account scenarios. + * When true, automatically selects the account if only one is available. + * Defaults to false for better user control. + */ + val autoSelectEnabled: Boolean = false, /** * A map of custom OAuth parameters. @@ -505,8 +519,9 @@ abstract class AuthProvider(open val providerId: String, open val providerName: " default_web_client_id string wasn't populated.", R.string.default_web_client_id ) + serverClientId = context.getString(R.string.default_web_client_id) } else { - require(serverClientId.isNotBlank()) { + require(serverClientId!!.isNotBlank()) { "Server client ID cannot be blank." } } @@ -529,7 +544,7 @@ abstract class AuthProvider(open val providerId: String, open val providerName: val credential: AuthCredential, val idToken: String, val displayName: String?, - val photoUrl: Uri? + val photoUrl: Uri?, ) /** @@ -567,7 +582,7 @@ abstract class AuthProvider(open val providerId: String, open val providerName: credentialManager: CredentialManager, serverClientId: String, filterByAuthorizedAccounts: Boolean, - autoSelectEnabled: Boolean + autoSelectEnabled: Boolean, ): GoogleSignInResult suspend fun clearCredentialState( @@ -600,8 +615,10 @@ abstract class AuthProvider(open val providerId: String, open val providerName: .build() val result = credentialManager.getCredential(context, request) - val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(result.credential.data) - val credential = GoogleAuthProvider.getCredential(googleIdTokenCredential.idToken, null) + val googleIdTokenCredential = + GoogleIdTokenCredential.createFrom(result.credential.data) + val credential = + GoogleAuthProvider.getCredential(googleIdTokenCredential.idToken, null) return GoogleSignInResult( credential = credential, @@ -624,11 +641,6 @@ abstract class AuthProvider(open val providerId: String, open val providerName: * Facebook Login provider configuration. */ class Facebook( - /** - * The Facebook application ID. - */ - val applicationId: String? = null, - /** * The list of scopes (permissions) to request. Defaults to email and public_profile. */ @@ -653,18 +665,26 @@ abstract class AuthProvider(open val providerId: String, open val providerName: ) } - if (applicationId == null) { - Preconditions.checkConfigured( - context, - "Facebook provider unconfigured. Make sure to " + - "add a `facebook_application_id` string or provide applicationId parameter.", - R.string.facebook_application_id - ) - } else { - require(applicationId.isNotBlank()) { - "Facebook application ID cannot be blank" - } - } + Preconditions.checkConfigured( + context, + "Facebook provider unconfigured. Make sure to " + + "add a `facebook_application_id` string to your strings.xml", + R.string.facebook_application_id + ) + + Preconditions.checkConfigured( + context, + "Facebook provider unconfigured. Make sure to " + + "add a `facebook_login_protocol_scheme` string to your strings.xml", + R.string.facebook_login_protocol_scheme + ) + + Preconditions.checkConfigured( + context, + "Facebook provider unconfigured. Make sure to " + + "add a `facebook_client_token` string to your strings.xml", + R.string.facebook_client_token + ) } /** diff --git a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProvider+FirebaseAuthUI.kt b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProvider+FirebaseAuthUI.kt index 2afdb3599..4d18cb0a9 100644 --- a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProvider+FirebaseAuthUI.kt +++ b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProvider+FirebaseAuthUI.kt @@ -133,14 +133,48 @@ internal suspend fun FirebaseAuthUI.signInWithGoogle( } } - val result = + // Try with configured filterByAuthorizedAccounts setting + // If default (true), fallback to false if no authorized accounts found + // See: https://developer.android.com/identity/sign-in/credential-manager-siwg#siwg-button + val result = if (provider.filterByAuthorizedAccounts) { + // Default behavior: Try authorized accounts first, fallback to all accounts + try { + (testCredentialManagerProvider ?: credentialManagerProvider).getGoogleCredential( + context = context, + credentialManager = CredentialManager.create(context), + serverClientId = provider.serverClientId!!, + filterByAuthorizedAccounts = true, + autoSelectEnabled = provider.autoSelectEnabled + ) + } catch (e: NoCredentialException) { + // No authorized accounts found, try again with all accounts for sign-up flow + Log.d("GoogleAuthProvider", "No authorized accounts found, showing all Google accounts for sign-up") + try { + (testCredentialManagerProvider ?: credentialManagerProvider).getGoogleCredential( + context = context, + credentialManager = CredentialManager.create(context), + serverClientId = provider.serverClientId!!, + filterByAuthorizedAccounts = false, + autoSelectEnabled = provider.autoSelectEnabled + ) + } catch (fallbackException: NoCredentialException) { + // No Google accounts available on device at all + throw AuthException.UnknownException( + message = "No Google accounts available.\n\nPlease add a Google account to your device and try again.", + cause = fallbackException + ) + } + } + } else { + // Developer explicitly wants to show all accounts (no fallback needed) (testCredentialManagerProvider ?: credentialManagerProvider).getGoogleCredential( context = context, credentialManager = CredentialManager.create(context), serverClientId = provider.serverClientId!!, - filterByAuthorizedAccounts = true, - autoSelectEnabled = false + filterByAuthorizedAccounts = false, + autoSelectEnabled = provider.autoSelectEnabled ) + } idTokenFromResult = result.idToken signInAndLinkWithCredential( diff --git a/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/AuthUIStringProvider.kt b/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/AuthUIStringProvider.kt index df71966ab..a062debdd 100644 --- a/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/AuthUIStringProvider.kt +++ b/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/AuthUIStringProvider.kt @@ -539,4 +539,7 @@ interface AuthUIStringProvider { /** Tooltip message shown when new account sign-up is disabled */ val newAccountsDisabledTooltip: String + + /** Tooltip message shown when MFA is disabled */ + val mfaDisabledTooltip: String } diff --git a/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/DefaultAuthUIStringProvider.kt b/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/DefaultAuthUIStringProvider.kt index a0e53e2a9..429d6d286 100644 --- a/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/DefaultAuthUIStringProvider.kt +++ b/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/DefaultAuthUIStringProvider.kt @@ -491,4 +491,7 @@ class DefaultAuthUIStringProvider( override val newAccountsDisabledTooltip: String get() = localizedContext.getString(R.string.fui_new_accounts_disabled_tooltip) + + override val mfaDisabledTooltip: String + get() = localizedContext.getString(R.string.fui_mfa_disabled_tooltip) } diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/screens/FirebaseAuthScreen.kt b/auth/src/main/java/com/firebase/ui/auth/ui/screens/FirebaseAuthScreen.kt index 6b3bf5d38..5a065400c 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/screens/FirebaseAuthScreen.kt +++ b/auth/src/main/java/com/firebase/ui/auth/ui/screens/FirebaseAuthScreen.kt @@ -28,10 +28,16 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.PlainTooltip import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text +import androidx.compose.material3.TooltipAnchorPosition +import androidx.compose.material3.TooltipBox +import androidx.compose.material3.TooltipDefaults +import androidx.compose.material3.rememberTooltipState import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect @@ -348,6 +354,7 @@ fun FirebaseAuthScreen( AuthSuccessUiContext( authUI = authUI, stringProvider = stringProvider, + configuration = configuration, onSignOut = { coroutineScope.launch { try { @@ -362,7 +369,15 @@ fun FirebaseAuthScreen( } }, onManageMfa = { - navController.navigate(AuthRoute.MfaEnrollment.route) + if (configuration.isMfaEnabled) { + navController.navigate(AuthRoute.MfaEnrollment.route) + } else { + val exception = AuthException.AuthCancelledException( + message = "Multi-factor authentication is disabled in the configuration. " + + "Enable MFA in AuthUIConfiguration to use this feature." + ) + authUI.updateAuthState(AuthState.Error(exception)) + } }, onReloadUser = { coroutineScope.launch { @@ -410,6 +425,7 @@ fun FirebaseAuthScreen( SuccessDestination( authState = authState, stringProvider = stringProvider, + configuration = configuration, uiContext = uiContext ) } @@ -654,6 +670,7 @@ sealed class AuthRoute(val route: String) { data class AuthSuccessUiContext( val authUI: FirebaseAuthUI, val stringProvider: AuthUIStringProvider, + val configuration: AuthUIConfiguration, val onSignOut: () -> Unit, val onManageMfa: () -> Unit, val onReloadUser: () -> Unit, @@ -664,6 +681,7 @@ data class AuthSuccessUiContext( private fun SuccessDestination( authState: AuthState, stringProvider: AuthUIStringProvider, + configuration: AuthUIConfiguration, uiContext: AuthSuccessUiContext, ) { when (authState) { @@ -671,6 +689,7 @@ private fun SuccessDestination( AuthSuccessContent( authUI = uiContext.authUI, stringProvider = stringProvider, + configuration = configuration, onSignOut = uiContext.onSignOut, onManageMfa = uiContext.onManageMfa ) @@ -704,10 +723,12 @@ private fun SuccessDestination( } } +@OptIn(ExperimentalMaterial3Api::class) @Composable private fun AuthSuccessContent( authUI: FirebaseAuthUI, stringProvider: AuthUIStringProvider, + configuration: AuthUIConfiguration, onSignOut: () -> Unit, onManageMfa: () -> Unit, ) { @@ -726,8 +747,25 @@ private fun AuthSuccessContent( Spacer(modifier = Modifier.height(16.dp)) } if (user != null && authUI.auth.app.options.projectId != null) { - Button(onClick = onManageMfa) { - Text(stringProvider.manageMfaAction) + TooltipBox( + positionProvider = TooltipDefaults.rememberTooltipPositionProvider( + TooltipAnchorPosition.Above + ), + tooltip = { + PlainTooltip { + Text(stringProvider.mfaDisabledTooltip) + } + }, + state = rememberTooltipState( + initialIsVisible = !configuration.isMfaEnabled + ) + ) { + Button( + onClick = onManageMfa, + enabled = configuration.isMfaEnabled + ) { + Text(stringProvider.manageMfaAction) + } } Spacer(modifier = Modifier.height(8.dp)) } diff --git a/auth/src/main/res/values-ar/strings.xml b/auth/src/main/res/values-ar/strings.xml index dcf4ca88c..e6d6f9b96 100755 --- a/auth/src/main/res/values-ar/strings.xml +++ b/auth/src/main/res/values-ar/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + المصادقة متعددة العوامل معطلة حاليًا diff --git a/auth/src/main/res/values-b+es+419/strings.xml b/auth/src/main/res/values-b+es+419/strings.xml index 017b893bd..0513671be 100755 --- a/auth/src/main/res/values-b+es+419/strings.xml +++ b/auth/src/main/res/values-b+es+419/strings.xml @@ -197,4 +197,5 @@ This button is currently disabled because new accounts are not allowed + Multi-factor authentication is currently disabled diff --git a/auth/src/main/res/values-bg/strings.xml b/auth/src/main/res/values-bg/strings.xml index 8b9db9839..08432527b 100755 --- a/auth/src/main/res/values-bg/strings.xml +++ b/auth/src/main/res/values-bg/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + Многофакторната автентификация в момента е деактивирана diff --git a/auth/src/main/res/values-bn/strings.xml b/auth/src/main/res/values-bn/strings.xml index 747f19c8c..18010598a 100755 --- a/auth/src/main/res/values-bn/strings.xml +++ b/auth/src/main/res/values-bn/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + মাল্টি-ফ্যাক্টর প্রমাণীকরণ বর্তমানে নিষ্ক্রিয় diff --git a/auth/src/main/res/values-ca/strings.xml b/auth/src/main/res/values-ca/strings.xml index 5b56f2489..a4cb13b80 100755 --- a/auth/src/main/res/values-ca/strings.xml +++ b/auth/src/main/res/values-ca/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + L\'autenticació multifactor està desactivada actualment diff --git a/auth/src/main/res/values-cs/strings.xml b/auth/src/main/res/values-cs/strings.xml index 57afae344..527ddce0f 100755 --- a/auth/src/main/res/values-cs/strings.xml +++ b/auth/src/main/res/values-cs/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + Vícefaktorové ověřování je aktuálně zakázáno diff --git a/auth/src/main/res/values-da/strings.xml b/auth/src/main/res/values-da/strings.xml index 0b91742aa..0fb15c8cf 100755 --- a/auth/src/main/res/values-da/strings.xml +++ b/auth/src/main/res/values-da/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + Multifaktorgodkendelse er i øjeblikket deaktiveret diff --git a/auth/src/main/res/values-de-rAT/strings.xml b/auth/src/main/res/values-de-rAT/strings.xml index 427f52319..10ebb575b 100755 --- a/auth/src/main/res/values-de-rAT/strings.xml +++ b/auth/src/main/res/values-de-rAT/strings.xml @@ -197,4 +197,5 @@ This button is currently disabled because new accounts are not allowed + Die Multi-Faktor-Authentifizierung ist derzeit deaktiviert diff --git a/auth/src/main/res/values-de-rCH/strings.xml b/auth/src/main/res/values-de-rCH/strings.xml index 316f26f09..f45895074 100755 --- a/auth/src/main/res/values-de-rCH/strings.xml +++ b/auth/src/main/res/values-de-rCH/strings.xml @@ -198,4 +198,5 @@ This button is currently disabled because new accounts are not allowed + Die Multi-Faktor-Authentifizierung ist derzeit deaktiviert diff --git a/auth/src/main/res/values-de/strings.xml b/auth/src/main/res/values-de/strings.xml index e7c0a9bd4..01232ea04 100755 --- a/auth/src/main/res/values-de/strings.xml +++ b/auth/src/main/res/values-de/strings.xml @@ -197,4 +197,5 @@ This button is currently disabled because new accounts are not allowed + Die Multi-Faktor-Authentifizierung ist derzeit deaktiviert diff --git a/auth/src/main/res/values-el/strings.xml b/auth/src/main/res/values-el/strings.xml index 7a1872d87..434a11268 100755 --- a/auth/src/main/res/values-el/strings.xml +++ b/auth/src/main/res/values-el/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + Ο έλεγχος ταυτότητας πολλαπλών παραγόντων είναι απενεργοποιημένος προς το παρόν diff --git a/auth/src/main/res/values-en-rAU/strings.xml b/auth/src/main/res/values-en-rAU/strings.xml index 33bd778b7..4f5b7581e 100755 --- a/auth/src/main/res/values-en-rAU/strings.xml +++ b/auth/src/main/res/values-en-rAU/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + Multi-factor authentication is currently disabled diff --git a/auth/src/main/res/values-en-rCA/strings.xml b/auth/src/main/res/values-en-rCA/strings.xml index 9534d4b43..214a3d91f 100755 --- a/auth/src/main/res/values-en-rCA/strings.xml +++ b/auth/src/main/res/values-en-rCA/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + Multi-factor authentication is currently disabled diff --git a/auth/src/main/res/values-en-rGB/strings.xml b/auth/src/main/res/values-en-rGB/strings.xml index f86d87442..c30f71c1d 100755 --- a/auth/src/main/res/values-en-rGB/strings.xml +++ b/auth/src/main/res/values-en-rGB/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + Multi-factor authentication is currently disabled diff --git a/auth/src/main/res/values-en-rIE/strings.xml b/auth/src/main/res/values-en-rIE/strings.xml index 5d7f7b2f3..1a3b4860e 100755 --- a/auth/src/main/res/values-en-rIE/strings.xml +++ b/auth/src/main/res/values-en-rIE/strings.xml @@ -172,4 +172,5 @@ This button is currently disabled because new accounts are not allowed + Multi-factor authentication is currently disabled diff --git a/auth/src/main/res/values-en-rIN/strings.xml b/auth/src/main/res/values-en-rIN/strings.xml index 5d7f7b2f3..1a3b4860e 100755 --- a/auth/src/main/res/values-en-rIN/strings.xml +++ b/auth/src/main/res/values-en-rIN/strings.xml @@ -172,4 +172,5 @@ This button is currently disabled because new accounts are not allowed + Multi-factor authentication is currently disabled diff --git a/auth/src/main/res/values-en-rSG/strings.xml b/auth/src/main/res/values-en-rSG/strings.xml index 5d7f7b2f3..1a3b4860e 100755 --- a/auth/src/main/res/values-en-rSG/strings.xml +++ b/auth/src/main/res/values-en-rSG/strings.xml @@ -172,4 +172,5 @@ This button is currently disabled because new accounts are not allowed + Multi-factor authentication is currently disabled diff --git a/auth/src/main/res/values-en-rZA/strings.xml b/auth/src/main/res/values-en-rZA/strings.xml index 5d7f7b2f3..1a3b4860e 100755 --- a/auth/src/main/res/values-en-rZA/strings.xml +++ b/auth/src/main/res/values-en-rZA/strings.xml @@ -172,4 +172,5 @@ This button is currently disabled because new accounts are not allowed + Multi-factor authentication is currently disabled diff --git a/auth/src/main/res/values-es-rAR/strings.xml b/auth/src/main/res/values-es-rAR/strings.xml index df6acc012..8bf944c45 100755 --- a/auth/src/main/res/values-es-rAR/strings.xml +++ b/auth/src/main/res/values-es-rAR/strings.xml @@ -190,4 +190,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-es-rBO/strings.xml b/auth/src/main/res/values-es-rBO/strings.xml index 9ebc9ee65..95195a514 100755 --- a/auth/src/main/res/values-es-rBO/strings.xml +++ b/auth/src/main/res/values-es-rBO/strings.xml @@ -190,4 +190,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-es-rCL/strings.xml b/auth/src/main/res/values-es-rCL/strings.xml index 9ebc9ee65..95195a514 100755 --- a/auth/src/main/res/values-es-rCL/strings.xml +++ b/auth/src/main/res/values-es-rCL/strings.xml @@ -190,4 +190,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-es-rCO/strings.xml b/auth/src/main/res/values-es-rCO/strings.xml index 9ebc9ee65..95195a514 100755 --- a/auth/src/main/res/values-es-rCO/strings.xml +++ b/auth/src/main/res/values-es-rCO/strings.xml @@ -190,4 +190,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-es-rCR/strings.xml b/auth/src/main/res/values-es-rCR/strings.xml index 9ebc9ee65..95195a514 100755 --- a/auth/src/main/res/values-es-rCR/strings.xml +++ b/auth/src/main/res/values-es-rCR/strings.xml @@ -190,4 +190,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-es-rDO/strings.xml b/auth/src/main/res/values-es-rDO/strings.xml index 9ebc9ee65..95195a514 100755 --- a/auth/src/main/res/values-es-rDO/strings.xml +++ b/auth/src/main/res/values-es-rDO/strings.xml @@ -190,4 +190,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-es-rEC/strings.xml b/auth/src/main/res/values-es-rEC/strings.xml index 9ebc9ee65..95195a514 100755 --- a/auth/src/main/res/values-es-rEC/strings.xml +++ b/auth/src/main/res/values-es-rEC/strings.xml @@ -190,4 +190,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-es-rGT/strings.xml b/auth/src/main/res/values-es-rGT/strings.xml index 9ebc9ee65..95195a514 100755 --- a/auth/src/main/res/values-es-rGT/strings.xml +++ b/auth/src/main/res/values-es-rGT/strings.xml @@ -190,4 +190,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-es-rHN/strings.xml b/auth/src/main/res/values-es-rHN/strings.xml index 9ebc9ee65..95195a514 100755 --- a/auth/src/main/res/values-es-rHN/strings.xml +++ b/auth/src/main/res/values-es-rHN/strings.xml @@ -190,4 +190,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-es-rMX/strings.xml b/auth/src/main/res/values-es-rMX/strings.xml index 9ebc9ee65..95195a514 100755 --- a/auth/src/main/res/values-es-rMX/strings.xml +++ b/auth/src/main/res/values-es-rMX/strings.xml @@ -190,4 +190,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-es-rNI/strings.xml b/auth/src/main/res/values-es-rNI/strings.xml index 9ebc9ee65..95195a514 100755 --- a/auth/src/main/res/values-es-rNI/strings.xml +++ b/auth/src/main/res/values-es-rNI/strings.xml @@ -190,4 +190,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-es-rPA/strings.xml b/auth/src/main/res/values-es-rPA/strings.xml index 9ebc9ee65..95195a514 100755 --- a/auth/src/main/res/values-es-rPA/strings.xml +++ b/auth/src/main/res/values-es-rPA/strings.xml @@ -190,4 +190,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-es-rPE/strings.xml b/auth/src/main/res/values-es-rPE/strings.xml index 9ebc9ee65..95195a514 100755 --- a/auth/src/main/res/values-es-rPE/strings.xml +++ b/auth/src/main/res/values-es-rPE/strings.xml @@ -190,4 +190,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-es-rPR/strings.xml b/auth/src/main/res/values-es-rPR/strings.xml index 9ebc9ee65..95195a514 100755 --- a/auth/src/main/res/values-es-rPR/strings.xml +++ b/auth/src/main/res/values-es-rPR/strings.xml @@ -190,4 +190,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-es-rPY/strings.xml b/auth/src/main/res/values-es-rPY/strings.xml index 9ebc9ee65..95195a514 100755 --- a/auth/src/main/res/values-es-rPY/strings.xml +++ b/auth/src/main/res/values-es-rPY/strings.xml @@ -190,4 +190,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-es-rSV/strings.xml b/auth/src/main/res/values-es-rSV/strings.xml index 9ebc9ee65..95195a514 100755 --- a/auth/src/main/res/values-es-rSV/strings.xml +++ b/auth/src/main/res/values-es-rSV/strings.xml @@ -190,4 +190,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-es-rUS/strings.xml b/auth/src/main/res/values-es-rUS/strings.xml index 9ebc9ee65..95195a514 100755 --- a/auth/src/main/res/values-es-rUS/strings.xml +++ b/auth/src/main/res/values-es-rUS/strings.xml @@ -190,4 +190,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-es-rUY/strings.xml b/auth/src/main/res/values-es-rUY/strings.xml index 9ebc9ee65..95195a514 100755 --- a/auth/src/main/res/values-es-rUY/strings.xml +++ b/auth/src/main/res/values-es-rUY/strings.xml @@ -190,4 +190,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-es-rVE/strings.xml b/auth/src/main/res/values-es-rVE/strings.xml index 9ebc9ee65..95195a514 100755 --- a/auth/src/main/res/values-es-rVE/strings.xml +++ b/auth/src/main/res/values-es-rVE/strings.xml @@ -190,4 +190,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-es/strings.xml b/auth/src/main/res/values-es/strings.xml index 5f8895314..ba0a84efe 100755 --- a/auth/src/main/res/values-es/strings.xml +++ b/auth/src/main/res/values-es/strings.xml @@ -197,4 +197,5 @@ This button is currently disabled because new accounts are not allowed + La autenticación multifactor está actualmente desactivada diff --git a/auth/src/main/res/values-fa/strings.xml b/auth/src/main/res/values-fa/strings.xml index 2215781c2..16f3338fc 100755 --- a/auth/src/main/res/values-fa/strings.xml +++ b/auth/src/main/res/values-fa/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + احراز هویت چند مرحله‌ای در حال حاضر غیرفعال است diff --git a/auth/src/main/res/values-fi/strings.xml b/auth/src/main/res/values-fi/strings.xml index 7c45770a8..9cfb2ce03 100755 --- a/auth/src/main/res/values-fi/strings.xml +++ b/auth/src/main/res/values-fi/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + Monivaiheinen todennus on tällä hetkellä poistettu käytöstä diff --git a/auth/src/main/res/values-fil/strings.xml b/auth/src/main/res/values-fil/strings.xml index fc2474b26..1db48118c 100755 --- a/auth/src/main/res/values-fil/strings.xml +++ b/auth/src/main/res/values-fil/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + Kasalukuyang naka-disable ang multi-factor authentication diff --git a/auth/src/main/res/values-fr-rCH/strings.xml b/auth/src/main/res/values-fr-rCH/strings.xml index dd6c99b1b..173450749 100755 --- a/auth/src/main/res/values-fr-rCH/strings.xml +++ b/auth/src/main/res/values-fr-rCH/strings.xml @@ -191,4 +191,5 @@ This button is currently disabled because new accounts are not allowed + L\'authentification multifacteur est actuellement désactivée diff --git a/auth/src/main/res/values-fr/strings.xml b/auth/src/main/res/values-fr/strings.xml index ceaf93d6e..d92ef24e1 100755 --- a/auth/src/main/res/values-fr/strings.xml +++ b/auth/src/main/res/values-fr/strings.xml @@ -197,4 +197,5 @@ This button is currently disabled because new accounts are not allowed + L\'authentification multifacteur est actuellement désactivée diff --git a/auth/src/main/res/values-gsw/strings.xml b/auth/src/main/res/values-gsw/strings.xml index 2b586c600..0b97606b8 100755 --- a/auth/src/main/res/values-gsw/strings.xml +++ b/auth/src/main/res/values-gsw/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + D\'Multi-Faktor-Authentifizierig isch zurziit deaktiviert diff --git a/auth/src/main/res/values-gu/strings.xml b/auth/src/main/res/values-gu/strings.xml index f331a75d3..d83ee4813 100755 --- a/auth/src/main/res/values-gu/strings.xml +++ b/auth/src/main/res/values-gu/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + મલ્ટિ-ફેક્ટર પ્રમાણીકરણ હાલમાં અક્ષમ છે diff --git a/auth/src/main/res/values-hi/strings.xml b/auth/src/main/res/values-hi/strings.xml index 847f6c169..53339be6e 100755 --- a/auth/src/main/res/values-hi/strings.xml +++ b/auth/src/main/res/values-hi/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + मल्टी-फैक्टर प्रमाणीकरण वर्तमान में अक्षम है diff --git a/auth/src/main/res/values-hr/strings.xml b/auth/src/main/res/values-hr/strings.xml index 4a481d5b3..e2516dfe0 100755 --- a/auth/src/main/res/values-hr/strings.xml +++ b/auth/src/main/res/values-hr/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + Višefaktorska autentifikacija trenutno je onemogućena diff --git a/auth/src/main/res/values-hu/strings.xml b/auth/src/main/res/values-hu/strings.xml index 6f8f96e28..e10f495b4 100755 --- a/auth/src/main/res/values-hu/strings.xml +++ b/auth/src/main/res/values-hu/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + A többfaktoros hitelesítés jelenleg le van tiltva diff --git a/auth/src/main/res/values-in/strings.xml b/auth/src/main/res/values-in/strings.xml index 5e125242a..cc6b13419 100755 --- a/auth/src/main/res/values-in/strings.xml +++ b/auth/src/main/res/values-in/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + Autentikasi multifaktor saat ini dinonaktifkan diff --git a/auth/src/main/res/values-it/strings.xml b/auth/src/main/res/values-it/strings.xml index dd6ab26a7..a0efdc6d3 100755 --- a/auth/src/main/res/values-it/strings.xml +++ b/auth/src/main/res/values-it/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + L\'autenticazione a più fattori è attualmente disabilitata diff --git a/auth/src/main/res/values-iw/strings.xml b/auth/src/main/res/values-iw/strings.xml index 712bfec7d..10f0db9c1 100755 --- a/auth/src/main/res/values-iw/strings.xml +++ b/auth/src/main/res/values-iw/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + אימות רב-גורמי מושבת כעת diff --git a/auth/src/main/res/values-ja/strings.xml b/auth/src/main/res/values-ja/strings.xml index dc900e2d8..620c2cb11 100755 --- a/auth/src/main/res/values-ja/strings.xml +++ b/auth/src/main/res/values-ja/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + 多要素認証は現在無効になっています diff --git a/auth/src/main/res/values-kn/strings.xml b/auth/src/main/res/values-kn/strings.xml index 31f780a6a..12f649a31 100755 --- a/auth/src/main/res/values-kn/strings.xml +++ b/auth/src/main/res/values-kn/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + ಮಲ್ಟಿ-ಫ್ಯಾಕ್ಟರ್ ದೃಢೀಕರಣವು ಪ್ರಸ್ತುತ ನಿಷ್ಕ್ರಿಯಗೊಂಡಿದೆ diff --git a/auth/src/main/res/values-ko/strings.xml b/auth/src/main/res/values-ko/strings.xml index eb6e1d22b..d829ffe62 100755 --- a/auth/src/main/res/values-ko/strings.xml +++ b/auth/src/main/res/values-ko/strings.xml @@ -178,4 +178,5 @@ This button is currently disabled because new accounts are not allowed + 다단계 인증이 현재 비활성화되어 있습니다 diff --git a/auth/src/main/res/values-ln/strings.xml b/auth/src/main/res/values-ln/strings.xml index 0ee345992..6304e1f10 100755 --- a/auth/src/main/res/values-ln/strings.xml +++ b/auth/src/main/res/values-ln/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + Bondimisami ya makambo mingi ezali sikoyo te diff --git a/auth/src/main/res/values-lt/strings.xml b/auth/src/main/res/values-lt/strings.xml index cef70d317..b08c4dbb1 100755 --- a/auth/src/main/res/values-lt/strings.xml +++ b/auth/src/main/res/values-lt/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + Daugiafaktoris tapatybės nustatymas šiuo metu išjungtas diff --git a/auth/src/main/res/values-lv/strings.xml b/auth/src/main/res/values-lv/strings.xml index fbba1e17a..21aa5fc1d 100755 --- a/auth/src/main/res/values-lv/strings.xml +++ b/auth/src/main/res/values-lv/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + Daudzfaktoru autentifikācija pašlaik ir atspējota diff --git a/auth/src/main/res/values-mo/strings.xml b/auth/src/main/res/values-mo/strings.xml index 73ac609a4..717eb65ca 100755 --- a/auth/src/main/res/values-mo/strings.xml +++ b/auth/src/main/res/values-mo/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + Autentificarea cu mai mulți factori este dezactivată în prezent diff --git a/auth/src/main/res/values-mr/strings.xml b/auth/src/main/res/values-mr/strings.xml index 00b6ee391..c95fef12a 100755 --- a/auth/src/main/res/values-mr/strings.xml +++ b/auth/src/main/res/values-mr/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + मल्टी-फॅक्टर ऑथेंटिकेशन सध्या अक्षम आहे diff --git a/auth/src/main/res/values-ms/strings.xml b/auth/src/main/res/values-ms/strings.xml index be8b30ccc..e35e22476 100755 --- a/auth/src/main/res/values-ms/strings.xml +++ b/auth/src/main/res/values-ms/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + Pengesahan berbilang faktor dilumpuhkan buat masa ini diff --git a/auth/src/main/res/values-nb/strings.xml b/auth/src/main/res/values-nb/strings.xml index 5cc9c83ac..5018c1952 100755 --- a/auth/src/main/res/values-nb/strings.xml +++ b/auth/src/main/res/values-nb/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + Flerfaktorautentisering er for øyeblikket deaktivert diff --git a/auth/src/main/res/values-nl/strings.xml b/auth/src/main/res/values-nl/strings.xml index 8d011cc4f..328497cf5 100755 --- a/auth/src/main/res/values-nl/strings.xml +++ b/auth/src/main/res/values-nl/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + Multi-factorauthenticatie is momenteel uitgeschakeld diff --git a/auth/src/main/res/values-no/strings.xml b/auth/src/main/res/values-no/strings.xml index 6afe11726..7833bccd9 100755 --- a/auth/src/main/res/values-no/strings.xml +++ b/auth/src/main/res/values-no/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + Flerfaktorautentisering er for øyeblikket deaktivert diff --git a/auth/src/main/res/values-pl/strings.xml b/auth/src/main/res/values-pl/strings.xml index 7fd45ad4e..9c4bcadbf 100755 --- a/auth/src/main/res/values-pl/strings.xml +++ b/auth/src/main/res/values-pl/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + Uwierzytelnianie wieloskładnikowe jest obecnie wyłączone diff --git a/auth/src/main/res/values-pt-rBR/strings.xml b/auth/src/main/res/values-pt-rBR/strings.xml index 7e805ba3e..f576f884c 100755 --- a/auth/src/main/res/values-pt-rBR/strings.xml +++ b/auth/src/main/res/values-pt-rBR/strings.xml @@ -198,4 +198,5 @@ This button is currently disabled because new accounts are not allowed + A autenticação multifator está atualmente desativada diff --git a/auth/src/main/res/values-pt-rPT/strings.xml b/auth/src/main/res/values-pt-rPT/strings.xml index 3844841bc..bc6c216d4 100755 --- a/auth/src/main/res/values-pt-rPT/strings.xml +++ b/auth/src/main/res/values-pt-rPT/strings.xml @@ -198,4 +198,5 @@ This button is currently disabled because new accounts are not allowed + A autenticação multifator está atualmente desativada diff --git a/auth/src/main/res/values-pt/strings.xml b/auth/src/main/res/values-pt/strings.xml index 54473de13..fbd9e7b37 100755 --- a/auth/src/main/res/values-pt/strings.xml +++ b/auth/src/main/res/values-pt/strings.xml @@ -197,4 +197,5 @@ This button is currently disabled because new accounts are not allowed + A autenticação multifator está atualmente desativada diff --git a/auth/src/main/res/values-ro/strings.xml b/auth/src/main/res/values-ro/strings.xml index c91b2199c..1b5b8cafb 100755 --- a/auth/src/main/res/values-ro/strings.xml +++ b/auth/src/main/res/values-ro/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + Autentificarea cu mai mulți factori este dezactivată în prezent diff --git a/auth/src/main/res/values-ru/strings.xml b/auth/src/main/res/values-ru/strings.xml index f41c29527..e2d654da9 100755 --- a/auth/src/main/res/values-ru/strings.xml +++ b/auth/src/main/res/values-ru/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + Многофакторная аутентификация в настоящее время отключена diff --git a/auth/src/main/res/values-sk/strings.xml b/auth/src/main/res/values-sk/strings.xml index 2643ea9d2..49c93e6e1 100755 --- a/auth/src/main/res/values-sk/strings.xml +++ b/auth/src/main/res/values-sk/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + Viacfaktorové overovanie je momentálne zakázané diff --git a/auth/src/main/res/values-sl/strings.xml b/auth/src/main/res/values-sl/strings.xml index 12c7fee84..be839d41b 100755 --- a/auth/src/main/res/values-sl/strings.xml +++ b/auth/src/main/res/values-sl/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + Večfaktorska avtentikacija je trenutno onemogočena diff --git a/auth/src/main/res/values-sr/strings.xml b/auth/src/main/res/values-sr/strings.xml index 666d446ad..be4fd78b2 100755 --- a/auth/src/main/res/values-sr/strings.xml +++ b/auth/src/main/res/values-sr/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + Вишефакторска аутентификација је тренутно онемогућена diff --git a/auth/src/main/res/values-sv/strings.xml b/auth/src/main/res/values-sv/strings.xml index 79c33bf9d..616d43dd2 100755 --- a/auth/src/main/res/values-sv/strings.xml +++ b/auth/src/main/res/values-sv/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + Multifaktorautentisering är för närvarande inaktiverad diff --git a/auth/src/main/res/values-ta/strings.xml b/auth/src/main/res/values-ta/strings.xml index a01ca8e42..378ced01f 100755 --- a/auth/src/main/res/values-ta/strings.xml +++ b/auth/src/main/res/values-ta/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + பல-காரணி அங்கீகாரம் தற்போது முடக்கப்பட்டுள்ளது diff --git a/auth/src/main/res/values-th/strings.xml b/auth/src/main/res/values-th/strings.xml index 9dc12174b..859b5fc36 100755 --- a/auth/src/main/res/values-th/strings.xml +++ b/auth/src/main/res/values-th/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + การรับรองความถูกต้องแบบหลายปัจจัยถูกปิดใช้งานในขณะนี้ diff --git a/auth/src/main/res/values-tl/strings.xml b/auth/src/main/res/values-tl/strings.xml index bcafcca5e..e5f5b11e5 100755 --- a/auth/src/main/res/values-tl/strings.xml +++ b/auth/src/main/res/values-tl/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + Kasalukuyang naka-disable ang multi-factor authentication diff --git a/auth/src/main/res/values-tr/strings.xml b/auth/src/main/res/values-tr/strings.xml index 59b2ba45b..7885d361e 100755 --- a/auth/src/main/res/values-tr/strings.xml +++ b/auth/src/main/res/values-tr/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + Çok faktörlü kimlik doğrulama şu anda devre dışı diff --git a/auth/src/main/res/values-uk/strings.xml b/auth/src/main/res/values-uk/strings.xml index 2361de7c4..5c99137d3 100755 --- a/auth/src/main/res/values-uk/strings.xml +++ b/auth/src/main/res/values-uk/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + Багатофакторна автентифікація наразі вимкнена diff --git a/auth/src/main/res/values-ur/strings.xml b/auth/src/main/res/values-ur/strings.xml index 9e4268e6c..f73956b29 100755 --- a/auth/src/main/res/values-ur/strings.xml +++ b/auth/src/main/res/values-ur/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + ملٹی فیکٹر تصدیق فی الحال غیر فعال ہے diff --git a/auth/src/main/res/values-vi/strings.xml b/auth/src/main/res/values-vi/strings.xml index f67c4b703..e77e08e6d 100755 --- a/auth/src/main/res/values-vi/strings.xml +++ b/auth/src/main/res/values-vi/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + Xác thực đa yếu tố hiện đang bị vô hiệu hóa diff --git a/auth/src/main/res/values-zh-rCN/strings.xml b/auth/src/main/res/values-zh-rCN/strings.xml index 64f584490..a4b5e61ff 100755 --- a/auth/src/main/res/values-zh-rCN/strings.xml +++ b/auth/src/main/res/values-zh-rCN/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + 多重身份验证当前已禁用 diff --git a/auth/src/main/res/values-zh-rHK/strings.xml b/auth/src/main/res/values-zh-rHK/strings.xml index a2b6f9530..f002ae7b6 100755 --- a/auth/src/main/res/values-zh-rHK/strings.xml +++ b/auth/src/main/res/values-zh-rHK/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + 多重身份验证当前已禁用 diff --git a/auth/src/main/res/values-zh-rTW/strings.xml b/auth/src/main/res/values-zh-rTW/strings.xml index 97939b4c9..094052f93 100755 --- a/auth/src/main/res/values-zh-rTW/strings.xml +++ b/auth/src/main/res/values-zh-rTW/strings.xml @@ -180,4 +180,5 @@ This button is currently disabled because new accounts are not allowed + 多重身份验证当前已禁用 diff --git a/auth/src/main/res/values-zh/strings.xml b/auth/src/main/res/values-zh/strings.xml index a845558c9..55f8cb92b 100755 --- a/auth/src/main/res/values-zh/strings.xml +++ b/auth/src/main/res/values-zh/strings.xml @@ -179,4 +179,5 @@ This button is currently disabled because new accounts are not allowed + 多重身份验证当前已禁用 diff --git a/auth/src/main/res/values/strings.xml b/auth/src/main/res/values/strings.xml index ee88a98a5..bb4b4e813 100644 --- a/auth/src/main/res/values/strings.xml +++ b/auth/src/main/res/values/strings.xml @@ -249,4 +249,5 @@ This button is currently disabled because new accounts are not allowed + Multi-factor authentication is currently disabled diff --git a/auth/src/test/java/com/firebase/ui/auth/configuration/AuthUIConfigurationTest.kt b/auth/src/test/java/com/firebase/ui/auth/configuration/AuthUIConfigurationTest.kt index 80cf85ad6..4afcfa84b 100644 --- a/auth/src/test/java/com/firebase/ui/auth/configuration/AuthUIConfigurationTest.kt +++ b/auth/src/test/java/com/firebase/ui/auth/configuration/AuthUIConfigurationTest.kt @@ -294,12 +294,13 @@ class AuthUIConfigurationTest { } @Test + @Config(manifest = Config.NONE, qualifiers = "night") fun `validation accepts all supported providers`() { val config = authUIConfiguration { context = applicationContext providers { provider(AuthProvider.Google(scopes = listOf(), serverClientId = "test_client_id")) - provider(AuthProvider.Facebook(applicationId = "test_app_id")) + provider(AuthProvider.Facebook()) provider(AuthProvider.Twitter(customParameters = mapOf())) provider(AuthProvider.Github(customParameters = mapOf())) provider(AuthProvider.Microsoft(customParameters = mapOf(), tenant = null)) diff --git a/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/AuthProviderTest.kt b/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/AuthProviderTest.kt index f64bfc2a6..718d38ad3 100644 --- a/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/AuthProviderTest.kt +++ b/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/AuthProviderTest.kt @@ -2,6 +2,7 @@ package com.firebase.ui.auth.configuration.auth_provider import android.content.Context import androidx.test.core.app.ApplicationProvider +import com.firebase.ui.auth.R import com.google.common.truth.Truth.assertThat import com.google.firebase.auth.actionCodeSettings import org.junit.Before @@ -264,32 +265,34 @@ class AuthProviderTest { } } + @Test + @Config(manifest = Config.NONE, qualifiers = "night") + fun `google provider assigns default_web_client_id to serverClientId when null`() { + val provider = AuthProvider.Google( + scopes = listOf("email"), + serverClientId = null + ) + + provider.validate(applicationContext) + + assertThat(provider.serverClientId) + .isEqualTo(applicationContext.getString(R.string.default_web_client_id)) + } + // ============================================================================================= // Facebook Provider Tests // ============================================================================================= @Test + @Config(manifest = Config.NONE, qualifiers = "night") fun `facebook provider with valid configuration should succeed`() { - val provider = AuthProvider.Facebook(applicationId = "application_id") + val provider = AuthProvider.Facebook() provider.validate(applicationContext) } @Test - fun `facebook provider with empty application id throws`() { - val provider = AuthProvider.Facebook(applicationId = "") - - try { - provider.validate(applicationContext) - assertThat(false).isTrue() // Should not reach here - } catch (e: Exception) { - assertThat(e).isInstanceOf(IllegalArgumentException::class.java) - assertThat(e.message).isEqualTo("Facebook application ID cannot be blank") - } - } - - @Test - fun `facebook provider validates facebook_application_id when applicationId is null`() { + fun `facebook provider validates facebook_application_id`() { val provider = AuthProvider.Facebook() try { @@ -299,7 +302,7 @@ class AuthProviderTest { assertThat(e).isInstanceOf(IllegalStateException::class.java) assertThat(e.message).isEqualTo( "Facebook provider unconfigured. Make sure to " + - "add a `facebook_application_id` string or provide applicationId parameter." + "add a `facebook_application_id` string to your strings.xml" ) } } @@ -400,4 +403,4 @@ class AuthProviderTest { assertThat(e.message).isEqualTo("Button label cannot be null or empty") } } -} \ No newline at end of file +} diff --git a/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/FacebookAuthProviderFirebaseAuthUI.kt b/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/FacebookAuthProviderFirebaseAuthUI.kt index 155de1f82..1e48bae90 100644 --- a/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/FacebookAuthProviderFirebaseAuthUI.kt +++ b/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/FacebookAuthProviderFirebaseAuthUI.kt @@ -103,6 +103,7 @@ class FacebookAuthProviderFirebaseAuthUITest { } @Test + @Config(manifest = Config.NONE, qualifiers = "night") fun `signInWithFacebook - successful sign in signs user in and emits Success authState`() = runTest { val authStateListeners = mutableListOf() doAnswer { invocation -> @@ -118,9 +119,7 @@ class FacebookAuthProviderFirebaseAuthUITest { whenever(mockFirebaseAuth.currentUser).thenReturn(null) val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth) - val provider = spy(AuthProvider.Facebook( - applicationId = "000000000000" - )) + val provider = spy(AuthProvider.Facebook()) val config = authUIConfiguration { context = applicationContext providers { @@ -175,6 +174,7 @@ class FacebookAuthProviderFirebaseAuthUITest { } @Test + @Config(manifest = Config.NONE, qualifiers = "night") fun `signInWithFacebook - handles account collision by saving credential and emitting error`() = runTest { EmailLinkPersistenceManager.default.clear(applicationContext) EmailLinkPersistenceManager.default.saveEmail( @@ -185,9 +185,7 @@ class FacebookAuthProviderFirebaseAuthUITest { ) val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth) - val provider = spy(AuthProvider.Facebook( - applicationId = "000000000000" - )) + val provider = spy(AuthProvider.Facebook()) val config = authUIConfiguration { context = applicationContext providers { @@ -238,11 +236,10 @@ class FacebookAuthProviderFirebaseAuthUITest { } @Test + @Config(manifest = Config.NONE, qualifiers = "night") fun `signInWithFacebook - converts FacebookException into AuthException`() = runTest { val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth) - val provider = spy(AuthProvider.Facebook( - applicationId = "000000000000" - )) + val provider = spy(AuthProvider.Facebook()) val config = authUIConfiguration { context = applicationContext providers { diff --git a/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProviderFirebaseAuthUITest.kt b/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProviderFirebaseAuthUITest.kt index 9091e7d7c..2fd855c37 100644 --- a/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProviderFirebaseAuthUITest.kt +++ b/auth/src/test/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProviderFirebaseAuthUITest.kt @@ -602,6 +602,200 @@ class GoogleAuthProviderFirebaseAuthUITest { verify(mockFirebaseAuth, never()).signInWithCredential(any()) } + // ============================================================================================= + // signInWithGoogle - Configuration Properties + // ============================================================================================= + + @Test + fun `Sign in with Google with default settings passes filterByAuthorizedAccounts=true`() = runTest { + val mockCredential = mock(AuthCredential::class.java) + val mockUser = mock(FirebaseUser::class.java) + val mockAuthResult = mock(AuthResult::class.java) + `when`(mockAuthResult.user).thenReturn(mockUser) + + val googleSignInResult = AuthProvider.Google.GoogleSignInResult( + credential = mockCredential, + idToken = "test-id-token", + displayName = "Test User", + photoUrl = null + ) + + `when`( + mockCredentialManagerProvider.getGoogleCredential( + context = eq(applicationContext), + credentialManager = any(), + serverClientId = eq("test-client-id"), + filterByAuthorizedAccounts = eq(true), + autoSelectEnabled = eq(false) + ) + ).thenReturn(googleSignInResult) + + val taskCompletionSource = TaskCompletionSource() + taskCompletionSource.setResult(mockAuthResult) + `when`(mockFirebaseAuth.signInWithCredential(mockCredential)) + .thenReturn(taskCompletionSource.task) + `when`(mockFirebaseAuth.currentUser).thenReturn(null) + + val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth) + val googleProvider = AuthProvider.Google( + serverClientId = "test-client-id", + scopes = emptyList() + // filterByAuthorizedAccounts defaults to true + // autoSelectEnabled defaults to false + ) + val config = authUIConfiguration { + context = applicationContext + providers { + provider(googleProvider) + } + } + + instance.signInWithGoogle( + context = applicationContext, + config = config, + provider = googleProvider, + authorizationProvider = mockAuthorizationProvider, + credentialManagerProvider = mockCredentialManagerProvider + ) + + // Verify correct parameters were passed + verify(mockCredentialManagerProvider).getGoogleCredential( + context = eq(applicationContext), + credentialManager = any(), + serverClientId = eq("test-client-id"), + filterByAuthorizedAccounts = eq(true), + autoSelectEnabled = eq(false) + ) + + verify(mockFirebaseAuth).signInWithCredential(mockCredential) + } + + @Test + fun `Sign in with Google with filterByAuthorizedAccounts=false passes correct parameter`() = runTest { + val mockCredential = mock(AuthCredential::class.java) + val mockUser = mock(FirebaseUser::class.java) + val mockAuthResult = mock(AuthResult::class.java) + `when`(mockAuthResult.user).thenReturn(mockUser) + + val googleSignInResult = AuthProvider.Google.GoogleSignInResult( + credential = mockCredential, + idToken = "test-id-token", + displayName = "Test User", + photoUrl = null + ) + + `when`( + mockCredentialManagerProvider.getGoogleCredential( + context = eq(applicationContext), + credentialManager = any(), + serverClientId = eq("test-client-id"), + filterByAuthorizedAccounts = eq(false), + autoSelectEnabled = eq(false) + ) + ).thenReturn(googleSignInResult) + + val taskCompletionSource = TaskCompletionSource() + taskCompletionSource.setResult(mockAuthResult) + `when`(mockFirebaseAuth.signInWithCredential(mockCredential)) + .thenReturn(taskCompletionSource.task) + `when`(mockFirebaseAuth.currentUser).thenReturn(null) + + val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth) + val googleProvider = AuthProvider.Google( + serverClientId = "test-client-id", + scopes = emptyList(), + filterByAuthorizedAccounts = false + ) + val config = authUIConfiguration { + context = applicationContext + providers { + provider(googleProvider) + } + } + + instance.signInWithGoogle( + context = applicationContext, + config = config, + provider = googleProvider, + authorizationProvider = mockAuthorizationProvider, + credentialManagerProvider = mockCredentialManagerProvider + ) + + // Verify filterByAuthorizedAccounts=false was passed + verify(mockCredentialManagerProvider).getGoogleCredential( + context = eq(applicationContext), + credentialManager = any(), + serverClientId = eq("test-client-id"), + filterByAuthorizedAccounts = eq(false), + autoSelectEnabled = eq(false) + ) + + verify(mockFirebaseAuth).signInWithCredential(mockCredential) + } + + @Test + fun `Sign in with Google with autoSelectEnabled=true passes correct parameter`() = runTest { + val mockCredential = mock(AuthCredential::class.java) + val mockUser = mock(FirebaseUser::class.java) + val mockAuthResult = mock(AuthResult::class.java) + `when`(mockAuthResult.user).thenReturn(mockUser) + + val googleSignInResult = AuthProvider.Google.GoogleSignInResult( + credential = mockCredential, + idToken = "test-id-token", + displayName = "Test User", + photoUrl = null + ) + + `when`( + mockCredentialManagerProvider.getGoogleCredential( + context = eq(applicationContext), + credentialManager = any(), + serverClientId = eq("test-client-id"), + filterByAuthorizedAccounts = eq(true), + autoSelectEnabled = eq(true) + ) + ).thenReturn(googleSignInResult) + + val taskCompletionSource = TaskCompletionSource() + taskCompletionSource.setResult(mockAuthResult) + `when`(mockFirebaseAuth.signInWithCredential(mockCredential)) + .thenReturn(taskCompletionSource.task) + `when`(mockFirebaseAuth.currentUser).thenReturn(null) + + val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth) + val googleProvider = AuthProvider.Google( + serverClientId = "test-client-id", + scopes = emptyList(), + autoSelectEnabled = true + ) + val config = authUIConfiguration { + context = applicationContext + providers { + provider(googleProvider) + } + } + + instance.signInWithGoogle( + context = applicationContext, + config = config, + provider = googleProvider, + authorizationProvider = mockAuthorizationProvider, + credentialManagerProvider = mockCredentialManagerProvider + ) + + // Verify autoSelectEnabled=true was passed + verify(mockCredentialManagerProvider).getGoogleCredential( + context = eq(applicationContext), + credentialManager = any(), + serverClientId = eq("test-client-id"), + filterByAuthorizedAccounts = eq(true), + autoSelectEnabled = eq(true) + ) + + verify(mockFirebaseAuth).signInWithCredential(mockCredential) + } + // ============================================================================================= // signInWithGoogle - State Management // ============================================================================================= diff --git a/auth/src/test/res/values-night/config.xml b/auth/src/test/res/values-night/config.xml new file mode 100644 index 000000000..0b31fe015 --- /dev/null +++ b/auth/src/test/res/values-night/config.xml @@ -0,0 +1,7 @@ + + + test_client_id + test_app_id + test_login_scheme + test_client_token + diff --git a/e2eTest/src/test/java/com/firebase/ui/auth/ui/screens/MfaDisabledTest.kt b/e2eTest/src/test/java/com/firebase/ui/auth/ui/screens/MfaDisabledTest.kt new file mode 100644 index 000000000..307f79bc6 --- /dev/null +++ b/e2eTest/src/test/java/com/firebase/ui/auth/ui/screens/MfaDisabledTest.kt @@ -0,0 +1,229 @@ +package com.firebase.ui.auth.ui.screens + +import android.content.Context +import android.os.Looper +import androidx.compose.material3.Text +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.assertIsNotEnabled +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.test.core.app.ApplicationProvider +import com.firebase.ui.auth.AuthException +import com.firebase.ui.auth.AuthState +import com.firebase.ui.auth.FirebaseAuthUI +import com.firebase.ui.auth.configuration.authUIConfiguration +import com.firebase.ui.auth.configuration.auth_provider.AuthProvider +import com.firebase.ui.auth.configuration.string_provider.AuthUIStringProvider +import com.firebase.ui.auth.configuration.string_provider.DefaultAuthUIStringProvider +import com.firebase.ui.auth.testutil.AUTH_STATE_WAIT_TIMEOUT_MS +import com.firebase.ui.auth.testutil.EmulatorAuthApi +import com.google.common.truth.Truth.assertThat +import com.google.firebase.FirebaseApp +import com.google.firebase.FirebaseOptions +import org.junit.After +import org.junit.Before +import org.junit.Ignore +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.MockitoAnnotations +import org.robolectric.RobolectricTestRunner +import org.robolectric.Shadows.shadowOf +import org.robolectric.annotation.Config + +/** + * E2E tests for MFA disabled functionality. + * + * Tests that when isMfaEnabled is false, the Manage MFA button is disabled + * and attempting to access MFA enrollment shows an AuthCancelledException. + */ +@Config(sdk = [34]) +@RunWith(RobolectricTestRunner::class) +class MfaDisabledTest { + @get:Rule + val composeTestRule = createComposeRule() + + private lateinit var applicationContext: Context + private lateinit var stringProvider: AuthUIStringProvider + private lateinit var authUI: FirebaseAuthUI + private lateinit var emulatorApi: EmulatorAuthApi + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + + applicationContext = ApplicationProvider.getApplicationContext() + stringProvider = DefaultAuthUIStringProvider(applicationContext) + + // Clear any existing Firebase apps + FirebaseApp.getApps(applicationContext).forEach { app -> + app.delete() + } + + // Initialize default FirebaseApp + val firebaseApp = FirebaseApp.initializeApp( + applicationContext, + FirebaseOptions.Builder() + .setApiKey("fake-api-key") + .setApplicationId("fake-app-id") + .setProjectId("fake-project-id") + .build() + ) + + authUI = FirebaseAuthUI.getInstance() + authUI.auth.useEmulator("127.0.0.1", 9099) + + emulatorApi = EmulatorAuthApi( + projectId = firebaseApp.options.projectId + ?: throw IllegalStateException("Project ID is required for emulator interactions"), + emulatorHost = "127.0.0.1", + emulatorPort = 9099 + ) + + // Clear emulator data + emulatorApi.clearEmulatorData() + } + + @After + fun tearDown() { + // Clean up after each test to prevent test pollution + FirebaseAuthUI.clearInstanceCache() + + // Clear emulator data + emulatorApi.clearEmulatorData() + } + + @Test + fun `Manage MFA button is disabled when isMfaEnabled is false`() { + val configuration = authUIConfiguration { + context = applicationContext + isMfaEnabled = false // MFA disabled + providers { + provider(AuthProvider.Anonymous) + provider( + AuthProvider.Email( + emailLinkActionCodeSettings = null, + passwordValidationRules = emptyList() + ) + ) + } + } + + var currentAuthState: AuthState = AuthState.Idle + + composeTestRule.setContent { + FirebaseAuthScreen( + authUI = authUI, + configuration = configuration, + onSignInSuccess = {}, + onSignInFailure = {}, + onSignInCancelled = {} + ) + val authState by authUI.authStateFlow().collectAsState(AuthState.Idle) + currentAuthState = authState + } + + // Wait for the navigation to settle and UI to be ready + composeTestRule.waitForIdle() + shadowOf(Looper.getMainLooper()).idle() + + // Sign in anonymously to get to the success screen + composeTestRule.onNodeWithText(stringProvider.signInAnonymously) + .assertIsDisplayed () + .performClick() + composeTestRule.waitForIdle() + shadowOf(Looper.getMainLooper()).idle() + + // Wait for auth state to transition to Success + composeTestRule.waitUntil(timeoutMillis = AUTH_STATE_WAIT_TIMEOUT_MS) { + shadowOf(Looper.getMainLooper()).idle() + currentAuthState is AuthState.Success + } + + // Wait for UI to update + composeTestRule.waitForIdle() + shadowOf(Looper.getMainLooper()).idle() + + // Verify the Manage MFA button is displayed but disabled + composeTestRule.onNodeWithText(stringProvider.manageMfaAction) + .assertIsDisplayed() + .assertIsNotEnabled() + } + + @Test + @Ignore("Flaky in CI due to timing issues") + fun `onManageMfa throws AuthCancelledException when MFA is disabled`() { + val configuration = authUIConfiguration { + context = applicationContext + isMfaEnabled = false // MFA disabled + providers { + provider(AuthProvider.Anonymous) + provider( + AuthProvider.Email( + emailLinkActionCodeSettings = null, + passwordValidationRules = emptyList() + ) + ) + } + } + + var currentAuthState: AuthState = AuthState.Idle + var capturedUiContext: AuthSuccessUiContext? = null + + composeTestRule.setContent { + FirebaseAuthScreen( + authUI = authUI, + configuration = configuration, + onSignInSuccess = {}, + onSignInFailure = {}, + onSignInCancelled = {}, + authenticatedContent = { _, uiContext -> + // Custom content that captures the uiContext + capturedUiContext = uiContext + Text("Custom authenticated content") + } + ) + val authState by authUI.authStateFlow().collectAsState(AuthState.Idle) + currentAuthState = authState + } + + // Wait for the navigation to settle and UI to be ready + composeTestRule.waitForIdle() + shadowOf(Looper.getMainLooper()).idle() + + // Sign in anonymously to get to the success screen + composeTestRule.onNodeWithText(stringProvider.signInAnonymously) + .assertIsDisplayed() + .performClick() + composeTestRule.waitForIdle() + shadowOf(Looper.getMainLooper()).idle() + + // Wait for auth state to transition to Success + composeTestRule.waitUntil(timeoutMillis = AUTH_STATE_WAIT_TIMEOUT_MS) { + shadowOf(Looper.getMainLooper()).idle() + currentAuthState is AuthState.Success + } + + // Now call onManageMfa directly (simulating custom content calling it) + assertThat(capturedUiContext).isNotNull() + capturedUiContext?.onManageMfa?.invoke() + + // Wait for auth state to update + composeTestRule.waitForIdle() + shadowOf(Looper.getMainLooper()).idle() + + // Verify that auth state is now Error with AuthCancelledException + composeTestRule.waitUntil(timeoutMillis = AUTH_STATE_WAIT_TIMEOUT_MS) { + shadowOf(Looper.getMainLooper()).idle() + currentAuthState is AuthState.Error && + (currentAuthState as AuthState.Error).exception is AuthException.AuthCancelledException + } + + val errorState = currentAuthState as AuthState.Error + assertThat(errorState.exception).isInstanceOf(AuthException.AuthCancelledException::class.java) + assertThat(errorState.exception.message).contains("Multi-factor authentication is disabled") + } +}