From c5a266dfc029774d798bc8c45db4cdbee26adb79 Mon Sep 17 00:00:00 2001 From: David Perez Date: Wed, 23 Oct 2024 07:51:28 -0500 Subject: [PATCH] PM-13020: During totp flow master password reprompt should be honored (#4136) --- .../platform/feature/search/SearchContent.kt | 4 +- .../feature/search/SearchViewModel.kt | 14 +++++ .../search/util/SearchTypeDataExtensions.kt | 9 ++++ .../itemlisting/VaultItemListingContent.kt | 13 +++-- .../itemlisting/VaultItemListingViewModel.kt | 13 +++++ .../util/VaultItemListingDataExtensions.kt | 6 +++ .../feature/search/SearchScreenTest.kt | 20 +++++++ .../feature/search/SearchViewModelTest.kt | 31 +++++++++++ .../util/SearchTypeDataExtensionsTest.kt | 4 ++ .../feature/search/util/SearchUtil.kt | 7 +++ .../itemlisting/VaultItemListingScreenTest.kt | 54 +++++++++++++++++++ .../VaultItemListingViewModelTest.kt | 26 +++++++++ .../util/VaultItemListingDataUtil.kt | 8 +++ 13 files changed, 203 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchContent.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchContent.kt index c0fc89f3f..0b102942e 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchContent.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchContent.kt @@ -116,7 +116,9 @@ fun SearchContent( supportingLabelTestTag = it.subtitleTestTag, optionsTestTag = it.overflowTestTag, onClick = { - if (it.autofillSelectionOptions.isNotEmpty()) { + if (it.isTotp && it.shouldDisplayMasterPasswordReprompt) { + masterPasswordRepromptData = MasterPasswordRepromptData.Totp(it.id) + } else if (it.autofillSelectionOptions.isNotEmpty()) { autofillSelectionOptionsItem = it } else { searchHandlers.onItemClick(it.id) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModel.kt index 7eea1b728..1f06d7871 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModel.kt @@ -570,6 +570,10 @@ class SearchViewModel @Inject constructor( ), ) } + + is MasterPasswordRepromptData.Totp -> { + trySendAction(SearchAction.ItemClick(itemId = data.cipherId)) + } } } @@ -680,6 +684,7 @@ class SearchViewModel @Inject constructor( baseIconUrl = state.baseIconUrl, isIconLoadingDisabled = state.isIconLoadingDisabled, isAutofill = state.isAutofill, + isTotp = state.isTotp, isPremiumUser = state.isPremium, ) } @@ -826,6 +831,7 @@ data class SearchState( val overflowOptions: List, val overflowTestTag: String?, val autofillSelectionOptions: List, + val isTotp: Boolean, val shouldDisplayMasterPasswordReprompt: Boolean, ) : Parcelable } @@ -1171,6 +1177,14 @@ sealed class MasterPasswordRepromptData : Parcelable { val cipherId: String, ) : MasterPasswordRepromptData() + /** + * Autofill was selected. + */ + @Parcelize + data class Totp( + val cipherId: String, + ) : MasterPasswordRepromptData() + /** * A cipher overflow menu item action was selected. */ diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/util/SearchTypeDataExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/util/SearchTypeDataExtensions.kt index 93c7b21aa..861eb7c67 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/util/SearchTypeDataExtensions.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/search/util/SearchTypeDataExtensions.kt @@ -148,6 +148,7 @@ fun List.toViewState( hasMasterPassword: Boolean, isIconLoadingDisabled: Boolean, isAutofill: Boolean, + isTotp: Boolean, isPremiumUser: Boolean, ): SearchState.ViewState = when { @@ -159,6 +160,7 @@ fun List.toViewState( hasMasterPassword = hasMasterPassword, isIconLoadingDisabled = isIconLoadingDisabled, isAutofill = isAutofill, + isTotp = isTotp, isPremiumUser = isPremiumUser, ) .sortAlphabetically(), @@ -172,11 +174,13 @@ fun List.toViewState( } } +@Suppress("LongParameterList") private fun List.toDisplayItemList( baseIconUrl: String, hasMasterPassword: Boolean, isIconLoadingDisabled: Boolean, isAutofill: Boolean, + isTotp: Boolean, isPremiumUser: Boolean, ): List = this.map { @@ -185,15 +189,18 @@ private fun List.toDisplayItemList( hasMasterPassword = hasMasterPassword, isIconLoadingDisabled = isIconLoadingDisabled, isAutofill = isAutofill, + isTotp = isTotp, isPremiumUser = isPremiumUser, ) } +@Suppress("LongParameterList") private fun CipherView.toDisplayItem( baseIconUrl: String, hasMasterPassword: Boolean, isIconLoadingDisabled: Boolean, isAutofill: Boolean, + isTotp: Boolean, isPremiumUser: Boolean, ): SearchState.DisplayItem = SearchState.DisplayItem( @@ -221,6 +228,7 @@ private fun CipherView.toDisplayItem( .filter { this.login != null || (it != AutofillSelectionOption.AUTOFILL_AND_SAVE) }, + isTotp = isTotp, shouldDisplayMasterPasswordReprompt = reprompt == CipherRepromptType.PASSWORD, ) @@ -360,6 +368,7 @@ private fun SendView.toDisplayItem( overflowTestTag = "SendOptionsButton", totpCode = null, autofillSelectionOptions = emptyList(), + isTotp = false, shouldDisplayMasterPasswordReprompt = false, ) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingContent.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingContent.kt index cbb8a69ee..0eae49a2b 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingContent.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingContent.kt @@ -215,11 +215,14 @@ fun VaultItemListingContent( supportingLabelTestTag = it.subtitleTestTag, optionsTestTag = it.optionsTestTag, onClick = { - if (it.isAutofill && it.shouldShowMasterPasswordReprompt) { - masterPasswordRepromptData = - MasterPasswordRepromptData.Autofill( - cipherId = it.id, - ) + if (it.isTotp && it.shouldShowMasterPasswordReprompt) { + masterPasswordRepromptData = MasterPasswordRepromptData.Totp( + cipherId = it.id, + ) + } else if (it.isAutofill && it.shouldShowMasterPasswordReprompt) { + masterPasswordRepromptData = MasterPasswordRepromptData.Autofill( + cipherId = it.id, + ) } else { vaultItemClick(it.id) } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt index 9e0be4a6b..d0db9cb6e 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt @@ -1153,6 +1153,10 @@ class VaultItemListingViewModel @Inject constructor( VaultItemListingsAction.OverflowOptionClick(data.action), ) } + + is MasterPasswordRepromptData.Totp -> { + sendEvent(VaultItemListingEvent.NavigateToEditCipher(data.cipherId)) + } } } @@ -1972,6 +1976,7 @@ data class VaultItemListingState( val optionsTestTag: String, val isAutofill: Boolean, val isFido2Creation: Boolean, + val isTotp: Boolean, val shouldShowMasterPasswordReprompt: Boolean, ) @@ -2551,6 +2556,14 @@ sealed class MasterPasswordRepromptData : Parcelable { val cipherId: String, ) : MasterPasswordRepromptData() + /** + * Totp was selected. + */ + @Parcelize + data class Totp( + val cipherId: String, + ) : MasterPasswordRepromptData() + /** * A cipher overflow menu item action was selected. */ diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataExtensions.kt index 450e6ca66..148dc3cf2 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataExtensions.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataExtensions.kt @@ -137,6 +137,7 @@ fun VaultData.toViewState( isFido2Creation = fido2CreationData != null, fido2CredentialAutofillViews = fido2CredentialAutofillViews, isPremiumUser = isPremiumUser, + isTotp = totpData != null, ), displayFolderList = folderList.map { folderView -> VaultItemListingState.FolderDisplayItem( @@ -282,6 +283,7 @@ private fun List.toDisplayItemList( isFido2Creation: Boolean, fido2CredentialAutofillViews: List?, isPremiumUser: Boolean, + isTotp: Boolean, ): List = this.map { it.toDisplayItem( @@ -295,6 +297,7 @@ private fun List.toDisplayItemList( fido2CredentialAutofillView.cipherId == it.id }, isPremiumUser = isPremiumUser, + isTotp = isTotp, ) } @@ -318,6 +321,7 @@ private fun CipherView.toDisplayItem( isFido2Creation: Boolean, fido2CredentialAutofillView: Fido2CredentialAutofillView?, isPremiumUser: Boolean, + isTotp: Boolean, ): VaultItemListingState.DisplayItem = VaultItemListingState.DisplayItem( id = id.orEmpty(), @@ -345,6 +349,7 @@ private fun CipherView.toDisplayItem( optionsTestTag = "CipherOptionsButton", isAutofill = isAutofill, isFido2Creation = isFido2Creation, + isTotp = isTotp, shouldShowMasterPasswordReprompt = (reprompt == CipherRepromptType.PASSWORD) && hasMasterPassword, ) @@ -416,6 +421,7 @@ private fun SendView.toDisplayItem( isAutofill = false, shouldShowMasterPasswordReprompt = false, isFido2Creation = false, + isTotp = false, ) @get:DrawableRes diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchScreenTest.kt index ae1c15485..aca5ba248 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchScreenTest.kt @@ -345,6 +345,26 @@ class SearchScreenTest : BaseComposeTest() { composeTestRule.assertNoDialogExists() } + @Test + fun `clicking on totp when reprompt is required should show master password dialog`() { + mutableStateFlow.value = DEFAULT_STATE.copy( + viewState = SearchState.ViewState.Content( + displayItems = listOf( + createMockDisplayItemForCipher(number = 1, isTotp = true).copy( + shouldDisplayMasterPasswordReprompt = true, + ), + ), + ), + totpData = mockk(), + ) + composeTestRule + .onNodeWithText(text = "mockName-1") + .assertIsDisplayed() + .performClick() + + composeTestRule.assertMasterPasswordDialogDisplayed() + } + @Test fun `clicking cancel on the master password dialog should close the dialog`() { mutableStateFlow.value = createStateForAutofill(isRepromptRequired = true) diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt index df3f0f45a..9936ac3e8 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt @@ -592,6 +592,32 @@ class SearchViewModelTest : BaseViewModelTest() { } } + @Suppress("MaxLineLength") + @Test + fun `MasterPasswordRepromptSubmit for a request Success with a valid password for totp should emit NavigateToEditCipher`() = + runTest { + setupMockUri() + val cipherId = CIPHER_ID + val password = "password" + + coEvery { + authRepository.validatePassword(password = password) + } returns ValidatePasswordResult.Success(isValid = true) + val viewModel = createViewModel(initialState = DEFAULT_STATE.copy(totpData = mockk())) + + viewModel.eventFlow.test { + viewModel.trySendAction( + SearchAction.MasterPasswordRepromptSubmit( + password = password, + masterPasswordRepromptData = MasterPasswordRepromptData.Totp( + cipherId = cipherId, + ), + ), + ) + assertEquals(SearchEvent.NavigateToEditCipher(cipherId), awaitItem()) + } + } + @Suppress("MaxLineLength") @Test fun `MasterPasswordRepromptSubmit for a request Success with a valid password for an overflow action should perform the action`() = @@ -990,6 +1016,7 @@ class SearchViewModelTest : BaseViewModelTest() { isAutofill = false, hasMasterPassword = true, isPremiumUser = true, + isTotp = false, ) } returns expectedViewState val dataState = DataState.Loaded( @@ -1092,6 +1119,7 @@ class SearchViewModelTest : BaseViewModelTest() { isAutofill = false, hasMasterPassword = true, isPremiumUser = true, + isTotp = false, ) } returns expectedViewState mutableVaultDataStateFlow.tryEmit( @@ -1204,6 +1232,7 @@ class SearchViewModelTest : BaseViewModelTest() { isAutofill = false, hasMasterPassword = true, isPremiumUser = true, + isTotp = false, ) } returns expectedViewState val dataState = DataState.Error( @@ -1319,6 +1348,7 @@ class SearchViewModelTest : BaseViewModelTest() { isAutofill = false, hasMasterPassword = true, isPremiumUser = true, + isTotp = false, ) } returns expectedViewState val dataState = DataState.NoNetwork( @@ -1494,6 +1524,7 @@ class SearchViewModelTest : BaseViewModelTest() { isAutofill = true, hasMasterPassword = true, isPremiumUser = true, + isTotp = false, ) } returns expectedViewState val dataState = DataState.Loaded( diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/util/SearchTypeDataExtensionsTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/util/SearchTypeDataExtensionsTest.kt index 32a5fb177..7898c1698 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/util/SearchTypeDataExtensionsTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/util/SearchTypeDataExtensionsTest.kt @@ -299,6 +299,7 @@ class SearchTypeDataExtensionsTest { isAutofill = false, hasMasterPassword = true, isPremiumUser = true, + isTotp = true, ) assertEquals(SearchState.ViewState.Empty(message = null), result) @@ -324,6 +325,7 @@ class SearchTypeDataExtensionsTest { isAutofill = false, hasMasterPassword = true, isPremiumUser = true, + isTotp = false, ) assertEquals( @@ -364,6 +366,7 @@ class SearchTypeDataExtensionsTest { isAutofill = true, hasMasterPassword = true, isPremiumUser = true, + isTotp = false, ) assertEquals( @@ -414,6 +417,7 @@ class SearchTypeDataExtensionsTest { isAutofill = false, hasMasterPassword = true, isPremiumUser = true, + isTotp = true, ) assertEquals( diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/util/SearchUtil.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/util/SearchUtil.kt index 43f6ca427..80736f1bf 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/util/SearchUtil.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/search/util/SearchUtil.kt @@ -15,6 +15,7 @@ import com.x8bit.bitwarden.ui.vault.feature.itemlisting.model.ListingItemOverflo fun createMockDisplayItemForCipher( number: Int, cipherType: CipherType = CipherType.LOGIN, + isTotp: Boolean = false, ): SearchState.DisplayItem = when (cipherType) { CipherType.LOGIN -> { @@ -65,6 +66,7 @@ fun createMockDisplayItemForCipher( totpCode = "mockTotp-$number", autofillSelectionOptions = emptyList(), shouldDisplayMasterPasswordReprompt = false, + isTotp = isTotp, ) } @@ -102,6 +104,7 @@ fun createMockDisplayItemForCipher( totpCode = null, autofillSelectionOptions = emptyList(), shouldDisplayMasterPasswordReprompt = false, + isTotp = false, ) } @@ -145,6 +148,7 @@ fun createMockDisplayItemForCipher( totpCode = null, autofillSelectionOptions = emptyList(), shouldDisplayMasterPasswordReprompt = false, + isTotp = false, ) } @@ -179,6 +183,7 @@ fun createMockDisplayItemForCipher( totpCode = null, autofillSelectionOptions = emptyList(), shouldDisplayMasterPasswordReprompt = false, + isTotp = false, ) } } @@ -227,6 +232,7 @@ fun createMockDisplayItemForSend( totpCode = null, autofillSelectionOptions = emptyList(), shouldDisplayMasterPasswordReprompt = false, + isTotp = false, ) } @@ -265,6 +271,7 @@ fun createMockDisplayItemForSend( totpCode = null, autofillSelectionOptions = emptyList(), shouldDisplayMasterPasswordReprompt = false, + isTotp = true, ) } } diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt index c83167a9a..169f8355f 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt @@ -1052,6 +1052,58 @@ class VaultItemListingScreenTest : BaseComposeTest() { } } + @Suppress("MaxLineLength") + @Test + fun `clicking on a display item when master password reprompt is required for totp flow should show the master password dialog`() { + mutableStateFlow.update { + it.copy( + viewState = VaultItemListingState.ViewState.Content( + displayCollectionList = emptyList(), + displayItemList = listOf( + createDisplayItem(number = 1).copy( + isTotp = true, + shouldShowMasterPasswordReprompt = true, + ), + ), + displayFolderList = emptyList(), + ), + ) + } + + composeTestRule + .onNodeWithText(text = "mockTitle-1") + .assertIsDisplayed() + .performClick() + + composeTestRule + .onAllNodesWithText(text = "Master password confirmation") + .filterToOne(hasAnyAncestor(isDialog())) + .assertIsDisplayed() + composeTestRule + .onAllNodesWithText( + text = "This action is protected, to continue please re-enter your master " + + "password to verify your identity.", + ) + .filterToOne(hasAnyAncestor(isDialog())) + .assertIsDisplayed() + composeTestRule + .onAllNodesWithText(text = "Master password") + .filterToOne(hasAnyAncestor(isDialog())) + .assertIsDisplayed() + composeTestRule + .onAllNodesWithText(text = "Cancel") + .filterToOne(hasAnyAncestor(isDialog())) + .assertIsDisplayed() + composeTestRule + .onAllNodesWithText(text = "Submit") + .filterToOne(hasAnyAncestor(isDialog())) + .assertIsDisplayed() + + verify(exactly = 0) { + viewModel.trySendAction(any()) + } + } + @Test fun `clicking cancel on the master password dialog should close the dialog`() { mutableStateFlow.update { @@ -2146,6 +2198,7 @@ private fun createDisplayItem(number: Int): VaultItemListingState.DisplayItem = isFido2Creation = false, shouldShowMasterPasswordReprompt = false, iconTestTag = null, + isTotp = false, ) private fun createCipherDisplayItem(number: Int): VaultItemListingState.DisplayItem = @@ -2170,4 +2223,5 @@ private fun createCipherDisplayItem(number: Int): VaultItemListingState.DisplayI isFido2Creation = false, shouldShowMasterPasswordReprompt = false, iconTestTag = null, + isTotp = true, ) diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt index 75c8cce39..7eeb19f82 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt @@ -917,6 +917,31 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { } } + @Suppress("MaxLineLength") + @Test + fun `MasterPasswordRepromptSubmit with a valid password for totp flow should emit NavigateToEditCipher`() = + runTest { + val cipherId = "cipherId-1234" + val password = "password" + val viewModel = createVaultItemListingViewModel() + coEvery { + authRepository.validatePassword(password = password) + } returns ValidatePasswordResult.Success(isValid = true) + + viewModel.eventFlow.test { + viewModel.trySendAction( + VaultItemListingsAction.MasterPasswordRepromptSubmit( + password = password, + masterPasswordRepromptData = MasterPasswordRepromptData.Totp( + cipherId = cipherId, + ), + ), + ) + // An Edit action navigates to the Edit screen + assertEquals(VaultItemListingEvent.NavigateToEditCipher(cipherId), awaitItem()) + } + } + @Test fun `AddVaultItemClick for vault item should emit NavigateToAddVaultItem`() = runTest { val viewModel = createVaultItemListingViewModel() @@ -1467,6 +1492,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { createMockDisplayItemForCipher( number = 1, secondSubtitleTestTag = "PasskeySite", + isTotp = true, ), ), displayFolderList = emptyList(), diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataUtil.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataUtil.kt index 7419b8070..61fa4bb8d 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataUtil.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataUtil.kt @@ -12,12 +12,14 @@ import com.x8bit.bitwarden.ui.vault.feature.itemlisting.model.ListingItemOverflo /** * Create a mock [VaultItemListingState.DisplayItem] with a given [number]. */ +@Suppress("LongParameterList") fun createMockDisplayItemForCipher( number: Int, cipherType: CipherType = CipherType.LOGIN, subtitle: String? = "mockUsername-$number", secondSubtitleTestTag: String? = null, requiresPasswordReprompt: Boolean = true, + isTotp: Boolean = false, ): VaultItemListingState.DisplayItem = when (cipherType) { CipherType.LOGIN -> { @@ -71,6 +73,7 @@ fun createMockDisplayItemForCipher( isFido2Creation = false, shouldShowMasterPasswordReprompt = false, iconTestTag = "LoginCipherIcon", + isTotp = isTotp, ) } @@ -111,6 +114,7 @@ fun createMockDisplayItemForCipher( isFido2Creation = false, shouldShowMasterPasswordReprompt = false, iconTestTag = "SecureNoteCipherIcon", + isTotp = false, ) } @@ -157,6 +161,7 @@ fun createMockDisplayItemForCipher( isFido2Creation = false, shouldShowMasterPasswordReprompt = false, iconTestTag = "CardCipherIcon", + isTotp = false, ) } @@ -194,6 +199,7 @@ fun createMockDisplayItemForCipher( isFido2Creation = false, shouldShowMasterPasswordReprompt = false, iconTestTag = "IdentityCipherIcon", + isTotp = false, ) } } @@ -245,6 +251,7 @@ fun createMockDisplayItemForSend( isFido2Creation = false, shouldShowMasterPasswordReprompt = false, iconTestTag = null, + isTotp = false, ) } @@ -286,6 +293,7 @@ fun createMockDisplayItemForSend( isFido2Creation = false, shouldShowMasterPasswordReprompt = false, iconTestTag = null, + isTotp = false, ) } }