mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 07:05:35 +03:00
[PM-9844] Android - Non-Premium Users Can Copy TOTP Code From Item Menu (#3539)
This commit is contained in:
parent
f1c486bf9a
commit
3d584c84f2
13 changed files with 120 additions and 36 deletions
|
@ -101,6 +101,7 @@ class SearchViewModel @Inject constructor(
|
||||||
isIconLoadingDisabled = settingsRepo.isIconLoadingDisabled,
|
isIconLoadingDisabled = settingsRepo.isIconLoadingDisabled,
|
||||||
autofillSelectionData = autofillSelectionData,
|
autofillSelectionData = autofillSelectionData,
|
||||||
hasMasterPassword = userState.activeAccount.hasMasterPassword,
|
hasMasterPassword = userState.activeAccount.hasMasterPassword,
|
||||||
|
isPremium = userState.activeAccount.isPremium,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
@ -657,6 +658,7 @@ class SearchViewModel @Inject constructor(
|
||||||
baseIconUrl = state.baseIconUrl,
|
baseIconUrl = state.baseIconUrl,
|
||||||
isIconLoadingDisabled = state.isIconLoadingDisabled,
|
isIconLoadingDisabled = state.isIconLoadingDisabled,
|
||||||
isAutofill = state.isAutofill,
|
isAutofill = state.isAutofill,
|
||||||
|
isPremiumUser = state.isPremium,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,6 +703,7 @@ data class SearchState(
|
||||||
// Internal
|
// Internal
|
||||||
val autofillSelectionData: AutofillSelectionData? = null,
|
val autofillSelectionData: AutofillSelectionData? = null,
|
||||||
val hasMasterPassword: Boolean,
|
val hasMasterPassword: Boolean,
|
||||||
|
val isPremium: Boolean,
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -140,12 +140,14 @@ private fun CipherView.matchedSearch(searchTerm: String): SortPriority? {
|
||||||
/**
|
/**
|
||||||
* Transforms a list of [CipherView] into [SearchState.ViewState].
|
* Transforms a list of [CipherView] into [SearchState.ViewState].
|
||||||
*/
|
*/
|
||||||
|
@Suppress("LongParameterList")
|
||||||
fun List<CipherView>.toViewState(
|
fun List<CipherView>.toViewState(
|
||||||
searchTerm: String,
|
searchTerm: String,
|
||||||
baseIconUrl: String,
|
baseIconUrl: String,
|
||||||
hasMasterPassword: Boolean,
|
hasMasterPassword: Boolean,
|
||||||
isIconLoadingDisabled: Boolean,
|
isIconLoadingDisabled: Boolean,
|
||||||
isAutofill: Boolean,
|
isAutofill: Boolean,
|
||||||
|
isPremiumUser: Boolean,
|
||||||
): SearchState.ViewState =
|
): SearchState.ViewState =
|
||||||
when {
|
when {
|
||||||
searchTerm.isEmpty() -> SearchState.ViewState.Empty(message = null)
|
searchTerm.isEmpty() -> SearchState.ViewState.Empty(message = null)
|
||||||
|
@ -156,6 +158,7 @@ fun List<CipherView>.toViewState(
|
||||||
hasMasterPassword = hasMasterPassword,
|
hasMasterPassword = hasMasterPassword,
|
||||||
isIconLoadingDisabled = isIconLoadingDisabled,
|
isIconLoadingDisabled = isIconLoadingDisabled,
|
||||||
isAutofill = isAutofill,
|
isAutofill = isAutofill,
|
||||||
|
isPremiumUser = isPremiumUser,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -172,6 +175,7 @@ private fun List<CipherView>.toDisplayItemList(
|
||||||
hasMasterPassword: Boolean,
|
hasMasterPassword: Boolean,
|
||||||
isIconLoadingDisabled: Boolean,
|
isIconLoadingDisabled: Boolean,
|
||||||
isAutofill: Boolean,
|
isAutofill: Boolean,
|
||||||
|
isPremiumUser: Boolean,
|
||||||
): List<SearchState.DisplayItem> =
|
): List<SearchState.DisplayItem> =
|
||||||
this.map {
|
this.map {
|
||||||
it.toDisplayItem(
|
it.toDisplayItem(
|
||||||
|
@ -179,6 +183,7 @@ private fun List<CipherView>.toDisplayItemList(
|
||||||
hasMasterPassword = hasMasterPassword,
|
hasMasterPassword = hasMasterPassword,
|
||||||
isIconLoadingDisabled = isIconLoadingDisabled,
|
isIconLoadingDisabled = isIconLoadingDisabled,
|
||||||
isAutofill = isAutofill,
|
isAutofill = isAutofill,
|
||||||
|
isPremiumUser = isPremiumUser,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,6 +192,7 @@ private fun CipherView.toDisplayItem(
|
||||||
hasMasterPassword: Boolean,
|
hasMasterPassword: Boolean,
|
||||||
isIconLoadingDisabled: Boolean,
|
isIconLoadingDisabled: Boolean,
|
||||||
isAutofill: Boolean,
|
isAutofill: Boolean,
|
||||||
|
isPremiumUser: Boolean,
|
||||||
): SearchState.DisplayItem =
|
): SearchState.DisplayItem =
|
||||||
SearchState.DisplayItem(
|
SearchState.DisplayItem(
|
||||||
id = id.orEmpty(),
|
id = id.orEmpty(),
|
||||||
|
@ -199,7 +205,10 @@ private fun CipherView.toDisplayItem(
|
||||||
isIconLoadingDisabled = isIconLoadingDisabled,
|
isIconLoadingDisabled = isIconLoadingDisabled,
|
||||||
),
|
),
|
||||||
extraIconList = toLabelIcons(),
|
extraIconList = toLabelIcons(),
|
||||||
overflowOptions = toOverflowActions(hasMasterPassword = hasMasterPassword),
|
overflowOptions = toOverflowActions(
|
||||||
|
hasMasterPassword = hasMasterPassword,
|
||||||
|
isPremiumUser = isPremiumUser,
|
||||||
|
),
|
||||||
overflowTestTag = "CipherOptionsButton",
|
overflowTestTag = "CipherOptionsButton",
|
||||||
totpCode = login?.totp,
|
totpCode = login?.totp,
|
||||||
autofillSelectionOptions = AutofillSelectionOption
|
autofillSelectionOptions = AutofillSelectionOption
|
||||||
|
|
|
@ -123,6 +123,7 @@ class VaultItemListingViewModel @Inject constructor(
|
||||||
shouldFinishOnComplete = shouldFinishOnComplete,
|
shouldFinishOnComplete = shouldFinishOnComplete,
|
||||||
hasMasterPassword = userState.activeAccount.hasMasterPassword,
|
hasMasterPassword = userState.activeAccount.hasMasterPassword,
|
||||||
fido2CredentialRequest = fido2CreationData?.fido2CredentialRequest,
|
fido2CredentialRequest = fido2CreationData?.fido2CredentialRequest,
|
||||||
|
isPremium = userState.activeAccount.isPremium,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
@ -1008,6 +1009,7 @@ class VaultItemListingViewModel @Inject constructor(
|
||||||
fido2CreationData = state.fido2CredentialRequest,
|
fido2CreationData = state.fido2CredentialRequest,
|
||||||
fido2CredentialAutofillViews = vaultData
|
fido2CredentialAutofillViews = vaultData
|
||||||
.fido2CredentialAutofillViewList,
|
.fido2CredentialAutofillViewList,
|
||||||
|
isPremiumUser = state.isPremium,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1127,6 +1129,7 @@ data class VaultItemListingState(
|
||||||
val fido2CredentialRequest: Fido2CredentialRequest? = null,
|
val fido2CredentialRequest: Fido2CredentialRequest? = null,
|
||||||
val shouldFinishOnComplete: Boolean = false,
|
val shouldFinishOnComplete: Boolean = false,
|
||||||
val hasMasterPassword: Boolean,
|
val hasMasterPassword: Boolean,
|
||||||
|
val isPremium: Boolean,
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* Whether or not this represents a listing screen for autofill.
|
* Whether or not this represents a listing screen for autofill.
|
||||||
|
|
|
@ -104,6 +104,7 @@ fun VaultData.toViewState(
|
||||||
autofillSelectionData: AutofillSelectionData?,
|
autofillSelectionData: AutofillSelectionData?,
|
||||||
fido2CreationData: Fido2CredentialRequest?,
|
fido2CreationData: Fido2CredentialRequest?,
|
||||||
fido2CredentialAutofillViews: List<Fido2CredentialAutofillView>?,
|
fido2CredentialAutofillViews: List<Fido2CredentialAutofillView>?,
|
||||||
|
isPremiumUser: Boolean,
|
||||||
): VaultItemListingState.ViewState {
|
): VaultItemListingState.ViewState {
|
||||||
val filteredCipherViewList = cipherViewList
|
val filteredCipherViewList = cipherViewList
|
||||||
.filter { cipherView ->
|
.filter { cipherView ->
|
||||||
|
@ -133,6 +134,7 @@ fun VaultData.toViewState(
|
||||||
isAutofill = autofillSelectionData != null,
|
isAutofill = autofillSelectionData != null,
|
||||||
isFido2Creation = fido2CreationData != null,
|
isFido2Creation = fido2CreationData != null,
|
||||||
fido2CredentialAutofillViews = fido2CredentialAutofillViews,
|
fido2CredentialAutofillViews = fido2CredentialAutofillViews,
|
||||||
|
isPremiumUser = isPremiumUser,
|
||||||
),
|
),
|
||||||
displayFolderList = folderList.map { folderView ->
|
displayFolderList = folderList.map { folderView ->
|
||||||
VaultItemListingState.FolderDisplayItem(
|
VaultItemListingState.FolderDisplayItem(
|
||||||
|
@ -271,6 +273,7 @@ private fun List<CipherView>.toDisplayItemList(
|
||||||
isAutofill: Boolean,
|
isAutofill: Boolean,
|
||||||
isFido2Creation: Boolean,
|
isFido2Creation: Boolean,
|
||||||
fido2CredentialAutofillViews: List<Fido2CredentialAutofillView>?,
|
fido2CredentialAutofillViews: List<Fido2CredentialAutofillView>?,
|
||||||
|
isPremiumUser: Boolean,
|
||||||
): List<VaultItemListingState.DisplayItem> =
|
): List<VaultItemListingState.DisplayItem> =
|
||||||
this.map {
|
this.map {
|
||||||
it.toDisplayItem(
|
it.toDisplayItem(
|
||||||
|
@ -283,6 +286,7 @@ private fun List<CipherView>.toDisplayItemList(
|
||||||
?.firstOrNull { fido2CredentialAutofillView ->
|
?.firstOrNull { fido2CredentialAutofillView ->
|
||||||
fido2CredentialAutofillView.cipherId == it.id
|
fido2CredentialAutofillView.cipherId == it.id
|
||||||
},
|
},
|
||||||
|
isPremiumUser = isPremiumUser,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,6 +309,7 @@ private fun CipherView.toDisplayItem(
|
||||||
isAutofill: Boolean,
|
isAutofill: Boolean,
|
||||||
isFido2Creation: Boolean,
|
isFido2Creation: Boolean,
|
||||||
fido2CredentialAutofillView: Fido2CredentialAutofillView?,
|
fido2CredentialAutofillView: Fido2CredentialAutofillView?,
|
||||||
|
isPremiumUser: Boolean,
|
||||||
): VaultItemListingState.DisplayItem =
|
): VaultItemListingState.DisplayItem =
|
||||||
VaultItemListingState.DisplayItem(
|
VaultItemListingState.DisplayItem(
|
||||||
id = id.orEmpty(),
|
id = id.orEmpty(),
|
||||||
|
@ -325,7 +330,10 @@ private fun CipherView.toDisplayItem(
|
||||||
),
|
),
|
||||||
iconTestTag = this.toIconTestTag(),
|
iconTestTag = this.toIconTestTag(),
|
||||||
extraIconList = this.toLabelIcons(),
|
extraIconList = this.toLabelIcons(),
|
||||||
overflowOptions = this.toOverflowActions(hasMasterPassword = hasMasterPassword),
|
overflowOptions = this.toOverflowActions(
|
||||||
|
hasMasterPassword = hasMasterPassword,
|
||||||
|
isPremiumUser = isPremiumUser,
|
||||||
|
),
|
||||||
optionsTestTag = "CipherOptionsButton",
|
optionsTestTag = "CipherOptionsButton",
|
||||||
isAutofill = isAutofill,
|
isAutofill = isAutofill,
|
||||||
isFido2Creation = isFido2Creation,
|
isFido2Creation = isFido2Creation,
|
||||||
|
|
|
@ -11,6 +11,7 @@ import com.x8bit.bitwarden.ui.vault.model.VaultTrailingIcon
|
||||||
*/
|
*/
|
||||||
fun CipherView.toOverflowActions(
|
fun CipherView.toOverflowActions(
|
||||||
hasMasterPassword: Boolean,
|
hasMasterPassword: Boolean,
|
||||||
|
isPremiumUser: Boolean,
|
||||||
): List<ListingItemOverflowAction.VaultAction> =
|
): List<ListingItemOverflowAction.VaultAction> =
|
||||||
this
|
this
|
||||||
.id
|
.id
|
||||||
|
@ -36,7 +37,10 @@ fun CipherView.toOverflowActions(
|
||||||
.takeIf { this.viewPassword },
|
.takeIf { this.viewPassword },
|
||||||
this.login?.totp
|
this.login?.totp
|
||||||
?.let { ListingItemOverflowAction.VaultAction.CopyTotpClick(totpCode = it) }
|
?.let { ListingItemOverflowAction.VaultAction.CopyTotpClick(totpCode = it) }
|
||||||
.takeIf { this.type == CipherType.LOGIN },
|
.takeIf {
|
||||||
|
this.type == CipherType.LOGIN &&
|
||||||
|
(this.organizationUseTotp || isPremiumUser)
|
||||||
|
},
|
||||||
this.card?.number?.let {
|
this.card?.number?.let {
|
||||||
ListingItemOverflowAction.VaultAction.CopyNumberClick(
|
ListingItemOverflowAction.VaultAction.CopyNumberClick(
|
||||||
number = it,
|
number = it,
|
||||||
|
|
|
@ -83,6 +83,7 @@ fun VaultData.toViewState(
|
||||||
hasMasterPassword = hasMasterPassword,
|
hasMasterPassword = hasMasterPassword,
|
||||||
isIconLoadingDisabled = isIconLoadingDisabled,
|
isIconLoadingDisabled = isIconLoadingDisabled,
|
||||||
baseIconUrl = baseIconUrl,
|
baseIconUrl = baseIconUrl,
|
||||||
|
isPremiumUser = isPremium,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
folderItems = filteredFolderViewList
|
folderItems = filteredFolderViewList
|
||||||
|
@ -116,6 +117,7 @@ fun VaultData.toViewState(
|
||||||
hasMasterPassword = hasMasterPassword,
|
hasMasterPassword = hasMasterPassword,
|
||||||
isIconLoadingDisabled = isIconLoadingDisabled,
|
isIconLoadingDisabled = isIconLoadingDisabled,
|
||||||
baseIconUrl = baseIconUrl,
|
baseIconUrl = baseIconUrl,
|
||||||
|
isPremiumUser = isPremium,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.takeIf { it.size < NO_FOLDER_ITEM_THRESHOLD }
|
.takeIf { it.size < NO_FOLDER_ITEM_THRESHOLD }
|
||||||
|
@ -189,11 +191,12 @@ fun List<LoginUriView>?.toLoginIconData(
|
||||||
/**
|
/**
|
||||||
* Transforms a [CipherView] into a [VaultState.ViewState.VaultItem].
|
* Transforms a [CipherView] into a [VaultState.ViewState.VaultItem].
|
||||||
*/
|
*/
|
||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber", "LongMethod")
|
||||||
private fun CipherView.toVaultItemOrNull(
|
private fun CipherView.toVaultItemOrNull(
|
||||||
hasMasterPassword: Boolean,
|
hasMasterPassword: Boolean,
|
||||||
isIconLoadingDisabled: Boolean,
|
isIconLoadingDisabled: Boolean,
|
||||||
baseIconUrl: String,
|
baseIconUrl: String,
|
||||||
|
isPremiumUser: Boolean,
|
||||||
): VaultState.ViewState.VaultItem? {
|
): VaultState.ViewState.VaultItem? {
|
||||||
val id = this.id ?: return null
|
val id = this.id ?: return null
|
||||||
return when (type) {
|
return when (type) {
|
||||||
|
@ -206,7 +209,10 @@ private fun CipherView.toVaultItemOrNull(
|
||||||
baseIconUrl = baseIconUrl,
|
baseIconUrl = baseIconUrl,
|
||||||
usePasskeyDefaultIcon = false,
|
usePasskeyDefaultIcon = false,
|
||||||
),
|
),
|
||||||
overflowOptions = toOverflowActions(hasMasterPassword = hasMasterPassword),
|
overflowOptions = toOverflowActions(
|
||||||
|
hasMasterPassword = hasMasterPassword,
|
||||||
|
isPremiumUser = isPremiumUser,
|
||||||
|
),
|
||||||
extraIconList = toLabelIcons(),
|
extraIconList = toLabelIcons(),
|
||||||
shouldShowMasterPasswordReprompt = reprompt == CipherRepromptType.PASSWORD,
|
shouldShowMasterPasswordReprompt = reprompt == CipherRepromptType.PASSWORD,
|
||||||
)
|
)
|
||||||
|
@ -214,7 +220,10 @@ private fun CipherView.toVaultItemOrNull(
|
||||||
CipherType.SECURE_NOTE -> VaultState.ViewState.VaultItem.SecureNote(
|
CipherType.SECURE_NOTE -> VaultState.ViewState.VaultItem.SecureNote(
|
||||||
id = id,
|
id = id,
|
||||||
name = name.asText(),
|
name = name.asText(),
|
||||||
overflowOptions = toOverflowActions(hasMasterPassword = hasMasterPassword),
|
overflowOptions = toOverflowActions(
|
||||||
|
hasMasterPassword = hasMasterPassword,
|
||||||
|
isPremiumUser = isPremiumUser,
|
||||||
|
),
|
||||||
extraIconList = toLabelIcons(),
|
extraIconList = toLabelIcons(),
|
||||||
shouldShowMasterPasswordReprompt = reprompt == CipherRepromptType.PASSWORD,
|
shouldShowMasterPasswordReprompt = reprompt == CipherRepromptType.PASSWORD,
|
||||||
)
|
)
|
||||||
|
@ -226,7 +235,10 @@ private fun CipherView.toVaultItemOrNull(
|
||||||
lastFourDigits = card?.number
|
lastFourDigits = card?.number
|
||||||
?.takeLast(4)
|
?.takeLast(4)
|
||||||
?.asText(),
|
?.asText(),
|
||||||
overflowOptions = toOverflowActions(hasMasterPassword = hasMasterPassword),
|
overflowOptions = toOverflowActions(
|
||||||
|
hasMasterPassword = hasMasterPassword,
|
||||||
|
isPremiumUser = isPremiumUser,
|
||||||
|
),
|
||||||
extraIconList = toLabelIcons(),
|
extraIconList = toLabelIcons(),
|
||||||
shouldShowMasterPasswordReprompt = reprompt == CipherRepromptType.PASSWORD,
|
shouldShowMasterPasswordReprompt = reprompt == CipherRepromptType.PASSWORD,
|
||||||
)
|
)
|
||||||
|
@ -240,7 +252,10 @@ private fun CipherView.toVaultItemOrNull(
|
||||||
else -> "${identity?.firstName} ${identity?.lastName}"
|
else -> "${identity?.firstName} ${identity?.lastName}"
|
||||||
}
|
}
|
||||||
?.asText(),
|
?.asText(),
|
||||||
overflowOptions = toOverflowActions(hasMasterPassword = hasMasterPassword),
|
overflowOptions = toOverflowActions(
|
||||||
|
hasMasterPassword = hasMasterPassword,
|
||||||
|
isPremiumUser = isPremiumUser,
|
||||||
|
),
|
||||||
extraIconList = toLabelIcons(),
|
extraIconList = toLabelIcons(),
|
||||||
shouldShowMasterPasswordReprompt = reprompt == CipherRepromptType.PASSWORD,
|
shouldShowMasterPasswordReprompt = reprompt == CipherRepromptType.PASSWORD,
|
||||||
)
|
)
|
||||||
|
|
|
@ -887,6 +887,7 @@ private val DEFAULT_STATE: SearchState = SearchState(
|
||||||
baseIconUrl = "www.test.com",
|
baseIconUrl = "www.test.com",
|
||||||
isIconLoadingDisabled = false,
|
isIconLoadingDisabled = false,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
|
isPremium = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun createStateForAutofill(
|
private fun createStateForAutofill(
|
||||||
|
|
|
@ -861,6 +861,7 @@ class SearchViewModelTest : BaseViewModelTest() {
|
||||||
isIconLoadingDisabled = false,
|
isIconLoadingDisabled = false,
|
||||||
isAutofill = false,
|
isAutofill = false,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
|
isPremiumUser = true,
|
||||||
)
|
)
|
||||||
} returns expectedViewState
|
} returns expectedViewState
|
||||||
val dataState = DataState.Loaded(
|
val dataState = DataState.Loaded(
|
||||||
|
@ -962,6 +963,7 @@ class SearchViewModelTest : BaseViewModelTest() {
|
||||||
isIconLoadingDisabled = false,
|
isIconLoadingDisabled = false,
|
||||||
isAutofill = false,
|
isAutofill = false,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
|
isPremiumUser = true,
|
||||||
)
|
)
|
||||||
} returns expectedViewState
|
} returns expectedViewState
|
||||||
mutableVaultDataStateFlow.tryEmit(
|
mutableVaultDataStateFlow.tryEmit(
|
||||||
|
@ -1073,6 +1075,7 @@ class SearchViewModelTest : BaseViewModelTest() {
|
||||||
isIconLoadingDisabled = false,
|
isIconLoadingDisabled = false,
|
||||||
isAutofill = false,
|
isAutofill = false,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
|
isPremiumUser = true,
|
||||||
)
|
)
|
||||||
} returns expectedViewState
|
} returns expectedViewState
|
||||||
val dataState = DataState.Error(
|
val dataState = DataState.Error(
|
||||||
|
@ -1187,6 +1190,7 @@ class SearchViewModelTest : BaseViewModelTest() {
|
||||||
isIconLoadingDisabled = false,
|
isIconLoadingDisabled = false,
|
||||||
isAutofill = false,
|
isAutofill = false,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
|
isPremiumUser = true,
|
||||||
)
|
)
|
||||||
} returns expectedViewState
|
} returns expectedViewState
|
||||||
val dataState = DataState.NoNetwork(
|
val dataState = DataState.NoNetwork(
|
||||||
|
@ -1355,6 +1359,7 @@ class SearchViewModelTest : BaseViewModelTest() {
|
||||||
isIconLoadingDisabled = false,
|
isIconLoadingDisabled = false,
|
||||||
isAutofill = true,
|
isAutofill = true,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
|
isPremiumUser = true,
|
||||||
)
|
)
|
||||||
} returns expectedViewState
|
} returns expectedViewState
|
||||||
val dataState = DataState.Loaded(
|
val dataState = DataState.Loaded(
|
||||||
|
@ -1387,6 +1392,7 @@ private val DEFAULT_STATE: SearchState = SearchState(
|
||||||
baseIconUrl = "https://vault.bitwarden.com/icons",
|
baseIconUrl = "https://vault.bitwarden.com/icons",
|
||||||
isIconLoadingDisabled = false,
|
isIconLoadingDisabled = false,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
|
isPremium = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
private val DEFAULT_USER_STATE = UserState(
|
private val DEFAULT_USER_STATE = UserState(
|
||||||
|
|
|
@ -298,6 +298,7 @@ class SearchTypeDataExtensionsTest {
|
||||||
isIconLoadingDisabled = false,
|
isIconLoadingDisabled = false,
|
||||||
isAutofill = false,
|
isAutofill = false,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
|
isPremiumUser = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(SearchState.ViewState.Empty(message = null), result)
|
assertEquals(SearchState.ViewState.Empty(message = null), result)
|
||||||
|
@ -322,6 +323,7 @@ class SearchTypeDataExtensionsTest {
|
||||||
isIconLoadingDisabled = false,
|
isIconLoadingDisabled = false,
|
||||||
isAutofill = false,
|
isAutofill = false,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
|
isPremiumUser = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
@ -361,6 +363,7 @@ class SearchTypeDataExtensionsTest {
|
||||||
isIconLoadingDisabled = false,
|
isIconLoadingDisabled = false,
|
||||||
isAutofill = true,
|
isAutofill = true,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
|
isPremiumUser = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
@ -410,6 +413,7 @@ class SearchTypeDataExtensionsTest {
|
||||||
isIconLoadingDisabled = false,
|
isIconLoadingDisabled = false,
|
||||||
isAutofill = false,
|
isAutofill = false,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
|
isPremiumUser = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
|
|
@ -1713,6 +1713,7 @@ private val DEFAULT_STATE = VaultItemListingState(
|
||||||
dialogState = null,
|
dialogState = null,
|
||||||
policyDisablesSend = false,
|
policyDisablesSend = false,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
|
isPremium = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
private val STATE_FOR_AUTOFILL = DEFAULT_STATE.copy(
|
private val STATE_FOR_AUTOFILL = DEFAULT_STATE.copy(
|
||||||
|
|
|
@ -2374,6 +2374,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||||
policyDisablesSend = false,
|
policyDisablesSend = false,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
fido2CredentialRequest = null,
|
fido2CredentialRequest = null,
|
||||||
|
isPremium = true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -400,6 +400,7 @@ class VaultItemListingDataExtensionsTest {
|
||||||
fido2CreationData = null,
|
fido2CreationData = null,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
fido2CredentialAutofillViews = null,
|
fido2CredentialAutofillViews = null,
|
||||||
|
isPremiumUser = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
@ -488,6 +489,7 @@ class VaultItemListingDataExtensionsTest {
|
||||||
fido2CreationData = null,
|
fido2CreationData = null,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
fido2CredentialAutofillViews = fido2CredentialAutofillViews,
|
fido2CredentialAutofillViews = fido2CredentialAutofillViews,
|
||||||
|
isPremiumUser = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
@ -553,6 +555,7 @@ class VaultItemListingDataExtensionsTest {
|
||||||
fido2CreationData = null,
|
fido2CreationData = null,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
fido2CredentialAutofillViews = null,
|
fido2CredentialAutofillViews = null,
|
||||||
|
isPremiumUser = true,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -574,6 +577,7 @@ class VaultItemListingDataExtensionsTest {
|
||||||
fido2CreationData = null,
|
fido2CreationData = null,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
fido2CredentialAutofillViews = null,
|
fido2CredentialAutofillViews = null,
|
||||||
|
isPremiumUser = true,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -593,6 +597,7 @@ class VaultItemListingDataExtensionsTest {
|
||||||
fido2CreationData = null,
|
fido2CreationData = null,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
fido2CredentialAutofillViews = null,
|
fido2CredentialAutofillViews = null,
|
||||||
|
isPremiumUser = true,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -615,6 +620,7 @@ class VaultItemListingDataExtensionsTest {
|
||||||
fido2CreationData = null,
|
fido2CreationData = null,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
fido2CredentialAutofillViews = null,
|
fido2CredentialAutofillViews = null,
|
||||||
|
isPremiumUser = true,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -640,6 +646,7 @@ class VaultItemListingDataExtensionsTest {
|
||||||
),
|
),
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
fido2CredentialAutofillViews = null,
|
fido2CredentialAutofillViews = null,
|
||||||
|
isPremiumUser = true,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -781,6 +788,7 @@ class VaultItemListingDataExtensionsTest {
|
||||||
fido2CreationData = null,
|
fido2CreationData = null,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
fido2CredentialAutofillViews = null,
|
fido2CredentialAutofillViews = null,
|
||||||
|
isPremiumUser = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
@ -823,6 +831,7 @@ class VaultItemListingDataExtensionsTest {
|
||||||
fido2CreationData = null,
|
fido2CreationData = null,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
fido2CredentialAutofillViews = null,
|
fido2CredentialAutofillViews = null,
|
||||||
|
isPremiumUser = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
|
|
@ -16,12 +16,7 @@ import org.junit.jupiter.api.Test
|
||||||
class CipherViewExtensionsTest {
|
class CipherViewExtensionsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `toOverflowActions should return all actions for a login cipher`() {
|
fun `toOverflowActions should return all actions for a login cipher when a user has premium`() {
|
||||||
val id = "mockId-1"
|
|
||||||
val username = "Bitwarden"
|
|
||||||
val password = "password"
|
|
||||||
val totpCode = "mockTotp-1"
|
|
||||||
val uri = "www.test.com"
|
|
||||||
val cipher = createMockCipherView(number = 1, cipherType = CipherType.LOGIN).copy(
|
val cipher = createMockCipherView(number = 1, cipherType = CipherType.LOGIN).copy(
|
||||||
id = id,
|
id = id,
|
||||||
login = createMockLoginView(number = 1).copy(
|
login = createMockLoginView(number = 1).copy(
|
||||||
|
@ -31,7 +26,7 @@ class CipherViewExtensionsTest {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
val result = cipher.toOverflowActions(hasMasterPassword = false)
|
val result = cipher.toOverflowActions(hasMasterPassword = false, isPremiumUser = true)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
listOf(
|
listOf(
|
||||||
|
@ -53,14 +48,41 @@ class CipherViewExtensionsTest {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `toOverflowActions should not return TOTP action when a user does not have premium`() {
|
||||||
|
val cipher = createMockCipherView(number = 1, cipherType = CipherType.LOGIN).copy(
|
||||||
|
id = id,
|
||||||
|
login = createMockLoginView(number = 1).copy(
|
||||||
|
username = username,
|
||||||
|
password = password,
|
||||||
|
uris = listOf(createMockUriView(number = 1).copy(uri = uri)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
val result = cipher.toOverflowActions(hasMasterPassword = false, isPremiumUser = false)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
listOf(
|
||||||
|
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id),
|
||||||
|
ListingItemOverflowAction.VaultAction.EditClick(
|
||||||
|
cipherId = id,
|
||||||
|
requiresPasswordReprompt = false,
|
||||||
|
),
|
||||||
|
ListingItemOverflowAction.VaultAction.CopyUsernameClick(username = username),
|
||||||
|
ListingItemOverflowAction.VaultAction.CopyPasswordClick(
|
||||||
|
password = password,
|
||||||
|
requiresPasswordReprompt = false,
|
||||||
|
cipherId = id,
|
||||||
|
),
|
||||||
|
ListingItemOverflowAction.VaultAction.LaunchClick(url = uri),
|
||||||
|
),
|
||||||
|
result,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("MaxLineLength")
|
@Suppress("MaxLineLength")
|
||||||
@Test
|
@Test
|
||||||
fun `toOverflowActions should return the correct actions when viewPassword is false for a login cipher`() {
|
fun `toOverflowActions should return the correct actions when viewPassword is false for a login cipher`() {
|
||||||
val id = "mockId-1"
|
|
||||||
val username = "Bitwarden"
|
|
||||||
val password = "password"
|
|
||||||
val totpCode = "mockTotp-1"
|
|
||||||
val uri = "www.test.com"
|
|
||||||
val cipher = createMockCipherView(number = 1, cipherType = CipherType.LOGIN).copy(
|
val cipher = createMockCipherView(number = 1, cipherType = CipherType.LOGIN).copy(
|
||||||
id = id,
|
id = id,
|
||||||
login = createMockLoginView(number = 1).copy(
|
login = createMockLoginView(number = 1).copy(
|
||||||
|
@ -70,7 +92,7 @@ class CipherViewExtensionsTest {
|
||||||
),
|
),
|
||||||
viewPassword = false,
|
viewPassword = false,
|
||||||
)
|
)
|
||||||
val result = cipher.toOverflowActions(hasMasterPassword = true)
|
val result = cipher.toOverflowActions(hasMasterPassword = true, isPremiumUser = false)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
listOf(
|
listOf(
|
||||||
|
@ -80,7 +102,6 @@ class CipherViewExtensionsTest {
|
||||||
requiresPasswordReprompt = true,
|
requiresPasswordReprompt = true,
|
||||||
),
|
),
|
||||||
ListingItemOverflowAction.VaultAction.CopyUsernameClick(username = username),
|
ListingItemOverflowAction.VaultAction.CopyUsernameClick(username = username),
|
||||||
ListingItemOverflowAction.VaultAction.CopyTotpClick(totpCode = totpCode),
|
|
||||||
ListingItemOverflowAction.VaultAction.LaunchClick(url = uri),
|
ListingItemOverflowAction.VaultAction.LaunchClick(url = uri),
|
||||||
),
|
),
|
||||||
result,
|
result,
|
||||||
|
@ -89,7 +110,6 @@ class CipherViewExtensionsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `toOverflowActions should return minimum actions for a login cipher`() {
|
fun `toOverflowActions should return minimum actions for a login cipher`() {
|
||||||
val id = "mockId-1"
|
|
||||||
val cipher = createMockCipherView(
|
val cipher = createMockCipherView(
|
||||||
number = 1,
|
number = 1,
|
||||||
isDeleted = true,
|
isDeleted = true,
|
||||||
|
@ -105,7 +125,7 @@ class CipherViewExtensionsTest {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
val result = cipher.toOverflowActions(hasMasterPassword = true)
|
val result = cipher.toOverflowActions(hasMasterPassword = true, isPremiumUser = false)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
listOf(ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id)),
|
listOf(ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id)),
|
||||||
|
@ -115,7 +135,6 @@ class CipherViewExtensionsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `toOverflowActions should return all actions for a card cipher`() {
|
fun `toOverflowActions should return all actions for a card cipher`() {
|
||||||
val id = "mockId-1"
|
|
||||||
val number = "1322-2414-7634-2354"
|
val number = "1322-2414-7634-2354"
|
||||||
val securityCode = "123"
|
val securityCode = "123"
|
||||||
val cipher = createMockCipherView(number = 1, cipherType = CipherType.CARD).copy(
|
val cipher = createMockCipherView(number = 1, cipherType = CipherType.CARD).copy(
|
||||||
|
@ -126,7 +145,7 @@ class CipherViewExtensionsTest {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
val result = cipher.toOverflowActions(hasMasterPassword = true)
|
val result = cipher.toOverflowActions(hasMasterPassword = true, isPremiumUser = false)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
listOf(
|
listOf(
|
||||||
|
@ -151,7 +170,6 @@ class CipherViewExtensionsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `toOverflowActions should return minimum actions for a card cipher`() {
|
fun `toOverflowActions should return minimum actions for a card cipher`() {
|
||||||
val id = "mockId-1"
|
|
||||||
val cipher = createMockCipherView(
|
val cipher = createMockCipherView(
|
||||||
number = 1,
|
number = 1,
|
||||||
isDeleted = true,
|
isDeleted = true,
|
||||||
|
@ -165,7 +183,7 @@ class CipherViewExtensionsTest {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
val result = cipher.toOverflowActions(hasMasterPassword = false)
|
val result = cipher.toOverflowActions(hasMasterPassword = false, isPremiumUser = false)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
listOf(ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id)),
|
listOf(ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id)),
|
||||||
|
@ -175,13 +193,12 @@ class CipherViewExtensionsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `toOverflowActions should return all actions for a identity cipher`() {
|
fun `toOverflowActions should return all actions for a identity cipher`() {
|
||||||
val id = "mockId-1"
|
|
||||||
val cipher = createMockCipherView(number = 1, cipherType = CipherType.IDENTITY).copy(
|
val cipher = createMockCipherView(number = 1, cipherType = CipherType.IDENTITY).copy(
|
||||||
id = id,
|
id = id,
|
||||||
identity = createMockIdentityView(number = 1),
|
identity = createMockIdentityView(number = 1),
|
||||||
)
|
)
|
||||||
|
|
||||||
val result = cipher.toOverflowActions(hasMasterPassword = false)
|
val result = cipher.toOverflowActions(hasMasterPassword = false, isPremiumUser = false)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
listOf(
|
listOf(
|
||||||
|
@ -197,7 +214,6 @@ class CipherViewExtensionsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `toOverflowActions should return minimum actions for a identity cipher`() {
|
fun `toOverflowActions should return minimum actions for a identity cipher`() {
|
||||||
val id = "mockId-1"
|
|
||||||
val cipher = createMockCipherView(
|
val cipher = createMockCipherView(
|
||||||
number = 1,
|
number = 1,
|
||||||
isDeleted = true,
|
isDeleted = true,
|
||||||
|
@ -208,7 +224,7 @@ class CipherViewExtensionsTest {
|
||||||
identity = createMockIdentityView(number = 1),
|
identity = createMockIdentityView(number = 1),
|
||||||
)
|
)
|
||||||
|
|
||||||
val result = cipher.toOverflowActions(hasMasterPassword = true)
|
val result = cipher.toOverflowActions(hasMasterPassword = true, false)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
listOf(ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id)),
|
listOf(ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id)),
|
||||||
|
@ -218,7 +234,6 @@ class CipherViewExtensionsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `toOverflowActions should return all actions for a secure note cipher`() {
|
fun `toOverflowActions should return all actions for a secure note cipher`() {
|
||||||
val id = "mockId-1"
|
|
||||||
val notes = "so secure"
|
val notes = "so secure"
|
||||||
val cipher = createMockCipherView(number = 1, cipherType = CipherType.SECURE_NOTE).copy(
|
val cipher = createMockCipherView(number = 1, cipherType = CipherType.SECURE_NOTE).copy(
|
||||||
id = id,
|
id = id,
|
||||||
|
@ -226,7 +241,7 @@ class CipherViewExtensionsTest {
|
||||||
notes = notes,
|
notes = notes,
|
||||||
)
|
)
|
||||||
|
|
||||||
val result = cipher.toOverflowActions(hasMasterPassword = true)
|
val result = cipher.toOverflowActions(hasMasterPassword = true, isPremiumUser = false)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
listOf(
|
listOf(
|
||||||
|
@ -243,7 +258,6 @@ class CipherViewExtensionsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `toOverflowActions should return minimum actions for a secure note cipher`() {
|
fun `toOverflowActions should return minimum actions for a secure note cipher`() {
|
||||||
val id = "mockId-1"
|
|
||||||
val cipher = createMockCipherView(
|
val cipher = createMockCipherView(
|
||||||
number = 1,
|
number = 1,
|
||||||
isDeleted = true,
|
isDeleted = true,
|
||||||
|
@ -255,7 +269,7 @@ class CipherViewExtensionsTest {
|
||||||
notes = null,
|
notes = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
val result = cipher.toOverflowActions(hasMasterPassword = false)
|
val result = cipher.toOverflowActions(hasMasterPassword = false, isPremiumUser = false)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
listOf(ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id)),
|
listOf(ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id)),
|
||||||
|
@ -358,3 +372,9 @@ class CipherViewExtensionsTest {
|
||||||
assertEquals(expected, result)
|
assertEquals(expected, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const val id = "mockId-1"
|
||||||
|
private const val username = "Bitwarden"
|
||||||
|
private const val password = "password"
|
||||||
|
private const val totpCode = "mockTotp-1"
|
||||||
|
private const val uri = "www.test.com"
|
||||||
|
|
Loading…
Reference in a new issue