diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/util/TwoFactorRequiredExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/util/TwoFactorRequiredExtensions.kt index 3a923de94..3ed674c34 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/util/TwoFactorRequiredExtensions.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/util/TwoFactorRequiredExtensions.kt @@ -32,14 +32,13 @@ val GetTokenResponseJson.TwoFactorRequired?.preferredAuthMethod: TwoFactorAuthMe /** * If it exists, return the value of the Duo auth url. */ -val GetTokenResponseJson.TwoFactorRequired?.twoFactorDuoAuthUrl: String +val GetTokenResponseJson.TwoFactorRequired?.twoFactorDuoAuthUrl: String? get() = this ?.authMethodsData ?.duo ?.get("AuthUrl") ?.jsonPrimitive ?.contentOrNull - .orEmpty() /** * If it exists, return the value to display for the email used with two-factor authentication. diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/auth/feature/twofactorlogin/TwoFactorLoginViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/auth/feature/twofactorlogin/TwoFactorLoginViewModel.kt index cf4441883..6ffbcfd9d 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/auth/feature/twofactorlogin/TwoFactorLoginViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/auth/feature/twofactorlogin/TwoFactorLoginViewModel.kt @@ -160,10 +160,19 @@ class TwoFactorLoginViewModel @Inject constructor( */ private fun handleContinueButtonClick() { if (state.authMethod.isDuo) { + val authUrl = authRepository.twoFactorResponse.twoFactorDuoAuthUrl + // The url should not be empty unless the environment is somehow not supported. sendEvent( - event = TwoFactorLoginEvent.NavigateToDuo( - uri = Uri.parse(authRepository.twoFactorResponse.twoFactorDuoAuthUrl), - ), + event = authUrl + ?.let { + TwoFactorLoginEvent.NavigateToDuo( + uri = Uri.parse(it), + ) + } + ?: TwoFactorLoginEvent.ShowToast( + // TODO BIT-1927 Update to use string resource + message = "Duo not yet supported".asText(), + ), ) } else { initiateLogin() diff --git a/app/src/test/java/com/x8bit/bitwarden/data/auth/datasource/network/util/TwoFactorRequiredExtensionTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/auth/datasource/network/util/TwoFactorRequiredExtensionTest.kt index 092bfccc1..a225ec565 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/auth/datasource/network/util/TwoFactorRequiredExtensionTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/auth/datasource/network/util/TwoFactorRequiredExtensionTest.kt @@ -6,6 +6,7 @@ import kotlinx.serialization.json.JsonNull import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNull import org.junit.jupiter.api.Test class TwoFactorRequiredExtensionTest { @@ -62,7 +63,7 @@ class TwoFactorRequiredExtensionTest { } @Test - fun `twoFactorDuoAuthUrl returns empty string when no DUO AuthUrl is present`() { + fun `twoFactorDuoAuthUrl returns null when no DUO AuthUrl is present`() { val subject = GetTokenResponseJson.TwoFactorRequired( authMethodsData = mapOf( TwoFactorAuthMethod.AUTHENTICATOR_APP to JsonObject(mapOf("AuthUrl" to JsonNull)), @@ -70,7 +71,7 @@ class TwoFactorRequiredExtensionTest { captchaToken = null, ssoToken = null, ) - assertEquals("", subject.twoFactorDuoAuthUrl) + assertNull(subject.twoFactorDuoAuthUrl) } @Test diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/twofactorlogin/TwoFactorLoginViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/twofactorlogin/TwoFactorLoginViewModelTest.kt index cdebb126e..41ecfb897 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/twofactorlogin/TwoFactorLoginViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/twofactorlogin/TwoFactorLoginViewModelTest.kt @@ -249,8 +249,9 @@ class TwoFactorLoginViewModelTest : BaseViewModelTest() { } } + @Suppress("MaxLineLength") @Test - fun `ContinueButtonClick login should emit NavigateToDuo when auth method is Duo`() = runTest { + fun `ContinueButtonClick login should emit NavigateToDuo when auth method is Duo and authUrl is non-null`() = runTest { val authMethodsData = mapOf( TwoFactorAuthMethod.DUO to JsonObject( mapOf("AuthUrl" to JsonPrimitive("bitwarden.com")), @@ -281,6 +282,35 @@ class TwoFactorLoginViewModelTest : BaseViewModelTest() { } } + @Suppress("MaxLineLength") + @Test + fun `ContinueButtonClick login should emit ShowToast when auth method is Duo and authUrl is null`() = runTest { + val authMethodsData = mapOf( + TwoFactorAuthMethod.DUO to JsonObject( + mapOf("Nothing" to JsonPrimitive("Nothing")), + ), + ) + val response = GetTokenResponseJson.TwoFactorRequired( + authMethodsData = authMethodsData, + captchaToken = null, + ssoToken = null, + ) + every { authRepository.twoFactorResponse } returns response + val mockkUri = mockk() + val viewModel = createViewModel( + state = DEFAULT_STATE.copy( + authMethod = TwoFactorAuthMethod.DUO, + ), + ) + viewModel.eventFlow.test { + viewModel.actionChannel.trySend(TwoFactorLoginAction.ContinueButtonClick) + assertEquals( + TwoFactorLoginEvent.ShowToast("Duo not yet supported".asText()), + awaitItem(), + ) + } + } + @Test fun `ContinueButtonClick login returns CaptchaRequired should emit NavigateToCaptcha`() = runTest {