diff --git a/app/src/main/kotlin/com/wire/android/ui/authentication/login/LoginScreen.kt b/app/src/main/kotlin/com/wire/android/ui/authentication/login/LoginScreen.kt index 3c5e63e03c8..bc620fa6d00 100644 --- a/app/src/main/kotlin/com/wire/android/ui/authentication/login/LoginScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/authentication/login/LoginScreen.kt @@ -307,13 +307,22 @@ fun LoginErrorDialog( dismissOnClickOutside = false ) - LoginState.Error.DialogError.PasswordNeededToRegisterClient -> TODO() - - else -> LoginDialogErrorData( - title = stringResource(R.string.error_unknown_title), - body = AnnotatedString(stringResource(R.string.error_unknown_message)), - onDismiss = onDialogDismiss - ) + LoginState.Error.DialogError.Request2FAWithHandle -> { + LoginDialogErrorData( + title = stringResource(R.string.login_error_request_2fa_with_handle_title), + body = AnnotatedString(stringResource(R.string.login_error_request_2fa_with_handle_message)), + onDismiss = onDialogDismiss + ) + } + LoginState.Error.TextFieldError.InvalidValue, + LoginState.Error.DialogError.PasswordNeededToRegisterClient, + LoginState.Error.TooManyDevicesError -> { + LoginDialogErrorData( + title = stringResource(R.string.error_unknown_title), + body = AnnotatedString(stringResource(R.string.error_unknown_message)), + onDismiss = onDialogDismiss + ) + } } WireDialog( diff --git a/app/src/main/kotlin/com/wire/android/ui/authentication/login/LoginState.kt b/app/src/main/kotlin/com/wire/android/ui/authentication/login/LoginState.kt index a96243cccce..15658002e13 100644 --- a/app/src/main/kotlin/com/wire/android/ui/authentication/login/LoginState.kt +++ b/app/src/main/kotlin/com/wire/android/ui/authentication/login/LoginState.kt @@ -37,6 +37,7 @@ sealed class LoginState { data object InvalidSSOCodeError : DialogError() data object UserAlreadyExists : DialogError() data object PasswordNeededToRegisterClient : DialogError() + data object Request2FAWithHandle : DialogError() data class SSOResultError(val result: SSOFailureCodes) : DialogError() data object ServerVersionNotSupported : DialogError() diff --git a/app/src/main/kotlin/com/wire/android/ui/authentication/login/email/LoginEmailViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/authentication/login/email/LoginEmailViewModel.kt index eedd8a7b86b..e4c1e6251b3 100644 --- a/app/src/main/kotlin/com/wire/android/ui/authentication/login/email/LoginEmailViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/authentication/login/email/LoginEmailViewModel.kt @@ -246,7 +246,14 @@ class LoginEmailViewModel @Inject constructor( } private suspend fun request2FACode(authScope: AuthenticationScope) { - val email = userIdentifierTextState.text.trim().toString() + val email = userIdentifierTextState.text.trim().toString().also { + // user is using handle to login when 2FA is required + if (!it.contains("@")) { + updateEmailFlowState(LoginState.Error.DialogError.Request2FAWithHandle) + return + } + } + val result = authScope.requestSecondFactorVerificationCode( email = email, verifiableAction = VerifiableAction.LOGIN_OR_CLIENT_REGISTRATION diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9309f671a99..54e810dbe7e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -369,6 +369,8 @@ SSO CODE OR EMAIL Please enter a valid SSO code. Enter a valid SSO code + Login with email + You can\'t use your username as two-factor authentication is activated. Please log in with your email instead. Deleted account You were logged out because your account was deleted. @@ -1637,5 +1639,4 @@ In group conversations, the group admin can overwrite this setting. You\'ve created or joined a team with this email address on another device. Wire could not complete your team creation due to a slow internet connection. Wire could not complete your team creation due to an unknown error. - diff --git a/app/src/test/kotlin/com/wire/android/ui/authentication/login/email/LoginEmailViewModelTest.kt b/app/src/test/kotlin/com/wire/android/ui/authentication/login/email/LoginEmailViewModelTest.kt index 2e79269e277..9c63b46196b 100644 --- a/app/src/test/kotlin/com/wire/android/ui/authentication/login/email/LoginEmailViewModelTest.kt +++ b/app/src/test/kotlin/com/wire/android/ui/authentication/login/email/LoginEmailViewModelTest.kt @@ -65,6 +65,7 @@ import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest +import org.amshove.kluent.internal.assertEquals import org.amshove.kluent.shouldBe import org.amshove.kluent.shouldBeEqualTo import org.amshove.kluent.shouldBeInstanceOf @@ -490,6 +491,19 @@ class LoginEmailViewModelTest { advanceUntilIdle() coVerify(exactly = 1) { getOrRegisterClientUseCase(match { it.secondFactorVerificationCode == null }) } } + @Test + fun `given 2fa is needed, when user used handle to login, then show correct error message` () = runTest { + val email = "some.handle" + val code = "123456" + coEvery { loginUseCase(any(), any(), any(), any(), any()) } returns AuthenticationResult.Failure.InvalidCredentials.Missing2FA + + loginViewModel.userIdentifierTextState.setTextAndPlaceCursorAtEnd(email) + loginViewModel.secondFactorVerificationCodeTextState.setTextAndPlaceCursorAtEnd(code) + advanceUntilIdle() + coVerify(exactly = 0) { addAuthenticatedUserUseCase(any(), any(), any(), any()) } + coVerify(exactly = 0) { getOrRegisterClientUseCase(any()) } + assertEquals(LoginState.Error.DialogError.Request2FAWithHandle, loginViewModel.loginState.flowState) + } companion object { val CLIENT = TestClient.CLIENT