BIT-2291: Bypass master password reprompt when user has no password (#1301)

This commit is contained in:
David Perez
2024-06-20 17:08:07 +01:00
committed by Álison Fernandes
parent b730330196
commit 0a03df75cc
25 changed files with 373 additions and 73 deletions
@@ -65,7 +65,12 @@ data class UserState(
val organizations: List<Organization>,
val isBiometricsEnabled: Boolean,
val vaultUnlockType: VaultUnlockType = VaultUnlockType.MASTER_PASSWORD,
)
) {
/**
* Indicates that the user does or does not have a master password.
*/
val hasMasterPassword: Boolean get() = trustedDevice?.hasMasterPassword != false
}
/**
* Models the data related to trusted device encryption (TDE).
@@ -97,6 +97,7 @@ class SearchViewModel @Inject constructor(
baseIconUrl = environmentRepo.environment.environmentUrlData.baseIconUrl,
isIconLoadingDisabled = settingsRepo.isIconLoadingDisabled,
autofillSelectionData = autofillSelectionData,
hasMasterPassword = userState.activeAccount.hasMasterPassword,
)
},
) {
@@ -640,6 +641,7 @@ class SearchViewModel @Inject constructor(
)
.toViewState(
searchTerm = state.searchTerm,
hasMasterPassword = state.hasMasterPassword,
baseIconUrl = state.baseIconUrl,
isIconLoadingDisabled = state.isIconLoadingDisabled,
isAutofill = state.isAutofill,
@@ -686,6 +688,7 @@ data class SearchState(
val isIconLoadingDisabled: Boolean,
// Internal
val autofillSelectionData: AutofillSelectionData? = null,
val hasMasterPassword: Boolean,
) : Parcelable {
/**
@@ -140,6 +140,7 @@ private fun CipherView.matchedSearch(searchTerm: String): SortPriority? {
fun List<CipherView>.toViewState(
searchTerm: String,
baseIconUrl: String,
hasMasterPassword: Boolean,
isIconLoadingDisabled: Boolean,
isAutofill: Boolean,
): SearchState.ViewState =
@@ -149,6 +150,7 @@ fun List<CipherView>.toViewState(
SearchState.ViewState.Content(
displayItems = toDisplayItemList(
baseIconUrl = baseIconUrl,
hasMasterPassword = hasMasterPassword,
isIconLoadingDisabled = isIconLoadingDisabled,
isAutofill = isAutofill,
),
@@ -164,12 +166,14 @@ fun List<CipherView>.toViewState(
private fun List<CipherView>.toDisplayItemList(
baseIconUrl: String,
hasMasterPassword: Boolean,
isIconLoadingDisabled: Boolean,
isAutofill: Boolean,
): List<SearchState.DisplayItem> =
this.map {
it.toDisplayItem(
baseIconUrl = baseIconUrl,
hasMasterPassword = hasMasterPassword,
isIconLoadingDisabled = isIconLoadingDisabled,
isAutofill = isAutofill,
)
@@ -177,6 +181,7 @@ private fun List<CipherView>.toDisplayItemList(
private fun CipherView.toDisplayItem(
baseIconUrl: String,
hasMasterPassword: Boolean,
isIconLoadingDisabled: Boolean,
isAutofill: Boolean,
): SearchState.DisplayItem =
@@ -191,7 +196,7 @@ private fun CipherView.toDisplayItem(
isIconLoadingDisabled = isIconLoadingDisabled,
),
extraIconList = toLabelIcons(),
overflowOptions = toOverflowActions(),
overflowOptions = toOverflowActions(hasMasterPassword = hasMasterPassword),
overflowTestTag = "CipherOptionsButton",
totpCode = login?.totp,
autofillSelectionOptions = AutofillSelectionOption
@@ -749,8 +749,7 @@ class VaultItemViewModel @Inject constructor(
mutableStateFlow.update {
it.copy(
viewState = vaultDataState.toViewStateOrError(
isPremiumUser = userState.activeAccount.isPremium,
totpCodeItemData = vaultDataState.data?.totpCodeItemData,
account = userState.activeAccount,
errorText = R.string.generic_error_message.asText(),
),
)
@@ -761,8 +760,7 @@ class VaultItemViewModel @Inject constructor(
mutableStateFlow.update {
it.copy(
viewState = vaultDataState.toViewStateOrError(
isPremiumUser = userState.activeAccount.isPremium,
totpCodeItemData = vaultDataState.data.totpCodeItemData,
account = userState.activeAccount,
errorText = R.string.generic_error_message.asText(),
),
)
@@ -779,8 +777,7 @@ class VaultItemViewModel @Inject constructor(
mutableStateFlow.update {
it.copy(
viewState = vaultDataState.toViewStateOrError(
isPremiumUser = userState.activeAccount.isPremium,
totpCodeItemData = vaultDataState.data?.totpCodeItemData,
account = userState.activeAccount,
errorText = R.string.internet_connection_required_title
.asText()
.concat(
@@ -796,8 +793,7 @@ class VaultItemViewModel @Inject constructor(
mutableStateFlow.update {
it.copy(
viewState = vaultDataState.toViewStateOrError(
isPremiumUser = userState.activeAccount.isPremium,
totpCodeItemData = vaultDataState.data.totpCodeItemData,
account = userState.activeAccount,
errorText = R.string.generic_error_message.asText(),
),
)
@@ -807,13 +803,16 @@ class VaultItemViewModel @Inject constructor(
}
private fun DataState<VaultItemStateData>.toViewStateOrError(
isPremiumUser: Boolean,
totpCodeItemData: TotpCodeItemData?,
account: UserState.Account,
errorText: Text,
): VaultItemState.ViewState = this
.data
?.cipher
?.toViewState(isPremiumUser = isPremiumUser, totpCodeItemData = totpCodeItemData)
?.toViewState(
isPremiumUser = account.isPremium,
hasMasterPassword = account.hasMasterPassword,
totpCodeItemData = this.data?.totpCodeItemData,
)
?: VaultItemState.ViewState.Error(message = errorText)
private fun handleValidatePasswordReceive(
@@ -33,9 +33,10 @@ private const val FIDO2_CREDENTIAL_CREATION_TIME_PATTERN: String = "h:mm a"
/**
* Transforms [VaultData] into [VaultState.ViewState].
*/
@Suppress("LongMethod")
@Suppress("CyclomaticComplexMethod", "LongMethod")
fun CipherView.toViewState(
isPremiumUser: Boolean,
hasMasterPassword: Boolean,
totpCodeItemData: TotpCodeItemData?,
clock: Clock = Clock.systemDefaultZone(),
): VaultItemState.ViewState =
@@ -43,7 +44,7 @@ fun CipherView.toViewState(
common = VaultItemState.ViewState.Content.Common(
currentCipher = this,
name = name,
requiresReprompt = reprompt == CipherRepromptType.PASSWORD,
requiresReprompt = reprompt == CipherRepromptType.PASSWORD && hasMasterPassword,
customFields = fields.orEmpty().map { it.toCustomField() },
lastUpdated = revisionDate.toFormattedPattern(
pattern = LAST_UPDATED_DATE_TIME_PATTERN,
@@ -99,6 +99,7 @@ class VaultItemListingViewModel @Inject constructor(
.any(),
autofillSelectionData = specialCircumstance?.autofillSelectionData,
shouldFinishOnComplete = specialCircumstance?.shouldFinishWhenComplete ?: false,
hasMasterPassword = userState.activeAccount.hasMasterPassword,
)
},
) {
@@ -686,6 +687,7 @@ class VaultItemListingViewModel @Inject constructor(
vaultData.toViewState(
vaultFilterType = state.vaultFilterType,
itemListingType = listingType,
hasMasterPassword = state.hasMasterPassword,
baseIconUrl = state.baseIconUrl,
isIconLoadingDisabled = state.isIconLoadingDisabled,
autofillSelectionData = state.autofillSelectionData,
@@ -754,6 +756,7 @@ data class VaultItemListingState(
private val isPullToRefreshSettingEnabled: Boolean,
val autofillSelectionData: AutofillSelectionData? = null,
val shouldFinishOnComplete: Boolean = false,
val hasMasterPassword: Boolean,
) {
/**
* Whether or not this represents a listing screen for autofill.
@@ -84,9 +84,11 @@ sealed class ListingItemOverflowAction : Parcelable {
* Click on the edit cipher overflow option.
*/
@Parcelize
data class EditClick(val cipherId: String) : VaultAction() {
data class EditClick(
val cipherId: String,
override val requiresPasswordReprompt: Boolean,
) : VaultAction() {
override val title: Text get() = R.string.edit.asText()
override val requiresPasswordReprompt: Boolean get() = true
}
/**
@@ -102,9 +104,11 @@ sealed class ListingItemOverflowAction : Parcelable {
* Click on the copy password overflow option.
*/
@Parcelize
data class CopyPasswordClick(val password: String) : VaultAction() {
data class CopyPasswordClick(
val password: String,
override val requiresPasswordReprompt: Boolean,
) : VaultAction() {
override val title: Text get() = R.string.copy_password.asText()
override val requiresPasswordReprompt: Boolean get() = true
}
/**
@@ -120,18 +124,22 @@ sealed class ListingItemOverflowAction : Parcelable {
* Click on the copy number overflow option.
*/
@Parcelize
data class CopyNumberClick(val number: String) : VaultAction() {
data class CopyNumberClick(
val number: String,
override val requiresPasswordReprompt: Boolean,
) : VaultAction() {
override val title: Text get() = R.string.copy_number.asText()
override val requiresPasswordReprompt: Boolean get() = true
}
/**
* Click on the copy security code overflow option.
*/
@Parcelize
data class CopySecurityCodeClick(val securityCode: String) : VaultAction() {
data class CopySecurityCodeClick(
val securityCode: String,
override val requiresPasswordReprompt: Boolean,
) : VaultAction() {
override val title: Text get() = R.string.copy_security_code.asText()
override val requiresPasswordReprompt: Boolean get() = true
}
/**
@@ -91,10 +91,11 @@ fun SendView.determineListingPredicate(
/**
* Transforms a list of [CipherView] into [VaultItemListingState.ViewState].
*/
@Suppress("CyclomaticComplexMethod", "LongMethod")
@Suppress("CyclomaticComplexMethod", "LongMethod", "LongParameterList")
fun VaultData.toViewState(
itemListingType: VaultItemListingState.ItemListingType.Vault,
vaultFilterType: VaultFilterType,
hasMasterPassword: Boolean,
baseIconUrl: String,
isIconLoadingDisabled: Boolean,
autofillSelectionData: AutofillSelectionData?,
@@ -122,6 +123,7 @@ fun VaultData.toViewState(
VaultItemListingState.ViewState.Content(
displayItemList = filteredCipherViewList.toDisplayItemList(
baseIconUrl = baseIconUrl,
hasMasterPassword = hasMasterPassword,
isIconLoadingDisabled = isIconLoadingDisabled,
isAutofill = autofillSelectionData != null,
),
@@ -246,12 +248,14 @@ fun VaultItemListingState.ItemListingType.updateWithAdditionalDataIfNecessary(
private fun List<CipherView>.toDisplayItemList(
baseIconUrl: String,
hasMasterPassword: Boolean,
isIconLoadingDisabled: Boolean,
isAutofill: Boolean,
): List<VaultItemListingState.DisplayItem> =
this.map {
it.toDisplayItem(
baseIconUrl = baseIconUrl,
hasMasterPassword = hasMasterPassword,
isIconLoadingDisabled = isIconLoadingDisabled,
isAutofill = isAutofill,
)
@@ -270,6 +274,7 @@ private fun List<SendView>.toDisplayItemList(
private fun CipherView.toDisplayItem(
baseIconUrl: String,
hasMasterPassword: Boolean,
isIconLoadingDisabled: Boolean,
isAutofill: Boolean,
): VaultItemListingState.DisplayItem =
@@ -285,7 +290,7 @@ private fun CipherView.toDisplayItem(
),
iconTestTag = toIconTestTag(),
extraIconList = toLabelIcons(),
overflowOptions = toOverflowActions(),
overflowOptions = toOverflowActions(hasMasterPassword = hasMasterPassword),
optionsTestTag = "CipherOptionsButton",
isAutofill = isAutofill,
shouldShowMasterPasswordReprompt = reprompt == CipherRepromptType.PASSWORD,
@@ -9,28 +9,44 @@ import com.x8bit.bitwarden.ui.vault.model.VaultTrailingIcon
/**
* Creates the list of overflow actions to be displayed for a [CipherView].
*/
fun CipherView.toOverflowActions(): List<ListingItemOverflowAction.VaultAction> =
fun CipherView.toOverflowActions(
hasMasterPassword: Boolean,
): List<ListingItemOverflowAction.VaultAction> =
this
.id
?.let { cipherId ->
listOfNotNull(
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = cipherId),
ListingItemOverflowAction.VaultAction.EditClick(cipherId = cipherId)
ListingItemOverflowAction.VaultAction.EditClick(
cipherId = cipherId,
requiresPasswordReprompt = hasMasterPassword,
)
.takeUnless { this.deletedDate != null },
this.login?.username?.let {
ListingItemOverflowAction.VaultAction.CopyUsernameClick(username = it)
},
this.login?.password
?.let { ListingItemOverflowAction.VaultAction.CopyPasswordClick(password = it) }
?.let {
ListingItemOverflowAction.VaultAction.CopyPasswordClick(
password = it,
requiresPasswordReprompt = hasMasterPassword,
)
}
.takeIf { this.viewPassword },
this.login?.totp
?.let { ListingItemOverflowAction.VaultAction.CopyTotpClick(totpCode = it) }
.takeIf { this.type == CipherType.LOGIN },
this.card?.number?.let {
ListingItemOverflowAction.VaultAction.CopyNumberClick(number = it)
ListingItemOverflowAction.VaultAction.CopyNumberClick(
number = it,
requiresPasswordReprompt = hasMasterPassword,
)
},
this.card?.code?.let {
ListingItemOverflowAction.VaultAction.CopySecurityCodeClick(securityCode = it)
ListingItemOverflowAction.VaultAction.CopySecurityCodeClick(
securityCode = it,
requiresPasswordReprompt = hasMasterPassword,
)
},
this.notes
?.let { ListingItemOverflowAction.VaultAction.CopyNoteClick(notes = it) }
@@ -83,6 +83,7 @@ class VaultViewModel @Inject constructor(
isPremium = userState.activeAccount.isPremium,
isPullToRefreshSettingEnabled = settingsRepository.getPullToRefreshEnabledFlow().value,
baseIconUrl = userState.activeAccount.environment.environmentUrlData.baseIconUrl,
hasMasterPassword = userState.activeAccount.hasMasterPassword,
)
},
) {
@@ -493,6 +494,7 @@ class VaultViewModel @Inject constructor(
vaultFilterType = vaultFilterTypeOrDefault,
isIconLoadingDisabled = state.isIconLoadingDisabled,
isPremium = state.isPremium,
hasMasterPassword = state.hasMasterPassword,
errorTitle = R.string.an_error_has_occurred.asText(),
errorMessage = R.string.generic_error_message.asText(),
)
@@ -513,6 +515,7 @@ class VaultViewModel @Inject constructor(
baseIconUrl = state.baseIconUrl,
isIconLoadingDisabled = state.isIconLoadingDisabled,
isPremium = state.isPremium,
hasMasterPassword = state.hasMasterPassword,
vaultFilterType = vaultFilterTypeOrDefault,
),
dialog = null,
@@ -533,6 +536,7 @@ class VaultViewModel @Inject constructor(
isPremium = state.isPremium,
errorTitle = R.string.internet_connection_required_title.asText(),
isIconLoadingDisabled = state.isIconLoadingDisabled,
hasMasterPassword = state.hasMasterPassword,
errorMessage = R.string.internet_connection_required_message.asText(),
)
sendEvent(VaultEvent.DismissPullToRefresh)
@@ -545,6 +549,7 @@ class VaultViewModel @Inject constructor(
baseIconUrl = state.baseIconUrl,
isIconLoadingDisabled = state.isIconLoadingDisabled,
isPremium = state.isPremium,
hasMasterPassword = state.hasMasterPassword,
vaultFilterType = vaultFilterTypeOrDefault,
),
)
@@ -610,6 +615,7 @@ data class VaultState(
// Internal-use properties
val isSwitchingAccounts: Boolean = false,
val isPremium: Boolean,
val hasMasterPassword: Boolean,
private val isPullToRefreshSettingEnabled: Boolean,
val baseIconUrl: String,
val isIconLoadingDisabled: Boolean,
@@ -1163,6 +1169,7 @@ private fun MutableStateFlow<VaultState>.updateToErrorStateOrDialog(
vaultFilterType: VaultFilterType,
isIconLoadingDisabled: Boolean,
isPremium: Boolean,
hasMasterPassword: Boolean,
errorTitle: Text,
errorMessage: Text,
) {
@@ -1172,6 +1179,7 @@ private fun MutableStateFlow<VaultState>.updateToErrorStateOrDialog(
viewState = vaultData.toViewState(
baseIconUrl = baseIconUrl,
isPremium = isPremium,
hasMasterPassword = hasMasterPassword,
vaultFilterType = vaultFilterType,
isIconLoadingDisabled = isIconLoadingDisabled,
),
@@ -35,6 +35,7 @@ private const val NO_FOLDER_ITEM_THRESHOLD: Int = 100
@Suppress("LongMethod")
fun VaultData.toViewState(
isPremium: Boolean,
hasMasterPassword: Boolean,
isIconLoadingDisabled: Boolean,
baseIconUrl: String,
vaultFilterType: VaultFilterType,
@@ -78,6 +79,7 @@ fun VaultData.toViewState(
.filter { it.favorite }
.mapNotNull {
it.toVaultItemOrNull(
hasMasterPassword = hasMasterPassword,
isIconLoadingDisabled = isIconLoadingDisabled,
baseIconUrl = baseIconUrl,
)
@@ -110,6 +112,7 @@ fun VaultData.toViewState(
noFolderItems = noFolderItems
.mapNotNull {
it.toVaultItemOrNull(
hasMasterPassword = hasMasterPassword,
isIconLoadingDisabled = isIconLoadingDisabled,
baseIconUrl = baseIconUrl,
)
@@ -183,6 +186,7 @@ fun List<LoginUriView>?.toLoginIconData(
*/
@Suppress("MagicNumber")
private fun CipherView.toVaultItemOrNull(
hasMasterPassword: Boolean,
isIconLoadingDisabled: Boolean,
baseIconUrl: String,
): VaultState.ViewState.VaultItem? {
@@ -196,7 +200,7 @@ private fun CipherView.toVaultItemOrNull(
isIconLoadingDisabled = isIconLoadingDisabled,
baseIconUrl = baseIconUrl,
),
overflowOptions = toOverflowActions(),
overflowOptions = toOverflowActions(hasMasterPassword = hasMasterPassword),
extraIconList = toLabelIcons(),
shouldShowMasterPasswordReprompt = reprompt == CipherRepromptType.PASSWORD,
)
@@ -204,7 +208,7 @@ private fun CipherView.toVaultItemOrNull(
CipherType.SECURE_NOTE -> VaultState.ViewState.VaultItem.SecureNote(
id = id,
name = name.asText(),
overflowOptions = toOverflowActions(),
overflowOptions = toOverflowActions(hasMasterPassword = hasMasterPassword),
extraIconList = toLabelIcons(),
shouldShowMasterPasswordReprompt = reprompt == CipherRepromptType.PASSWORD,
)
@@ -216,7 +220,7 @@ private fun CipherView.toVaultItemOrNull(
lastFourDigits = card?.number
?.takeLast(4)
?.asText(),
overflowOptions = toOverflowActions(),
overflowOptions = toOverflowActions(hasMasterPassword = hasMasterPassword),
extraIconList = toLabelIcons(),
shouldShowMasterPasswordReprompt = reprompt == CipherRepromptType.PASSWORD,
)
@@ -230,7 +234,7 @@ private fun CipherView.toVaultItemOrNull(
else -> "${identity?.firstName} ${identity?.lastName}"
}
?.asText(),
overflowOptions = toOverflowActions(),
overflowOptions = toOverflowActions(hasMasterPassword = hasMasterPassword),
extraIconList = toLabelIcons(),
shouldShowMasterPasswordReprompt = reprompt == CipherRepromptType.PASSWORD,
)
@@ -541,6 +541,7 @@ class SearchScreenTest : BaseComposeTest() {
SearchAction.OverflowOptionClick(
overflowAction = ListingItemOverflowAction.VaultAction.EditClick(
cipherId = "mockId-1",
requiresPasswordReprompt = true,
),
),
)
@@ -579,6 +580,7 @@ class SearchScreenTest : BaseComposeTest() {
SearchAction.OverflowOptionClick(
overflowAction = ListingItemOverflowAction.VaultAction.CopyPasswordClick(
password = "mockPassword-1",
requiresPasswordReprompt = true,
),
),
)
@@ -675,6 +677,7 @@ class SearchScreenTest : BaseComposeTest() {
masterPasswordRepromptData = MasterPasswordRepromptData.OverflowItem(
action = ListingItemOverflowAction.VaultAction.EditClick(
cipherId = "mockId-1",
requiresPasswordReprompt = true,
),
),
),
@@ -882,6 +885,7 @@ private val DEFAULT_STATE: SearchState = SearchState(
baseWebSendUrl = "www.test.com",
baseIconUrl = "www.test.com",
isIconLoadingDisabled = false,
hasMasterPassword = true,
)
private fun createStateForAutofill(
@@ -477,6 +477,7 @@ class SearchViewModelTest : BaseViewModelTest() {
masterPasswordRepromptData = MasterPasswordRepromptData.OverflowItem(
action = ListingItemOverflowAction.VaultAction.EditClick(
cipherId = cipherId,
requiresPasswordReprompt = true,
),
),
),
@@ -665,7 +666,10 @@ class SearchViewModelTest : BaseViewModelTest() {
val viewModel = createViewModel()
viewModel.trySendAction(
SearchAction.OverflowOptionClick(
ListingItemOverflowAction.VaultAction.CopyNumberClick(number = number),
ListingItemOverflowAction.VaultAction.CopyNumberClick(
number = number,
requiresPasswordReprompt = true,
),
),
)
verify(exactly = 1) {
@@ -726,7 +730,10 @@ class SearchViewModelTest : BaseViewModelTest() {
val viewModel = createViewModel()
viewModel.trySendAction(
SearchAction.OverflowOptionClick(
ListingItemOverflowAction.VaultAction.CopyPasswordClick(password = password),
ListingItemOverflowAction.VaultAction.CopyPasswordClick(
password = password,
requiresPasswordReprompt = true,
),
),
)
verify(exactly = 1) {
@@ -744,6 +751,7 @@ class SearchViewModelTest : BaseViewModelTest() {
SearchAction.OverflowOptionClick(
ListingItemOverflowAction.VaultAction.CopySecurityCodeClick(
securityCode = securityCode,
requiresPasswordReprompt = true,
),
),
)
@@ -777,7 +785,10 @@ class SearchViewModelTest : BaseViewModelTest() {
viewModel.eventFlow.test {
viewModel.trySendAction(
SearchAction.OverflowOptionClick(
ListingItemOverflowAction.VaultAction.EditClick(cipherId = cipherId),
ListingItemOverflowAction.VaultAction.EditClick(
cipherId = cipherId,
requiresPasswordReprompt = true,
),
),
)
assertEquals(SearchEvent.NavigateToEditCipher(cipherId), awaitItem())
@@ -834,6 +845,7 @@ class SearchViewModelTest : BaseViewModelTest() {
baseIconUrl = "https://vault.bitwarden.com/icons",
isIconLoadingDisabled = false,
isAutofill = false,
hasMasterPassword = true,
)
} returns expectedViewState
val dataState = DataState.Loaded(
@@ -934,6 +946,7 @@ class SearchViewModelTest : BaseViewModelTest() {
baseIconUrl = "https://vault.bitwarden.com/icons",
isIconLoadingDisabled = false,
isAutofill = false,
hasMasterPassword = true,
)
} returns expectedViewState
mutableVaultDataStateFlow.tryEmit(
@@ -1044,6 +1057,7 @@ class SearchViewModelTest : BaseViewModelTest() {
baseIconUrl = "https://vault.bitwarden.com/icons",
isIconLoadingDisabled = false,
isAutofill = false,
hasMasterPassword = true,
)
} returns expectedViewState
val dataState = DataState.Error(
@@ -1154,6 +1168,7 @@ class SearchViewModelTest : BaseViewModelTest() {
baseIconUrl = "https://vault.bitwarden.com/icons",
isIconLoadingDisabled = false,
isAutofill = false,
hasMasterPassword = true,
)
} returns expectedViewState
val dataState = DataState.NoNetwork(
@@ -1320,6 +1335,7 @@ class SearchViewModelTest : BaseViewModelTest() {
baseIconUrl = "https://vault.bitwarden.com/icons",
isIconLoadingDisabled = false,
isAutofill = true,
hasMasterPassword = true,
)
} returns expectedViewState
val dataState = DataState.Loaded(
@@ -1351,6 +1367,7 @@ private val DEFAULT_STATE: SearchState = SearchState(
baseWebSendUrl = "https://vault.bitwarden.com/#/send/",
baseIconUrl = "https://vault.bitwarden.com/icons",
isIconLoadingDisabled = false,
hasMasterPassword = true,
)
private val DEFAULT_USER_STATE = UserState(
@@ -271,6 +271,7 @@ class SearchTypeDataExtensionsTest {
baseIconUrl = "www.test.com",
isIconLoadingDisabled = false,
isAutofill = false,
hasMasterPassword = true,
)
assertEquals(SearchState.ViewState.Empty(message = null), result)
@@ -294,6 +295,7 @@ class SearchTypeDataExtensionsTest {
baseIconUrl = "https://vault.bitwarden.com/icons",
isIconLoadingDisabled = false,
isAutofill = false,
hasMasterPassword = true,
)
assertEquals(
@@ -332,6 +334,7 @@ class SearchTypeDataExtensionsTest {
baseIconUrl = "https://vault.bitwarden.com/icons",
isIconLoadingDisabled = false,
isAutofill = true,
hasMasterPassword = true,
)
assertEquals(
@@ -380,6 +383,7 @@ class SearchTypeDataExtensionsTest {
baseIconUrl = "www.test.com",
isIconLoadingDisabled = false,
isAutofill = false,
hasMasterPassword = true,
)
assertEquals(
@@ -42,12 +42,16 @@ fun createMockDisplayItemForCipher(
),
overflowOptions = listOf(
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"),
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
ListingItemOverflowAction.VaultAction.EditClick(
cipherId = "mockId-$number",
requiresPasswordReprompt = true,
),
ListingItemOverflowAction.VaultAction.CopyUsernameClick(
username = "mockUsername-$number",
),
ListingItemOverflowAction.VaultAction.CopyPasswordClick(
password = "mockPassword-$number",
requiresPasswordReprompt = true,
),
ListingItemOverflowAction.VaultAction.CopyTotpClick(
totpCode = "mockTotp-$number",
@@ -85,7 +89,10 @@ fun createMockDisplayItemForCipher(
),
overflowOptions = listOf(
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"),
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
ListingItemOverflowAction.VaultAction.EditClick(
cipherId = "mockId-$number",
requiresPasswordReprompt = true,
),
ListingItemOverflowAction.VaultAction.CopyNoteClick(
notes = "mockNotes-$number",
),
@@ -119,12 +126,17 @@ fun createMockDisplayItemForCipher(
),
overflowOptions = listOf(
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"),
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
ListingItemOverflowAction.VaultAction.EditClick(
cipherId = "mockId-$number",
requiresPasswordReprompt = true,
),
ListingItemOverflowAction.VaultAction.CopyNumberClick(
number = "mockNumber-$number",
requiresPasswordReprompt = true,
),
ListingItemOverflowAction.VaultAction.CopySecurityCodeClick(
securityCode = "mockCode-$number",
requiresPasswordReprompt = true,
),
),
overflowTestTag = "CipherOptionsButton",
@@ -156,7 +168,10 @@ fun createMockDisplayItemForCipher(
),
overflowOptions = listOf(
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"),
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
ListingItemOverflowAction.VaultAction.EditClick(
cipherId = "mockId-$number",
requiresPasswordReprompt = true,
),
),
overflowTestTag = "CipherOptionsButton",
totpCode = null,
@@ -142,6 +142,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns DEFAULT_VIEW_STATE
@@ -163,6 +164,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
verify(exactly = 1) {
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
}
@@ -180,6 +182,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns loginState
@@ -221,6 +224,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns loginState
@@ -251,6 +255,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
} returns loginViewState
@@ -292,6 +297,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns loginViewState
@@ -336,6 +342,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
} returns loginViewState
@@ -374,6 +381,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
} returns DEFAULT_VIEW_STATE
@@ -412,6 +420,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
} returns DEFAULT_VIEW_STATE
@@ -459,6 +468,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
} returns DEFAULT_VIEW_STATE
@@ -489,6 +499,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns loginViewState
@@ -521,6 +532,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns loginViewState
@@ -582,6 +594,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns loginViewState
@@ -633,6 +646,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns loginViewState
@@ -695,6 +709,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns DEFAULT_VIEW_STATE
@@ -716,6 +731,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
verify(exactly = 1) {
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
}
@@ -729,6 +745,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns createViewState(common = DEFAULT_COMMON.copy(requiresReprompt = false))
@@ -744,6 +761,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
clipboardManager.setText(text = field)
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
}
@@ -776,6 +794,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns DEFAULT_VIEW_STATE
@@ -805,6 +824,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
verify(exactly = 1) {
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
}
@@ -835,6 +855,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns loginViewState
@@ -864,6 +885,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
verify(exactly = 1) {
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
}
@@ -877,6 +899,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns DEFAULT_VIEW_STATE
@@ -898,6 +921,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
verify(exactly = 1) {
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
}
@@ -915,6 +939,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns loginViewState
@@ -947,6 +972,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns loginViewState
@@ -970,6 +996,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
verify(exactly = 1) {
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
}
@@ -991,6 +1018,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns loginViewState
@@ -1037,6 +1065,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns DEFAULT_VIEW_STATE
@@ -1058,6 +1087,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
verify(exactly = 1) {
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
}
@@ -1075,6 +1105,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns loginViewState
@@ -1104,6 +1135,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns DEFAULT_VIEW_STATE
@@ -1125,6 +1157,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
verify(exactly = 1) {
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
}
@@ -1142,6 +1175,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns loginViewState
@@ -1182,6 +1216,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns loginViewState
@@ -1236,6 +1271,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns loginViewState
@@ -1299,6 +1335,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns loginViewState
@@ -1475,6 +1512,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
} returns DEFAULT_VIEW_STATE
@@ -1513,6 +1551,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
verify(exactly = 1) {
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
}
@@ -1529,6 +1568,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
} returns DEFAULT_VIEW_STATE
@@ -1553,6 +1593,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
verify(exactly = 1) {
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
}
@@ -1565,6 +1606,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
} returns createViewState(common = DEFAULT_COMMON.copy(requiresReprompt = false))
@@ -1581,6 +1623,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
clipboardManager.setText(text = DEFAULT_LOGIN_PASSWORD)
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
}
@@ -1619,6 +1662,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
} returns createViewState(common = DEFAULT_COMMON.copy(requiresReprompt = false))
@@ -1633,6 +1677,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
clipboardManager.setText(text = DEFAULT_LOGIN_USERNAME)
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
}
@@ -1655,6 +1700,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
} returns DEFAULT_VIEW_STATE
@@ -1677,6 +1723,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
verify(exactly = 1) {
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
}
@@ -1690,6 +1737,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
}
@@ -1714,6 +1762,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
verify(exactly = 1) {
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
}
@@ -1728,6 +1777,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
} returns DEFAULT_VIEW_STATE
@@ -1754,6 +1804,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
verify(exactly = 1) {
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
}
@@ -1771,6 +1822,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
} returns loginViewState
@@ -1800,6 +1852,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
verify(exactly = 1) {
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = createTotpCodeData(),
)
}
@@ -1827,6 +1880,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns CARD_VIEW_STATE
@@ -1850,6 +1904,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
verify(exactly = 1) {
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
}
@@ -1862,6 +1917,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns createViewState(
@@ -1879,6 +1935,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
clipboardManager.setText(text = "12345436")
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
}
@@ -1892,6 +1949,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns CARD_VIEW_STATE
@@ -1915,6 +1973,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
verify(exactly = 1) {
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
}
@@ -1927,6 +1986,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
every {
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns createViewState(
@@ -1944,6 +2004,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
clipboardManager.setText(text = "987")
mockCipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
}
@@ -1975,7 +2036,11 @@ class VaultItemViewModelTest : BaseViewModelTest() {
val viewState = mockk<VaultItemState.ViewState>()
val cipherView = mockk<CipherView> {
every {
toViewState(isPremiumUser = true, totpCodeItemData = null)
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns viewState
}
val viewModel = createViewModel(state = null)
@@ -2006,7 +2071,11 @@ class VaultItemViewModelTest : BaseViewModelTest() {
val viewState = mockk<VaultItemState.ViewState>()
val cipherView = mockk<CipherView> {
every {
toViewState(isPremiumUser = true, totpCodeItemData = null)
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns viewState
}
val viewModel = createViewModel(state = null)
@@ -2038,7 +2107,11 @@ class VaultItemViewModelTest : BaseViewModelTest() {
val viewState = mockk<VaultItemState.ViewState>()
val cipherView = mockk<CipherView> {
every {
toViewState(isPremiumUser = true, totpCodeItemData = null)
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns viewState
}
val viewModel = createViewModel(state = null)
@@ -2069,7 +2142,11 @@ class VaultItemViewModelTest : BaseViewModelTest() {
val viewState = mockk<VaultItemState.ViewState>()
val cipherView = mockk<CipherView> {
every {
toViewState(isPremiumUser = true, totpCodeItemData = null)
toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
)
} returns viewState
}
val viewModel = createViewModel(state = null)
@@ -16,12 +16,41 @@ class CipherViewExtensionsTest {
ZoneOffset.UTC,
)
@Suppress("MaxLineLength")
@Test
fun `toViewState should transform full CipherView into ViewState Login Content without master password reprompt`() {
val cipherView = createCipherView(type = CipherType.LOGIN, isEmpty = false)
val viewState = cipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = false,
totpCodeItemData = TotpCodeItemData(
periodSeconds = 30,
timeLeftSeconds = 15,
verificationCode = "123456",
totpCode = "testCode",
),
clock = fixedClock,
)
assertEquals(
VaultItemState.ViewState.Content(
common = createCommonContent(isEmpty = false, isPremiumUser = true).copy(
currentCipher = cipherView,
requiresReprompt = false,
),
type = createLoginContent(isEmpty = false),
),
viewState,
)
}
@Test
fun `toViewState should transform full CipherView into ViewState Login Content with premium`() {
val cipherView = createCipherView(type = CipherType.LOGIN, isEmpty = false)
val viewState = cipherView.toViewState(
isPremiumUser = true,
TotpCodeItemData(
hasMasterPassword = true,
totpCodeItemData = TotpCodeItemData(
periodSeconds = 30,
timeLeftSeconds = 15,
verificationCode = "123456",
@@ -47,6 +76,7 @@ class CipherViewExtensionsTest {
val cipherView = createCipherView(type = CipherType.LOGIN, isEmpty = false)
val viewState = cipherView.toViewState(
isPremiumUser = isPremiumUser,
hasMasterPassword = true,
totpCodeItemData = TotpCodeItemData(
periodSeconds = 30,
timeLeftSeconds = 15,
@@ -71,6 +101,7 @@ class CipherViewExtensionsTest {
val cipherView = createCipherView(type = CipherType.LOGIN, isEmpty = true)
val viewState = cipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
clock = fixedClock,
)
@@ -91,6 +122,7 @@ class CipherViewExtensionsTest {
val cipherView = createCipherView(type = CipherType.IDENTITY, isEmpty = false)
val viewState = cipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
clock = fixedClock,
)
@@ -110,6 +142,7 @@ class CipherViewExtensionsTest {
val cipherView = createCipherView(type = CipherType.IDENTITY, isEmpty = true)
val viewState = cipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
clock = fixedClock,
)
@@ -139,6 +172,7 @@ class CipherViewExtensionsTest {
)
val viewState = cipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
clock = fixedClock,
)
@@ -173,6 +207,7 @@ class CipherViewExtensionsTest {
)
val result = cipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
clock = fixedClock,
)
@@ -209,6 +244,7 @@ class CipherViewExtensionsTest {
val cipherView = createCipherView(type = CipherType.SECURE_NOTE, isEmpty = false)
val viewState = cipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
clock = fixedClock,
)
@@ -229,6 +265,7 @@ class CipherViewExtensionsTest {
val cipherView = createCipherView(type = CipherType.SECURE_NOTE, isEmpty = true)
val viewState = cipherView.toViewState(
isPremiumUser = true,
hasMasterPassword = true,
totpCodeItemData = null,
clock = fixedClock,
)
@@ -1196,6 +1196,7 @@ class VaultItemListingScreenTest : BaseComposeTest() {
VaultItemListingsAction.OverflowOptionClick(
action = ListingItemOverflowAction.VaultAction.EditClick(
cipherId = "mockId-1",
requiresPasswordReprompt = true,
),
),
)
@@ -1508,6 +1509,7 @@ private val DEFAULT_STATE = VaultItemListingState(
isPullToRefreshSettingEnabled = false,
dialogState = null,
policyDisablesSend = false,
hasMasterPassword = true,
)
private val STATE_FOR_AUTOFILL = DEFAULT_STATE.copy(
@@ -1567,7 +1569,10 @@ private fun createCipherDisplayItem(number: Int): VaultItemListingState.DisplayI
iconData = IconData.Local(R.drawable.ic_vault),
extraIconList = emptyList(),
overflowOptions = listOf(
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
ListingItemOverflowAction.VaultAction.EditClick(
cipherId = "mockId-$number",
requiresPasswordReprompt = true,
),
),
optionsTestTag = "CipherOptionsButton",
isAutofill = false,
@@ -448,6 +448,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
masterPasswordRepromptData = MasterPasswordRepromptData.OverflowItem(
action = ListingItemOverflowAction.VaultAction.EditClick(
cipherId = cipherId,
requiresPasswordReprompt = true,
),
),
),
@@ -688,7 +689,10 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
val viewModel = createVaultItemListingViewModel()
viewModel.trySendAction(
VaultItemListingsAction.OverflowOptionClick(
ListingItemOverflowAction.VaultAction.CopyNumberClick(number = number),
ListingItemOverflowAction.VaultAction.CopyNumberClick(
number = number,
requiresPasswordReprompt = true,
),
),
)
verify(exactly = 1) {
@@ -704,7 +708,10 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
val viewModel = createVaultItemListingViewModel()
viewModel.trySendAction(
VaultItemListingsAction.OverflowOptionClick(
ListingItemOverflowAction.VaultAction.CopyPasswordClick(password = password),
ListingItemOverflowAction.VaultAction.CopyPasswordClick(
password = password,
requiresPasswordReprompt = true,
),
),
)
verify(exactly = 1) {
@@ -722,6 +729,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
VaultItemListingsAction.OverflowOptionClick(
ListingItemOverflowAction.VaultAction.CopySecurityCodeClick(
securityCode = securityCode,
requiresPasswordReprompt = true,
),
),
)
@@ -800,7 +808,10 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
viewModel.eventFlow.test {
viewModel.trySendAction(
VaultItemListingsAction.OverflowOptionClick(
ListingItemOverflowAction.VaultAction.EditClick(cipherId = cipherId),
ListingItemOverflowAction.VaultAction.EditClick(
cipherId = cipherId,
requiresPasswordReprompt = true,
),
),
)
assertEquals(VaultItemListingEvent.NavigateToEditCipher(cipherId), awaitItem())
@@ -1443,6 +1454,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
autofillSelectionData = null,
shouldFinishOnComplete = false,
policyDisablesSend = false,
hasMasterPassword = true,
)
}
@@ -393,6 +393,7 @@ class VaultItemListingDataExtensionsTest {
isIconLoadingDisabled = false,
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
autofillSelectionData = null,
hasMasterPassword = true,
)
assertEquals(
@@ -466,6 +467,7 @@ class VaultItemListingDataExtensionsTest {
type = AutofillSelectionData.Type.LOGIN,
uri = null,
),
hasMasterPassword = true,
)
assertEquals(
@@ -516,6 +518,7 @@ class VaultItemListingDataExtensionsTest {
isIconLoadingDisabled = false,
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
autofillSelectionData = null,
hasMasterPassword = true,
),
)
@@ -533,6 +536,7 @@ class VaultItemListingDataExtensionsTest {
isIconLoadingDisabled = false,
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
autofillSelectionData = null,
hasMasterPassword = true,
),
)
@@ -548,6 +552,7 @@ class VaultItemListingDataExtensionsTest {
isIconLoadingDisabled = false,
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
autofillSelectionData = null,
hasMasterPassword = true,
),
)
@@ -566,6 +571,7 @@ class VaultItemListingDataExtensionsTest {
type = AutofillSelectionData.Type.LOGIN,
uri = "https://www.test.com",
),
hasMasterPassword = true,
),
)
}
@@ -704,6 +710,7 @@ class VaultItemListingDataExtensionsTest {
autofillSelectionData = null,
itemListingType = VaultItemListingState.ItemListingType.Vault.Folder("1"),
vaultFilterType = VaultFilterType.AllVaults,
hasMasterPassword = true,
)
assertEquals(
@@ -743,6 +750,7 @@ class VaultItemListingDataExtensionsTest {
autofillSelectionData = null,
itemListingType = VaultItemListingState.ItemListingType.Vault.Collection("mockId-1"),
vaultFilterType = VaultFilterType.AllVaults,
hasMasterPassword = true,
)
assertEquals(
@@ -43,12 +43,16 @@ fun createMockDisplayItemForCipher(
),
overflowOptions = listOf(
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"),
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
ListingItemOverflowAction.VaultAction.EditClick(
cipherId = "mockId-$number",
requiresPasswordReprompt = true,
),
ListingItemOverflowAction.VaultAction.CopyUsernameClick(
username = "mockUsername-$number",
),
ListingItemOverflowAction.VaultAction.CopyPasswordClick(
password = "mockPassword-$number",
requiresPasswordReprompt = true,
),
ListingItemOverflowAction.VaultAction.CopyTotpClick(
totpCode = "mockTotp-$number",
@@ -86,7 +90,10 @@ fun createMockDisplayItemForCipher(
),
overflowOptions = listOf(
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"),
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
ListingItemOverflowAction.VaultAction.EditClick(
cipherId = "mockId-$number",
requiresPasswordReprompt = true,
),
ListingItemOverflowAction.VaultAction.CopyNoteClick(
notes = "mockNotes-$number",
),
@@ -120,12 +127,17 @@ fun createMockDisplayItemForCipher(
),
overflowOptions = listOf(
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"),
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
ListingItemOverflowAction.VaultAction.EditClick(
cipherId = "mockId-$number",
requiresPasswordReprompt = true,
),
ListingItemOverflowAction.VaultAction.CopyNumberClick(
number = "mockNumber-$number",
requiresPasswordReprompt = true,
),
ListingItemOverflowAction.VaultAction.CopySecurityCodeClick(
securityCode = "mockCode-$number",
requiresPasswordReprompt = true,
),
),
optionsTestTag = "CipherOptionsButton",
@@ -157,7 +169,10 @@ fun createMockDisplayItemForCipher(
),
overflowOptions = listOf(
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"),
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
ListingItemOverflowAction.VaultAction.EditClick(
cipherId = "mockId-$number",
requiresPasswordReprompt = true,
),
),
optionsTestTag = "CipherOptionsButton",
isAutofill = false,
@@ -31,14 +31,20 @@ class CipherViewExtensionsTest {
),
)
val result = cipher.toOverflowActions()
val result = cipher.toOverflowActions(hasMasterPassword = false)
assertEquals(
listOf(
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id),
ListingItemOverflowAction.VaultAction.EditClick(cipherId = id),
ListingItemOverflowAction.VaultAction.EditClick(
cipherId = id,
requiresPasswordReprompt = false,
),
ListingItemOverflowAction.VaultAction.CopyUsernameClick(username = username),
ListingItemOverflowAction.VaultAction.CopyPasswordClick(password = password),
ListingItemOverflowAction.VaultAction.CopyPasswordClick(
password = password,
requiresPasswordReprompt = false,
),
ListingItemOverflowAction.VaultAction.CopyTotpClick(totpCode = totpCode),
ListingItemOverflowAction.VaultAction.LaunchClick(url = uri),
),
@@ -63,12 +69,15 @@ class CipherViewExtensionsTest {
),
viewPassword = false,
)
val result = cipher.toOverflowActions()
val result = cipher.toOverflowActions(hasMasterPassword = true)
assertEquals(
listOf(
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id),
ListingItemOverflowAction.VaultAction.EditClick(cipherId = id),
ListingItemOverflowAction.VaultAction.EditClick(
cipherId = id,
requiresPasswordReprompt = true,
),
ListingItemOverflowAction.VaultAction.CopyUsernameClick(username = username),
ListingItemOverflowAction.VaultAction.CopyTotpClick(totpCode = totpCode),
ListingItemOverflowAction.VaultAction.LaunchClick(url = uri),
@@ -95,7 +104,7 @@ class CipherViewExtensionsTest {
),
)
val result = cipher.toOverflowActions()
val result = cipher.toOverflowActions(hasMasterPassword = true)
assertEquals(
listOf(ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id)),
@@ -116,15 +125,22 @@ class CipherViewExtensionsTest {
),
)
val result = cipher.toOverflowActions()
val result = cipher.toOverflowActions(hasMasterPassword = true)
assertEquals(
listOf(
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id),
ListingItemOverflowAction.VaultAction.EditClick(cipherId = id),
ListingItemOverflowAction.VaultAction.CopyNumberClick(number = number),
ListingItemOverflowAction.VaultAction.EditClick(
cipherId = id,
requiresPasswordReprompt = true,
),
ListingItemOverflowAction.VaultAction.CopyNumberClick(
number = number,
requiresPasswordReprompt = true,
),
ListingItemOverflowAction.VaultAction.CopySecurityCodeClick(
securityCode = securityCode,
requiresPasswordReprompt = true,
),
),
result,
@@ -147,7 +163,7 @@ class CipherViewExtensionsTest {
),
)
val result = cipher.toOverflowActions()
val result = cipher.toOverflowActions(hasMasterPassword = false)
assertEquals(
listOf(ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id)),
@@ -163,12 +179,15 @@ class CipherViewExtensionsTest {
identity = createMockIdentityView(number = 1),
)
val result = cipher.toOverflowActions()
val result = cipher.toOverflowActions(hasMasterPassword = false)
assertEquals(
listOf(
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id),
ListingItemOverflowAction.VaultAction.EditClick(cipherId = id),
ListingItemOverflowAction.VaultAction.EditClick(
cipherId = id,
requiresPasswordReprompt = false,
),
),
result,
)
@@ -187,7 +206,7 @@ class CipherViewExtensionsTest {
identity = createMockIdentityView(number = 1),
)
val result = cipher.toOverflowActions()
val result = cipher.toOverflowActions(hasMasterPassword = true)
assertEquals(
listOf(ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id)),
@@ -205,12 +224,15 @@ class CipherViewExtensionsTest {
notes = notes,
)
val result = cipher.toOverflowActions()
val result = cipher.toOverflowActions(hasMasterPassword = true)
assertEquals(
listOf(
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id),
ListingItemOverflowAction.VaultAction.EditClick(cipherId = id),
ListingItemOverflowAction.VaultAction.EditClick(
cipherId = id,
requiresPasswordReprompt = true,
),
ListingItemOverflowAction.VaultAction.CopyNoteClick(notes = notes),
),
result,
@@ -231,7 +253,7 @@ class CipherViewExtensionsTest {
notes = null,
)
val result = cipher.toOverflowActions()
val result = cipher.toOverflowActions(hasMasterPassword = false)
assertEquals(
listOf(ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id)),
@@ -1177,6 +1177,7 @@ private val DEFAULT_STATE: VaultState = VaultState(
isPullToRefreshSettingEnabled = false,
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
isIconLoadingDisabled = false,
hasMasterPassword = true,
)
private val DEFAULT_CONTENT_VIEW_STATE: VaultState.ViewState.Content = VaultState.ViewState.Content(
@@ -476,6 +476,7 @@ class VaultViewModelTest : BaseViewModelTest() {
vaultFilterType = VaultFilterType.AllVaults,
isIconLoadingDisabled = viewModel.stateFlow.value.isIconLoadingDisabled,
baseIconUrl = viewModel.stateFlow.value.baseIconUrl,
hasMasterPassword = true,
),
)
.copy(
@@ -499,6 +500,7 @@ class VaultViewModelTest : BaseViewModelTest() {
vaultFilterType = VaultFilterType.MyVault,
isIconLoadingDisabled = viewModel.stateFlow.value.isIconLoadingDisabled,
baseIconUrl = viewModel.stateFlow.value.baseIconUrl,
hasMasterPassword = true,
),
),
viewModel.stateFlow.value,
@@ -1186,7 +1188,10 @@ class VaultViewModelTest : BaseViewModelTest() {
val viewModel = createViewModel()
viewModel.trySendAction(
VaultAction.OverflowOptionClick(
ListingItemOverflowAction.VaultAction.CopyNumberClick(number = number),
ListingItemOverflowAction.VaultAction.CopyNumberClick(
number = number,
requiresPasswordReprompt = true,
),
),
)
verify(exactly = 1) {
@@ -1202,7 +1207,10 @@ class VaultViewModelTest : BaseViewModelTest() {
val viewModel = createViewModel()
viewModel.trySendAction(
VaultAction.OverflowOptionClick(
ListingItemOverflowAction.VaultAction.CopyPasswordClick(password = password),
ListingItemOverflowAction.VaultAction.CopyPasswordClick(
password = password,
requiresPasswordReprompt = true,
),
),
)
verify(exactly = 1) {
@@ -1265,6 +1273,7 @@ class VaultViewModelTest : BaseViewModelTest() {
VaultAction.OverflowOptionClick(
ListingItemOverflowAction.VaultAction.CopySecurityCodeClick(
securityCode = securityCode,
requiresPasswordReprompt = true,
),
),
)
@@ -1298,7 +1307,10 @@ class VaultViewModelTest : BaseViewModelTest() {
viewModel.eventFlow.test {
viewModel.trySendAction(
VaultAction.OverflowOptionClick(
ListingItemOverflowAction.VaultAction.EditClick(cipherId = cipherId),
ListingItemOverflowAction.VaultAction.EditClick(
cipherId = cipherId,
requiresPasswordReprompt = true,
),
),
)
assertEquals(VaultEvent.NavigateToEditVaultItem(cipherId), awaitItem())
@@ -1352,6 +1364,7 @@ class VaultViewModelTest : BaseViewModelTest() {
VaultAction.MasterPasswordRepromptSubmit(
overflowAction = ListingItemOverflowAction.VaultAction.CopyPasswordClick(
password = password,
requiresPasswordReprompt = true,
),
password = password,
),
@@ -1389,6 +1402,7 @@ class VaultViewModelTest : BaseViewModelTest() {
VaultAction.MasterPasswordRepromptSubmit(
overflowAction = ListingItemOverflowAction.VaultAction.CopyPasswordClick(
password = password,
requiresPasswordReprompt = true,
),
password = password,
),
@@ -1421,6 +1435,7 @@ class VaultViewModelTest : BaseViewModelTest() {
VaultAction.MasterPasswordRepromptSubmit(
overflowAction = ListingItemOverflowAction.VaultAction.CopyPasswordClick(
password = password,
requiresPasswordReprompt = true,
),
password = password,
),
@@ -1532,4 +1547,5 @@ private fun createMockVaultState(
isPullToRefreshSettingEnabled = false,
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
isIconLoadingDisabled = false,
hasMasterPassword = true,
)
@@ -55,6 +55,7 @@ class VaultDataExtensionsTest {
isIconLoadingDisabled = false,
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
vaultFilterType = VaultFilterType.AllVaults,
hasMasterPassword = true,
)
assertEquals(
@@ -115,6 +116,7 @@ class VaultDataExtensionsTest {
isIconLoadingDisabled = false,
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
vaultFilterType = VaultFilterType.MyVault,
hasMasterPassword = true,
)
assertEquals(
@@ -167,6 +169,7 @@ class VaultDataExtensionsTest {
organizationId = "mockOrganizationId-1",
organizationName = "Mock Organization 1",
),
hasMasterPassword = true,
)
assertEquals(
@@ -212,6 +215,7 @@ class VaultDataExtensionsTest {
isIconLoadingDisabled = false,
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
vaultFilterType = VaultFilterType.AllVaults,
hasMasterPassword = true,
)
assertEquals(
@@ -234,6 +238,7 @@ class VaultDataExtensionsTest {
isIconLoadingDisabled = false,
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
vaultFilterType = VaultFilterType.AllVaults,
hasMasterPassword = true,
)
assertEquals(
@@ -257,6 +262,7 @@ class VaultDataExtensionsTest {
isIconLoadingDisabled = false,
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
vaultFilterType = VaultFilterType.AllVaults,
hasMasterPassword = true,
)
assertEquals(
@@ -291,6 +297,7 @@ class VaultDataExtensionsTest {
vaultFilterType = VaultFilterType.AllVaults,
isIconLoadingDisabled = false,
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
hasMasterPassword = true,
)
assertEquals(
@@ -439,6 +446,7 @@ class VaultDataExtensionsTest {
isIconLoadingDisabled = false,
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
vaultFilterType = VaultFilterType.AllVaults,
hasMasterPassword = true,
)
assertEquals(
@@ -479,6 +487,7 @@ class VaultDataExtensionsTest {
isIconLoadingDisabled = false,
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
vaultFilterType = VaultFilterType.AllVaults,
hasMasterPassword = true,
)
assertEquals(
@@ -531,6 +540,7 @@ class VaultDataExtensionsTest {
isIconLoadingDisabled = false,
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
vaultFilterType = VaultFilterType.AllVaults,
hasMasterPassword = true,
)
assertEquals(