BIT-2246: Update link for recovery code process (#1303)

This commit is contained in:
Ramsey Smith
2024-04-24 15:37:53 -06:00
committed by Álison Fernandes
parent 86bf2d0877
commit a80f903df0
4 changed files with 40 additions and 8 deletions

View File

@@ -32,7 +32,6 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.net.toUri
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -97,8 +96,8 @@ fun TwoFactorLoginScreen(
when (event) { when (event) {
TwoFactorLoginEvent.NavigateBack -> onNavigateBack() TwoFactorLoginEvent.NavigateBack -> onNavigateBack()
TwoFactorLoginEvent.NavigateToRecoveryCode -> { is TwoFactorLoginEvent.NavigateToRecoveryCode -> {
intentManager.launchUri("https://bitwarden.com/help/lost-two-step-device".toUri()) intentManager.launchUri(uri = event.uri)
} }
is TwoFactorLoginEvent.NavigateToCaptcha -> { is TwoFactorLoginEvent.NavigateToCaptcha -> {

View File

@@ -3,6 +3,7 @@ package com.x8bit.bitwarden.ui.auth.feature.twofactorlogin
import android.net.Uri import android.net.Uri
import android.os.Parcelable import android.os.Parcelable
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.core.net.toUri
import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.x8bit.bitwarden.R import com.x8bit.bitwarden.R
@@ -19,6 +20,8 @@ import com.x8bit.bitwarden.data.auth.repository.util.CaptchaCallbackTokenResult
import com.x8bit.bitwarden.data.auth.repository.util.DuoCallbackTokenResult import com.x8bit.bitwarden.data.auth.repository.util.DuoCallbackTokenResult
import com.x8bit.bitwarden.data.auth.repository.util.generateUriForCaptcha import com.x8bit.bitwarden.data.auth.repository.util.generateUriForCaptcha
import com.x8bit.bitwarden.data.auth.util.YubiKeyResult import com.x8bit.bitwarden.data.auth.util.YubiKeyResult
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
import com.x8bit.bitwarden.data.platform.repository.util.baseWebVaultUrlOrDefault
import com.x8bit.bitwarden.ui.auth.feature.twofactorlogin.util.button import com.x8bit.bitwarden.ui.auth.feature.twofactorlogin.util.button
import com.x8bit.bitwarden.ui.auth.feature.twofactorlogin.util.imageRes import com.x8bit.bitwarden.ui.auth.feature.twofactorlogin.util.imageRes
import com.x8bit.bitwarden.ui.auth.feature.twofactorlogin.util.isDuo import com.x8bit.bitwarden.ui.auth.feature.twofactorlogin.util.isDuo
@@ -44,6 +47,7 @@ private const val KEY_STATE = "state"
@Suppress("TooManyFunctions") @Suppress("TooManyFunctions")
class TwoFactorLoginViewModel @Inject constructor( class TwoFactorLoginViewModel @Inject constructor(
private val authRepository: AuthRepository, private val authRepository: AuthRepository,
private val environmentRepository: EnvironmentRepository,
savedStateHandle: SavedStateHandle, savedStateHandle: SavedStateHandle,
) : BaseViewModel<TwoFactorLoginState, TwoFactorLoginEvent, TwoFactorLoginAction>( ) : BaseViewModel<TwoFactorLoginState, TwoFactorLoginEvent, TwoFactorLoginAction>(
initialState = savedStateHandle[KEY_STATE] initialState = savedStateHandle[KEY_STATE]
@@ -60,6 +64,16 @@ class TwoFactorLoginViewModel @Inject constructor(
password = TwoFactorLoginArgs(savedStateHandle).password, password = TwoFactorLoginArgs(savedStateHandle).password,
), ),
) { ) {
private val recover2faUri: Uri
get() {
val baseUrl = environmentRepository
.environment
.environmentUrlData
.baseWebVaultUrlOrDefault
return "$baseUrl/#/recover-2fa".toUri()
}
init { init {
// As state updates, write to saved state handle. // As state updates, write to saved state handle.
stateFlow stateFlow
@@ -357,7 +371,7 @@ class TwoFactorLoginViewModel @Inject constructor(
private fun handleSelectAuthMethod(action: TwoFactorLoginAction.SelectAuthMethod) { private fun handleSelectAuthMethod(action: TwoFactorLoginAction.SelectAuthMethod) {
when (action.authMethod) { when (action.authMethod) {
TwoFactorAuthMethod.RECOVERY_CODE -> { TwoFactorAuthMethod.RECOVERY_CODE -> {
sendEvent(TwoFactorLoginEvent.NavigateToRecoveryCode) sendEvent(TwoFactorLoginEvent.NavigateToRecoveryCode(recover2faUri))
} }
TwoFactorAuthMethod.EMAIL -> { TwoFactorAuthMethod.EMAIL -> {
@@ -520,8 +534,10 @@ sealed class TwoFactorLoginEvent {
/** /**
* Navigates to the recovery code help page. * Navigates to the recovery code help page.
*
* @param uri The recovery uri.
*/ */
data object NavigateToRecoveryCode : TwoFactorLoginEvent() data class NavigateToRecoveryCode(val uri: Uri) : TwoFactorLoginEvent()
/** /**
* Shows a toast with the given [message]. * Shows a toast with the given [message].

View File

@@ -255,9 +255,10 @@ class TwoFactorLoginScreenTest : BaseComposeTest() {
@Test @Test
fun `NavigateToRecoveryCode should launch the recovery code uri`() { fun `NavigateToRecoveryCode should launch the recovery code uri`() {
mutableEventFlow.tryEmit(TwoFactorLoginEvent.NavigateToRecoveryCode) val mockUri = mockk<Uri>()
mutableEventFlow.tryEmit(TwoFactorLoginEvent.NavigateToRecoveryCode(mockUri))
verify { verify {
intentManager.launchUri(any()) intentManager.launchUri(mockUri)
} }
} }
} }

View File

@@ -1,6 +1,7 @@
package com.x8bit.bitwarden.ui.auth.feature.twofactorlogin package com.x8bit.bitwarden.ui.auth.feature.twofactorlogin
import android.net.Uri import android.net.Uri
import androidx.core.net.toUri
import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.SavedStateHandle
import app.cash.turbine.test import app.cash.turbine.test
import com.x8bit.bitwarden.R import com.x8bit.bitwarden.R
@@ -14,6 +15,8 @@ import com.x8bit.bitwarden.data.auth.repository.util.CaptchaCallbackTokenResult
import com.x8bit.bitwarden.data.auth.repository.util.DuoCallbackTokenResult import com.x8bit.bitwarden.data.auth.repository.util.DuoCallbackTokenResult
import com.x8bit.bitwarden.data.auth.repository.util.generateUriForCaptcha import com.x8bit.bitwarden.data.auth.repository.util.generateUriForCaptcha
import com.x8bit.bitwarden.data.auth.util.YubiKeyResult import com.x8bit.bitwarden.data.auth.util.YubiKeyResult
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
import com.x8bit.bitwarden.data.platform.repository.util.baseWebVaultUrlOrDefault
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
import com.x8bit.bitwarden.ui.platform.base.util.asText import com.x8bit.bitwarden.ui.platform.base.util.asText
@@ -45,6 +48,11 @@ class TwoFactorLoginViewModelTest : BaseViewModelTest() {
every { duoTokenResultFlow } returns mutableDuoTokenResultFlow every { duoTokenResultFlow } returns mutableDuoTokenResultFlow
every { yubiKeyResultFlow } returns mutableYubiKeyResultFlow every { yubiKeyResultFlow } returns mutableYubiKeyResultFlow
} }
private val environmentRepository: EnvironmentRepository = mockk(relaxed = true) {
every {
environment.environmentUrlData.baseWebVaultUrlOrDefault
} returns "https://vault.bitwarden.com"
}
@BeforeEach @BeforeEach
fun setUp() { fun setUp() {
@@ -515,6 +523,11 @@ class TwoFactorLoginViewModelTest : BaseViewModelTest() {
@Test @Test
fun `SelectAuthMethod with RECOVERY_CODE should launch the NavigateToRecoveryCode event`() = fun `SelectAuthMethod with RECOVERY_CODE should launch the NavigateToRecoveryCode event`() =
runTest { runTest {
val mockkUri = mockk<Uri>()
every {
Uri.parse("https://vault.bitwarden.com/#/recover-2fa")
} returns mockkUri
val viewModel = createViewModel() val viewModel = createViewModel()
viewModel.eventFlow.test { viewModel.eventFlow.test {
viewModel.trySendAction( viewModel.trySendAction(
@@ -523,7 +536,9 @@ class TwoFactorLoginViewModelTest : BaseViewModelTest() {
), ),
) )
assertEquals( assertEquals(
TwoFactorLoginEvent.NavigateToRecoveryCode, TwoFactorLoginEvent.NavigateToRecoveryCode(
uri = "https://vault.bitwarden.com/#/recover-2fa".toUri(),
),
awaitItem(), awaitItem(),
) )
} }
@@ -611,6 +626,7 @@ class TwoFactorLoginViewModelTest : BaseViewModelTest() {
): TwoFactorLoginViewModel = ): TwoFactorLoginViewModel =
TwoFactorLoginViewModel( TwoFactorLoginViewModel(
authRepository = authRepository, authRepository = authRepository,
environmentRepository = environmentRepository,
savedStateHandle = SavedStateHandle().also { savedStateHandle = SavedStateHandle().also {
it["state"] = state it["state"] = state
it["email_address"] = "example@email.com" it["email_address"] = "example@email.com"