mirror of
https://github.com/bitwarden/android.git
synced 2025-12-12 00:08:00 -06:00
Remove the RemoveCardPolicy feature flag (#5770)
This commit is contained in:
parent
a1c6276092
commit
517829e7b0
@ -30,7 +30,6 @@ fun <T : Any> FlagKey<T>.ListItemContent(
|
|||||||
FlagKey.CredentialExchangeProtocolExport,
|
FlagKey.CredentialExchangeProtocolExport,
|
||||||
FlagKey.CipherKeyEncryption,
|
FlagKey.CipherKeyEncryption,
|
||||||
FlagKey.UserManagedPrivilegedApps,
|
FlagKey.UserManagedPrivilegedApps,
|
||||||
FlagKey.RemoveCardPolicy,
|
|
||||||
-> {
|
-> {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
BooleanFlagItem(
|
BooleanFlagItem(
|
||||||
@ -79,7 +78,6 @@ private fun <T : Any> FlagKey<T>.getDisplayLabel(): String = when (this) {
|
|||||||
stringResource(BitwardenString.user_trusted_privileged_app_management)
|
stringResource(BitwardenString.user_trusted_privileged_app_management)
|
||||||
}
|
}
|
||||||
|
|
||||||
FlagKey.RemoveCardPolicy -> stringResource(BitwardenString.remove_card_policy)
|
|
||||||
FlagKey.BitwardenAuthenticationEnabled -> {
|
FlagKey.BitwardenAuthenticationEnabled -> {
|
||||||
stringResource(BitwardenString.bitwarden_authentication_enabled)
|
stringResource(BitwardenString.bitwarden_authentication_enabled)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import android.os.Parcelable
|
|||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.bitwarden.annotation.OmitFromCoverage
|
import com.bitwarden.annotation.OmitFromCoverage
|
||||||
import com.bitwarden.core.data.manager.model.FlagKey
|
|
||||||
import com.bitwarden.core.data.repository.model.DataState
|
import com.bitwarden.core.data.repository.model.DataState
|
||||||
import com.bitwarden.data.repository.util.baseIconUrl
|
import com.bitwarden.data.repository.util.baseIconUrl
|
||||||
import com.bitwarden.data.repository.util.baseWebSendUrl
|
import com.bitwarden.data.repository.util.baseWebSendUrl
|
||||||
@ -27,7 +26,6 @@ import com.x8bit.bitwarden.data.autofill.accessibility.manager.AccessibilitySele
|
|||||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillSelectionManager
|
import com.x8bit.bitwarden.data.autofill.manager.AutofillSelectionManager
|
||||||
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
||||||
import com.x8bit.bitwarden.data.autofill.util.login
|
import com.x8bit.bitwarden.data.autofill.util.login
|
||||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
|
||||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||||
@ -69,8 +67,6 @@ import kotlinx.collections.immutable.ImmutableList
|
|||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
|
||||||
import kotlinx.coroutines.flow.flowOf
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
@ -99,7 +95,6 @@ class SearchViewModel @Inject constructor(
|
|||||||
private val organizationEventManager: OrganizationEventManager,
|
private val organizationEventManager: OrganizationEventManager,
|
||||||
private val vaultRepo: VaultRepository,
|
private val vaultRepo: VaultRepository,
|
||||||
private val authRepo: AuthRepository,
|
private val authRepo: AuthRepository,
|
||||||
featureFlagManager: FeatureFlagManager,
|
|
||||||
environmentRepo: EnvironmentRepository,
|
environmentRepo: EnvironmentRepository,
|
||||||
settingsRepo: SettingsRepository,
|
settingsRepo: SettingsRepository,
|
||||||
snackbarRelayManager: SnackbarRelayManager,
|
snackbarRelayManager: SnackbarRelayManager,
|
||||||
@ -155,24 +150,10 @@ class SearchViewModel @Inject constructor(
|
|||||||
.onEach(::sendAction)
|
.onEach(::sendAction)
|
||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
|
|
||||||
featureFlagManager
|
policyManager
|
||||||
.getFeatureFlagFlow(FlagKey.RemoveCardPolicy)
|
.getActivePoliciesFlow(type = PolicyTypeJson.RESTRICT_ITEM_TYPES)
|
||||||
.flatMapLatest { isFlagEnabled ->
|
.map { policies -> policies.map { it.organizationId } }
|
||||||
if (isFlagEnabled) {
|
.map { SearchAction.Internal.RestrictItemTypesPolicyUpdateReceive(it) }
|
||||||
policyManager
|
|
||||||
.getActivePoliciesFlow(type = PolicyTypeJson.RESTRICT_ITEM_TYPES)
|
|
||||||
.map { policies ->
|
|
||||||
policies.map { it.organizationId }
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
flowOf(emptyList<String>())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.map { organizationIds ->
|
|
||||||
SearchAction.Internal.RestrictItemTypesPolicyUpdateReceive(
|
|
||||||
restrictItemTypesPolicyOrdIds = organizationIds,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.onEach(::sendAction)
|
.onEach(::sendAction)
|
||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import android.net.Uri
|
|||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.bitwarden.core.data.manager.model.FlagKey
|
|
||||||
import com.bitwarden.core.data.util.toFormattedPattern
|
import com.bitwarden.core.data.util.toFormattedPattern
|
||||||
import com.bitwarden.network.model.PolicyTypeJson
|
import com.bitwarden.network.model.PolicyTypeJson
|
||||||
import com.bitwarden.ui.platform.base.BaseViewModel
|
import com.bitwarden.ui.platform.base.BaseViewModel
|
||||||
@ -19,7 +18,6 @@ import com.x8bit.bitwarden.data.auth.repository.model.PasswordStrengthResult
|
|||||||
import com.x8bit.bitwarden.data.auth.repository.model.RequestOtpResult
|
import com.x8bit.bitwarden.data.auth.repository.model.RequestOtpResult
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult
|
import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.VerifyOtpResult
|
import com.x8bit.bitwarden.data.auth.repository.model.VerifyOtpResult
|
||||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
|
||||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager
|
import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent
|
import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent
|
||||||
@ -55,7 +53,6 @@ class ExportVaultViewModel @Inject constructor(
|
|||||||
private val vaultRepository: VaultRepository,
|
private val vaultRepository: VaultRepository,
|
||||||
private val fileManager: FileManager,
|
private val fileManager: FileManager,
|
||||||
private val clock: Clock,
|
private val clock: Clock,
|
||||||
private val featureFlagManager: FeatureFlagManager,
|
|
||||||
private val organizationEventManager: OrganizationEventManager,
|
private val organizationEventManager: OrganizationEventManager,
|
||||||
) : BaseViewModel<ExportVaultState, ExportVaultEvent, ExportVaultAction>(
|
) : BaseViewModel<ExportVaultState, ExportVaultEvent, ExportVaultAction>(
|
||||||
initialState = savedStateHandle[KEY_STATE]
|
initialState = savedStateHandle[KEY_STATE]
|
||||||
@ -467,19 +464,14 @@ class ExportVaultViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getRestrictedItemTypes(): List<CipherType> {
|
private fun getRestrictedItemTypes(): List<CipherType> {
|
||||||
val isRemoveCardPolicyFeatureEnabled =
|
val hasActiveRestrictItemTypesPolicy = policyManager
|
||||||
featureFlagManager.getFeatureFlag(FlagKey.RemoveCardPolicy)
|
.getActivePolicies(type = PolicyTypeJson.RESTRICT_ITEM_TYPES)
|
||||||
if (!isRemoveCardPolicyFeatureEnabled) {
|
.isNotEmpty()
|
||||||
return emptyList()
|
return if (!hasActiveRestrictItemTypesPolicy) {
|
||||||
|
emptyList()
|
||||||
|
} else {
|
||||||
|
listOf(CipherType.CARD)
|
||||||
}
|
}
|
||||||
|
|
||||||
val hasActiveRestrictItemTypesPolicy =
|
|
||||||
policyManager.getActivePolicies(type = PolicyTypeJson.RESTRICT_ITEM_TYPES).isNotEmpty()
|
|
||||||
if (!hasActiveRestrictItemTypesPolicy) {
|
|
||||||
return emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
return listOf(CipherType.CARD)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,7 +526,7 @@ sealed class ExportVaultEvent {
|
|||||||
data object NavigateBack : ExportVaultEvent()
|
data object NavigateBack : ExportVaultEvent()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a toast with the given [message].
|
* Shows a toast with the given [data].
|
||||||
*/
|
*/
|
||||||
data class ShowSnackbar(
|
data class ShowSnackbar(
|
||||||
val data: BitwardenSnackbarData,
|
val data: BitwardenSnackbarData,
|
||||||
|
|||||||
@ -110,7 +110,6 @@ import kotlinx.collections.immutable.ImmutableList
|
|||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.combine
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
@ -212,15 +211,7 @@ class VaultItemListingViewModel @Inject constructor(
|
|||||||
|
|
||||||
policyManager
|
policyManager
|
||||||
.getActivePoliciesFlow(type = PolicyTypeJson.RESTRICT_ITEM_TYPES)
|
.getActivePoliciesFlow(type = PolicyTypeJson.RESTRICT_ITEM_TYPES)
|
||||||
.combine(
|
.map { policies -> policies.map { it.organizationId } }
|
||||||
featureFlagManager.getFeatureFlagFlow(FlagKey.RemoveCardPolicy),
|
|
||||||
) { policies, enabledFlag ->
|
|
||||||
if (enabledFlag) {
|
|
||||||
policies.map { it.organizationId }
|
|
||||||
} else {
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.map { VaultItemListingsAction.Internal.RestrictItemTypesPolicyUpdateReceive(it) }
|
.map { VaultItemListingsAction.Internal.RestrictItemTypesPolicyUpdateReceive(it) }
|
||||||
.onEach(::sendAction)
|
.onEach(::sendAction)
|
||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package com.x8bit.bitwarden.ui.vault.feature.vault
|
|||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.bitwarden.core.data.manager.model.FlagKey
|
|
||||||
import com.bitwarden.core.data.repository.model.DataState
|
import com.bitwarden.core.data.repository.model.DataState
|
||||||
import com.bitwarden.core.util.persistentListOfNotNull
|
import com.bitwarden.core.util.persistentListOfNotNull
|
||||||
import com.bitwarden.data.repository.util.baseIconUrl
|
import com.bitwarden.data.repository.util.baseIconUrl
|
||||||
@ -28,7 +27,6 @@ import com.x8bit.bitwarden.data.auth.repository.model.SwitchAccountResult
|
|||||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult
|
import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult
|
||||||
import com.x8bit.bitwarden.data.platform.datasource.disk.model.FlightRecorderDataSet
|
import com.x8bit.bitwarden.data.platform.datasource.disk.model.FlightRecorderDataSet
|
||||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
|
||||||
import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager
|
import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.ReviewPromptManager
|
import com.x8bit.bitwarden.data.platform.manager.ReviewPromptManager
|
||||||
@ -67,7 +65,6 @@ import kotlinx.collections.immutable.ImmutableList
|
|||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.merge
|
import kotlinx.coroutines.flow.merge
|
||||||
@ -99,7 +96,6 @@ class VaultViewModel @Inject constructor(
|
|||||||
private val specialCircumstanceManager: SpecialCircumstanceManager,
|
private val specialCircumstanceManager: SpecialCircumstanceManager,
|
||||||
private val networkConnectionManager: NetworkConnectionManager,
|
private val networkConnectionManager: NetworkConnectionManager,
|
||||||
snackbarRelayManager: SnackbarRelayManager,
|
snackbarRelayManager: SnackbarRelayManager,
|
||||||
featureFlagManager: FeatureFlagManager,
|
|
||||||
) : BaseViewModel<VaultState, VaultEvent, VaultAction>(
|
) : BaseViewModel<VaultState, VaultEvent, VaultAction>(
|
||||||
initialState = run {
|
initialState = run {
|
||||||
val userState = requireNotNull(authRepository.userStateFlow.value)
|
val userState = requireNotNull(authRepository.userStateFlow.value)
|
||||||
@ -194,15 +190,7 @@ class VaultViewModel @Inject constructor(
|
|||||||
|
|
||||||
policyManager
|
policyManager
|
||||||
.getActivePoliciesFlow(type = PolicyTypeJson.RESTRICT_ITEM_TYPES)
|
.getActivePoliciesFlow(type = PolicyTypeJson.RESTRICT_ITEM_TYPES)
|
||||||
.combine(
|
.map { policies -> policies.map { it.organizationId } }
|
||||||
featureFlagManager.getFeatureFlagFlow(FlagKey.RemoveCardPolicy),
|
|
||||||
) { policies, enabledFlag ->
|
|
||||||
if (enabledFlag && policies.isNotEmpty()) {
|
|
||||||
policies.map { it.organizationId }
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.map { VaultAction.Internal.PolicyUpdateReceive(it) }
|
.map { VaultAction.Internal.PolicyUpdateReceive(it) }
|
||||||
.onEach(::sendAction)
|
.onEach(::sendAction)
|
||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
@ -265,7 +253,7 @@ class VaultViewModel @Inject constructor(
|
|||||||
val excludedOptions = persistentListOfNotNull(
|
val excludedOptions = persistentListOfNotNull(
|
||||||
CreateVaultItemType.SSH_KEY,
|
CreateVaultItemType.SSH_KEY,
|
||||||
CreateVaultItemType.CARD.takeUnless {
|
CreateVaultItemType.CARD.takeUnless {
|
||||||
state.restrictItemTypesPolicyOrgIds.isNullOrEmpty()
|
state.restrictItemTypesPolicyOrgIds.isEmpty()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1045,7 +1033,7 @@ data class VaultState(
|
|||||||
private val isPullToRefreshSettingEnabled: Boolean,
|
private val isPullToRefreshSettingEnabled: Boolean,
|
||||||
val baseIconUrl: String,
|
val baseIconUrl: String,
|
||||||
val isIconLoadingDisabled: Boolean,
|
val isIconLoadingDisabled: Boolean,
|
||||||
val restrictItemTypesPolicyOrgIds: List<String>?,
|
val restrictItemTypesPolicyOrgIds: List<String>,
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1738,7 +1726,7 @@ sealed class VaultAction {
|
|||||||
* Indicates that a policy update has been received.
|
* Indicates that a policy update has been received.
|
||||||
*/
|
*/
|
||||||
data class PolicyUpdateReceive(
|
data class PolicyUpdateReceive(
|
||||||
val restrictItemTypesPolicyOrdIds: List<String>?,
|
val restrictItemTypesPolicyOrdIds: List<String>,
|
||||||
) : Internal()
|
) : Internal()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1763,7 +1751,7 @@ private fun MutableStateFlow<VaultState>.updateToErrorStateOrDialog(
|
|||||||
errorTitle: Text,
|
errorTitle: Text,
|
||||||
errorMessage: Text,
|
errorMessage: Text,
|
||||||
isRefreshing: Boolean,
|
isRefreshing: Boolean,
|
||||||
restrictItemTypesPolicyOrgIds: List<String>?,
|
restrictItemTypesPolicyOrgIds: List<String>,
|
||||||
) {
|
) {
|
||||||
this.update {
|
this.update {
|
||||||
if (vaultData != null) {
|
if (vaultData != null) {
|
||||||
|
|||||||
@ -42,13 +42,13 @@ fun VaultData.toViewState(
|
|||||||
isIconLoadingDisabled: Boolean,
|
isIconLoadingDisabled: Boolean,
|
||||||
baseIconUrl: String,
|
baseIconUrl: String,
|
||||||
vaultFilterType: VaultFilterType,
|
vaultFilterType: VaultFilterType,
|
||||||
restrictItemTypesPolicyOrgIds: List<String>?,
|
restrictItemTypesPolicyOrgIds: List<String>,
|
||||||
): VaultState.ViewState {
|
): VaultState.ViewState {
|
||||||
|
|
||||||
val filteredCipherViewListWithDeletedItems =
|
val filteredCipherViewListWithDeletedItems =
|
||||||
decryptCipherListResult
|
decryptCipherListResult
|
||||||
.successes
|
.successes
|
||||||
.applyRestrictItemTypesPolicy(restrictItemTypesPolicyOrgIds ?: emptyList())
|
.applyRestrictItemTypesPolicy(restrictItemTypesPolicyOrgIds)
|
||||||
.toFilteredList(vaultFilterType)
|
.toFilteredList(vaultFilterType)
|
||||||
|
|
||||||
val filteredCipherViewList = filteredCipherViewListWithDeletedItems
|
val filteredCipherViewList = filteredCipherViewListWithDeletedItems
|
||||||
@ -154,7 +154,7 @@ fun VaultData.toViewState(
|
|||||||
trashItemsCount = filteredCipherViewListWithDeletedItems.count {
|
trashItemsCount = filteredCipherViewListWithDeletedItems.count {
|
||||||
it.deletedDate != null
|
it.deletedDate != null
|
||||||
},
|
},
|
||||||
showCardGroup = cardCount != 0 || restrictItemTypesPolicyOrgIds == null,
|
showCardGroup = cardCount != 0 || restrictItemTypesPolicyOrgIds.isEmpty(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -147,14 +147,12 @@ private val DEFAULT_MAP_VALUE: ImmutableMap<FlagKey<Any>, Any> = persistentMapOf
|
|||||||
FlagKey.CredentialExchangeProtocolImport to true,
|
FlagKey.CredentialExchangeProtocolImport to true,
|
||||||
FlagKey.CredentialExchangeProtocolExport to true,
|
FlagKey.CredentialExchangeProtocolExport to true,
|
||||||
FlagKey.UserManagedPrivilegedApps to true,
|
FlagKey.UserManagedPrivilegedApps to true,
|
||||||
FlagKey.RemoveCardPolicy to true,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private val UPDATED_MAP_VALUE: ImmutableMap<FlagKey<Any>, Any> = persistentMapOf(
|
private val UPDATED_MAP_VALUE: ImmutableMap<FlagKey<Any>, Any> = persistentMapOf(
|
||||||
FlagKey.CredentialExchangeProtocolImport to false,
|
FlagKey.CredentialExchangeProtocolImport to false,
|
||||||
FlagKey.CredentialExchangeProtocolExport to false,
|
FlagKey.CredentialExchangeProtocolExport to false,
|
||||||
FlagKey.UserManagedPrivilegedApps to false,
|
FlagKey.UserManagedPrivilegedApps to false,
|
||||||
FlagKey.RemoveCardPolicy to false,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private val DEFAULT_STATE = DebugMenuState(
|
private val DEFAULT_STATE = DebugMenuState(
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import android.net.Uri
|
|||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import app.cash.turbine.turbineScope
|
import app.cash.turbine.turbineScope
|
||||||
import com.bitwarden.core.data.manager.model.FlagKey
|
|
||||||
import com.bitwarden.core.data.repository.model.DataState
|
import com.bitwarden.core.data.repository.model.DataState
|
||||||
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
|
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
|
||||||
import com.bitwarden.data.datasource.disk.base.FakeDispatcherManager
|
import com.bitwarden.data.datasource.disk.base.FakeDispatcherManager
|
||||||
@ -31,7 +30,6 @@ import com.x8bit.bitwarden.data.autofill.accessibility.manager.AccessibilitySele
|
|||||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillSelectionManager
|
import com.x8bit.bitwarden.data.autofill.manager.AutofillSelectionManager
|
||||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillSelectionManagerImpl
|
import com.x8bit.bitwarden.data.autofill.manager.AutofillSelectionManagerImpl
|
||||||
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
||||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
|
||||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManagerImpl
|
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManagerImpl
|
||||||
@ -158,13 +156,6 @@ class SearchViewModelTest : BaseViewModelTest() {
|
|||||||
} returns mutableSnackbarDataFlow
|
} returns mutableSnackbarDataFlow
|
||||||
}
|
}
|
||||||
|
|
||||||
private val mutableRemoveCardPolicyFeatureFlow = MutableStateFlow(false)
|
|
||||||
private val featureFlagManager: FeatureFlagManager = mockk {
|
|
||||||
every {
|
|
||||||
getFeatureFlagFlow(FlagKey.RemoveCardPolicy)
|
|
||||||
} returns mutableRemoveCardPolicyFeatureFlow
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
fun setup() {
|
fun setup() {
|
||||||
mockkStatic(
|
mockkStatic(
|
||||||
@ -1676,10 +1667,8 @@ class SearchViewModelTest : BaseViewModelTest() {
|
|||||||
|
|
||||||
@Suppress("MaxLineLength")
|
@Suppress("MaxLineLength")
|
||||||
@Test
|
@Test
|
||||||
fun `RESTRICT_ITEM_TYPES policy changes should update restrictItemTypesPolicyOrgIds accordingly if RemoveCardPolicy flag is enable`() =
|
fun `RESTRICT_ITEM_TYPES policy changes should update restrictItemTypesPolicyOrgIds accordingly`() =
|
||||||
runTest {
|
runTest {
|
||||||
mutableRemoveCardPolicyFeatureFlow.value = true
|
|
||||||
|
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
assertEquals(
|
assertEquals(
|
||||||
DEFAULT_STATE.copy(restrictItemTypesPolicyOrgIds = persistentListOf()),
|
DEFAULT_STATE.copy(restrictItemTypesPolicyOrgIds = persistentListOf()),
|
||||||
@ -1705,33 +1694,6 @@ class SearchViewModelTest : BaseViewModelTest() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("MaxLineLength")
|
|
||||||
@Test
|
|
||||||
fun `RESTRICT_ITEM_TYPES policy changes should update restrictItemTypesPolicyOrgIds accordingly if RemoveCardPolicy flag is disabled`() =
|
|
||||||
runTest {
|
|
||||||
val viewModel = createViewModel()
|
|
||||||
assertEquals(
|
|
||||||
DEFAULT_STATE,
|
|
||||||
viewModel.stateFlow.value,
|
|
||||||
)
|
|
||||||
mutableActivePoliciesFlow.emit(
|
|
||||||
listOf(
|
|
||||||
SyncResponseJson.Policy(
|
|
||||||
organizationId = "Test Organization",
|
|
||||||
id = "testId",
|
|
||||||
type = PolicyTypeJson.RESTRICT_ITEM_TYPES,
|
|
||||||
isEnabled = true,
|
|
||||||
data = null,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
assertEquals(
|
|
||||||
DEFAULT_STATE.copy(restrictItemTypesPolicyOrgIds = persistentListOf()),
|
|
||||||
viewModel.stateFlow.value,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `DecryptCipherErrorReceive should display error dialog`() = runTest {
|
fun `DecryptCipherErrorReceive should display error dialog`() = runTest {
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
@ -1799,7 +1761,6 @@ class SearchViewModelTest : BaseViewModelTest() {
|
|||||||
autofillSelectionManager = autofillSelectionManager,
|
autofillSelectionManager = autofillSelectionManager,
|
||||||
organizationEventManager = organizationEventManager,
|
organizationEventManager = organizationEventManager,
|
||||||
snackbarRelayManager = snackbarRelayManager,
|
snackbarRelayManager = snackbarRelayManager,
|
||||||
featureFlagManager = featureFlagManager,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.exportvault
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.bitwarden.core.data.manager.model.FlagKey
|
|
||||||
import com.bitwarden.data.repository.model.Environment
|
import com.bitwarden.data.repository.model.Environment
|
||||||
import com.bitwarden.exporters.ExportFormat
|
import com.bitwarden.exporters.ExportFormat
|
||||||
import com.bitwarden.network.model.PolicyTypeJson
|
import com.bitwarden.network.model.PolicyTypeJson
|
||||||
@ -20,7 +19,6 @@ import com.x8bit.bitwarden.data.auth.repository.model.RequestOtpResult
|
|||||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult
|
import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.VerifyOtpResult
|
import com.x8bit.bitwarden.data.auth.repository.model.VerifyOtpResult
|
||||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
|
||||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager
|
import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState
|
import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState
|
||||||
@ -81,13 +79,6 @@ class ExportVaultViewModelTest : BaseViewModelTest() {
|
|||||||
} returns ExportVaultDataResult.Success("data")
|
} returns ExportVaultDataResult.Success("data")
|
||||||
}
|
}
|
||||||
private val fileManager: FileManager = mockk()
|
private val fileManager: FileManager = mockk()
|
||||||
|
|
||||||
private val featureFlagManager: FeatureFlagManager = mockk {
|
|
||||||
every {
|
|
||||||
getFeatureFlag(FlagKey.RemoveCardPolicy)
|
|
||||||
} returns false
|
|
||||||
}
|
|
||||||
|
|
||||||
private val organizationEventManager = mockk<OrganizationEventManager> {
|
private val organizationEventManager = mockk<OrganizationEventManager> {
|
||||||
every { trackEvent(event = any()) } just runs
|
every { trackEvent(event = any()) } just runs
|
||||||
}
|
}
|
||||||
@ -143,7 +134,7 @@ class ExportVaultViewModelTest : BaseViewModelTest() {
|
|||||||
|
|
||||||
@Suppress("MaxLineLength")
|
@Suppress("MaxLineLength")
|
||||||
@Test
|
@Test
|
||||||
fun `ConfirmExportVaultClicked correct password should call exportVaultDataToString with restricted item types when policy and feature flags enabled`() {
|
fun `ConfirmExportVaultClicked correct password should call exportVaultDataToString with restricted item types when policy`() {
|
||||||
val password = "password"
|
val password = "password"
|
||||||
coEvery {
|
coEvery {
|
||||||
authRepository.validatePassword(
|
authRepository.validatePassword(
|
||||||
@ -153,9 +144,6 @@ class ExportVaultViewModelTest : BaseViewModelTest() {
|
|||||||
every {
|
every {
|
||||||
policyManager.getActivePolicies(type = PolicyTypeJson.RESTRICT_ITEM_TYPES)
|
policyManager.getActivePolicies(type = PolicyTypeJson.RESTRICT_ITEM_TYPES)
|
||||||
} returns listOf(createMockPolicy())
|
} returns listOf(createMockPolicy())
|
||||||
every {
|
|
||||||
featureFlagManager.getFeatureFlag(FlagKey.RemoveCardPolicy)
|
|
||||||
} returns true
|
|
||||||
|
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
viewModel.trySendAction(ExportVaultAction.PasswordInputChanged(password))
|
viewModel.trySendAction(ExportVaultAction.PasswordInputChanged(password))
|
||||||
@ -172,16 +160,13 @@ class ExportVaultViewModelTest : BaseViewModelTest() {
|
|||||||
|
|
||||||
@Suppress("MaxLineLength")
|
@Suppress("MaxLineLength")
|
||||||
@Test
|
@Test
|
||||||
fun `ConfirmExportVaultClicked correct password should call exportVaultDataToString without restricted item types when policy is disabled and feature flag is enabled`() {
|
fun `ConfirmExportVaultClicked correct password should call exportVaultDataToString without restricted item types when policy is disabled`() {
|
||||||
val password = "password"
|
val password = "password"
|
||||||
coEvery {
|
coEvery {
|
||||||
authRepository.validatePassword(
|
authRepository.validatePassword(
|
||||||
password = password,
|
password = password,
|
||||||
)
|
)
|
||||||
} returns ValidatePasswordResult.Success(isValid = true)
|
} returns ValidatePasswordResult.Success(isValid = true)
|
||||||
every {
|
|
||||||
featureFlagManager.getFeatureFlag(FlagKey.RemoveCardPolicy)
|
|
||||||
} returns true
|
|
||||||
|
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
viewModel.trySendAction(ExportVaultAction.PasswordInputChanged(password))
|
viewModel.trySendAction(ExportVaultAction.PasswordInputChanged(password))
|
||||||
@ -845,7 +830,6 @@ class ExportVaultViewModelTest : BaseViewModelTest() {
|
|||||||
fileManager = fileManager,
|
fileManager = fileManager,
|
||||||
vaultRepository = vaultRepository,
|
vaultRepository = vaultRepository,
|
||||||
clock = clock,
|
clock = clock,
|
||||||
featureFlagManager = featureFlagManager,
|
|
||||||
organizationEventManager = organizationEventManager,
|
organizationEventManager = organizationEventManager,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -250,14 +250,8 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||||||
coEvery { addTrustedPrivilegedApp(any(), any()) } just runs
|
coEvery { addTrustedPrivilegedApp(any(), any()) } just runs
|
||||||
}
|
}
|
||||||
|
|
||||||
private val mutableRemoveCardPolicyFeatureFlow = MutableStateFlow(false)
|
|
||||||
private val featureFlagManager: FeatureFlagManager = mockk {
|
private val featureFlagManager: FeatureFlagManager = mockk {
|
||||||
every {
|
every { getFeatureFlag(FlagKey.UserManagedPrivilegedApps) } returns true
|
||||||
getFeatureFlagFlow(FlagKey.RemoveCardPolicy)
|
|
||||||
} returns mutableRemoveCardPolicyFeatureFlow
|
|
||||||
every {
|
|
||||||
getFeatureFlag(FlagKey.UserManagedPrivilegedApps)
|
|
||||||
} returns true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val initialState = createVaultItemListingState()
|
private val initialState = createVaultItemListingState()
|
||||||
@ -376,10 +370,8 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||||||
|
|
||||||
@Suppress("MaxLineLength")
|
@Suppress("MaxLineLength")
|
||||||
@Test
|
@Test
|
||||||
fun `RESTRICT_ITEM_TYPES policy changes should update restrictItemTypesPolicyOrgIds accordingly if RemoveCardPolicy flag is enable`() =
|
fun `RESTRICT_ITEM_TYPES policy changes should update restrictItemTypesPolicyOrgIds accordingly`() =
|
||||||
runTest {
|
runTest {
|
||||||
mutableRemoveCardPolicyFeatureFlow.value = true
|
|
||||||
|
|
||||||
val viewModel = createVaultItemListingViewModel()
|
val viewModel = createVaultItemListingViewModel()
|
||||||
assertEquals(
|
assertEquals(
|
||||||
initialState.copy(restrictItemTypesPolicyOrgIds = persistentListOf()),
|
initialState.copy(restrictItemTypesPolicyOrgIds = persistentListOf()),
|
||||||
@ -405,33 +397,6 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("MaxLineLength")
|
|
||||||
@Test
|
|
||||||
fun `RESTRICT_ITEM_TYPES policy changes should update restrictItemTypesPolicyOrgIds accordingly if RemoveCardPolicy flag is disabled`() =
|
|
||||||
runTest {
|
|
||||||
val viewModel = createVaultItemListingViewModel()
|
|
||||||
assertEquals(
|
|
||||||
initialState,
|
|
||||||
viewModel.stateFlow.value,
|
|
||||||
)
|
|
||||||
mutableActivePoliciesFlow.emit(
|
|
||||||
listOf(
|
|
||||||
SyncResponseJson.Policy(
|
|
||||||
organizationId = "Test Organization",
|
|
||||||
id = "testId",
|
|
||||||
type = PolicyTypeJson.RESTRICT_ITEM_TYPES,
|
|
||||||
isEnabled = true,
|
|
||||||
data = null,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
assertEquals(
|
|
||||||
initialState.copy(restrictItemTypesPolicyOrgIds = persistentListOf()),
|
|
||||||
viewModel.stateFlow.value,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `on LockAccountClick should call lockVault for the given account`() {
|
fun `on LockAccountClick should call lockVault for the given account`() {
|
||||||
val accountUserId = "userId"
|
val accountUserId = "userId"
|
||||||
@ -1392,7 +1357,6 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||||||
@Test
|
@Test
|
||||||
fun `AddVaultItemClick inside a folder should hide card item selection dialog state when RESTRICT_ITEM_TYPES policy is enabled`() =
|
fun `AddVaultItemClick inside a folder should hide card item selection dialog state when RESTRICT_ITEM_TYPES policy is enabled`() =
|
||||||
runTest {
|
runTest {
|
||||||
mutableRemoveCardPolicyFeatureFlow.value = true
|
|
||||||
val viewModel = createVaultItemListingViewModel(
|
val viewModel = createVaultItemListingViewModel(
|
||||||
savedStateHandle = createSavedStateHandleWithVaultItemListingType(
|
savedStateHandle = createSavedStateHandleWithVaultItemListingType(
|
||||||
vaultItemListingType = VaultItemListingType.Folder(folderId = "id"),
|
vaultItemListingType = VaultItemListingType.Folder(folderId = "id"),
|
||||||
@ -1431,7 +1395,6 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||||||
@Test
|
@Test
|
||||||
fun `AddVaultItemClick inside a collection should hide card item selection dialog state when RESTRICT_ITEM_TYPES policy is enabled`() =
|
fun `AddVaultItemClick inside a collection should hide card item selection dialog state when RESTRICT_ITEM_TYPES policy is enabled`() =
|
||||||
runTest {
|
runTest {
|
||||||
mutableRemoveCardPolicyFeatureFlow.value = true
|
|
||||||
val viewModel = createVaultItemListingViewModel(
|
val viewModel = createVaultItemListingViewModel(
|
||||||
savedStateHandle = createSavedStateHandleWithVaultItemListingType(
|
savedStateHandle = createSavedStateHandleWithVaultItemListingType(
|
||||||
vaultItemListingType = VaultItemListingType.Collection(collectionId = "id"),
|
vaultItemListingType = VaultItemListingType.Collection(collectionId = "id"),
|
||||||
@ -5014,8 +4977,8 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||||||
title = BitwardenString.an_error_has_occurred.asText(),
|
title = BitwardenString.an_error_has_occurred.asText(),
|
||||||
message =
|
message =
|
||||||
BitwardenString
|
BitwardenString
|
||||||
.credential_operation_failed_because_user_verification_was_cancelled
|
.credential_operation_failed_because_user_verification_was_cancelled
|
||||||
.asText(),
|
.asText(),
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value.dialogState,
|
viewModel.stateFlow.value.dialogState,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -2071,7 +2071,7 @@ private val DEFAULT_STATE: VaultState = VaultState(
|
|||||||
isRefreshing = false,
|
isRefreshing = false,
|
||||||
showImportActionCard = false,
|
showImportActionCard = false,
|
||||||
flightRecorderSnackBar = null,
|
flightRecorderSnackBar = null,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
private val DEFAULT_CONTENT_VIEW_STATE: VaultState.ViewState.Content = VaultState.ViewState.Content(
|
private val DEFAULT_CONTENT_VIEW_STATE: VaultState.ViewState.Content = VaultState.ViewState.Content(
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package com.x8bit.bitwarden.ui.vault.feature.vault
|
package com.x8bit.bitwarden.ui.vault.feature.vault
|
||||||
|
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.bitwarden.core.data.manager.model.FlagKey
|
|
||||||
import com.bitwarden.core.data.repository.model.DataState
|
import com.bitwarden.core.data.repository.model.DataState
|
||||||
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
|
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
|
||||||
import com.bitwarden.data.repository.model.Environment
|
import com.bitwarden.data.repository.model.Environment
|
||||||
@ -25,7 +24,6 @@ import com.x8bit.bitwarden.data.auth.repository.model.SwitchAccountResult
|
|||||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult
|
import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult
|
||||||
import com.x8bit.bitwarden.data.platform.datasource.disk.model.FlightRecorderDataSet
|
import com.x8bit.bitwarden.data.platform.datasource.disk.model.FlightRecorderDataSet
|
||||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
|
||||||
import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager
|
import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.ReviewPromptManager
|
import com.x8bit.bitwarden.data.platform.manager.ReviewPromptManager
|
||||||
@ -171,13 +169,6 @@ class VaultViewModelTest : BaseViewModelTest() {
|
|||||||
every { trackEvent(event = any()) } just runs
|
every { trackEvent(event = any()) } just runs
|
||||||
}
|
}
|
||||||
|
|
||||||
private val mutableRemoveCardPolicyFeatureFlow = MutableStateFlow(false)
|
|
||||||
private val mutableSshKeyVaultItemsEnabledFlow = MutableStateFlow(false)
|
|
||||||
private val featureFlagManager: FeatureFlagManager = mockk {
|
|
||||||
every {
|
|
||||||
getFeatureFlagFlow(FlagKey.RemoveCardPolicy)
|
|
||||||
} returns mutableRemoveCardPolicyFeatureFlow
|
|
||||||
}
|
|
||||||
private val reviewPromptManager: ReviewPromptManager = mockk()
|
private val reviewPromptManager: ReviewPromptManager = mockk()
|
||||||
|
|
||||||
private val specialCircumstanceManager: SpecialCircumstanceManager = mockk {
|
private val specialCircumstanceManager: SpecialCircumstanceManager = mockk {
|
||||||
@ -219,7 +210,6 @@ class VaultViewModelTest : BaseViewModelTest() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("MaxLineLength")
|
|
||||||
@Test
|
@Test
|
||||||
fun `UserState updates with a non-null value when switching accounts should do nothing`() {
|
fun `UserState updates with a non-null value when switching accounts should do nothing`() {
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
@ -414,10 +404,8 @@ class VaultViewModelTest : BaseViewModelTest() {
|
|||||||
|
|
||||||
@Suppress("MaxLineLength")
|
@Suppress("MaxLineLength")
|
||||||
@Test
|
@Test
|
||||||
fun `RESTRICT_ITEM_TYPES policy changes should update restrictItemTypesPolicyOrgIds accordingly if RemoveCardPolicy flag is enable`() =
|
fun `RESTRICT_ITEM_TYPES policy changes should update restrictItemTypesPolicyOrgIds accordingly`() =
|
||||||
runTest {
|
runTest {
|
||||||
mutableRemoveCardPolicyFeatureFlow.value = true
|
|
||||||
|
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
assertEquals(
|
assertEquals(
|
||||||
DEFAULT_STATE,
|
DEFAULT_STATE,
|
||||||
@ -441,33 +429,6 @@ class VaultViewModelTest : BaseViewModelTest() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("MaxLineLength")
|
|
||||||
@Test
|
|
||||||
fun `RESTRICT_ITEM_TYPES policy changes should update restrictItemTypesPolicyOrgIds accordingly if RemoveCardPolicy flag is disabled`() =
|
|
||||||
runTest {
|
|
||||||
val viewModel = createViewModel()
|
|
||||||
assertEquals(
|
|
||||||
DEFAULT_STATE,
|
|
||||||
viewModel.stateFlow.value,
|
|
||||||
)
|
|
||||||
mutableActivePoliciesFlow.emit(
|
|
||||||
listOf(
|
|
||||||
SyncResponseJson.Policy(
|
|
||||||
organizationId = "Test Organization",
|
|
||||||
id = "testId",
|
|
||||||
type = PolicyTypeJson.RESTRICT_ITEM_TYPES,
|
|
||||||
isEnabled = true,
|
|
||||||
data = null,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
assertEquals(
|
|
||||||
DEFAULT_STATE.copy(restrictItemTypesPolicyOrgIds = null),
|
|
||||||
viewModel.stateFlow.value,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Flight Recorder changes should update flightRecorderSnackbar accordingly`() = runTest {
|
fun `Flight Recorder changes should update flightRecorderSnackbar accordingly`() = runTest {
|
||||||
mockkStatic(FlightRecorderDataSet::toSnackbarData)
|
mockkStatic(FlightRecorderDataSet::toSnackbarData)
|
||||||
@ -724,7 +685,7 @@ class VaultViewModelTest : BaseViewModelTest() {
|
|||||||
isIconLoadingDisabled = viewModel.stateFlow.value.isIconLoadingDisabled,
|
isIconLoadingDisabled = viewModel.stateFlow.value.isIconLoadingDisabled,
|
||||||
baseIconUrl = viewModel.stateFlow.value.baseIconUrl,
|
baseIconUrl = viewModel.stateFlow.value.baseIconUrl,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.copy(
|
.copy(
|
||||||
@ -749,7 +710,7 @@ class VaultViewModelTest : BaseViewModelTest() {
|
|||||||
isIconLoadingDisabled = viewModel.stateFlow.value.isIconLoadingDisabled,
|
isIconLoadingDisabled = viewModel.stateFlow.value.isIconLoadingDisabled,
|
||||||
baseIconUrl = viewModel.stateFlow.value.baseIconUrl,
|
baseIconUrl = viewModel.stateFlow.value.baseIconUrl,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
viewModel.stateFlow.value,
|
||||||
@ -759,7 +720,6 @@ class VaultViewModelTest : BaseViewModelTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `vaultDataStateFlow Loaded with items should update state to Content`() = runTest {
|
fun `vaultDataStateFlow Loaded with items should update state to Content`() = runTest {
|
||||||
mutableSshKeyVaultItemsEnabledFlow.value = true
|
|
||||||
mutableVaultDataStateFlow.tryEmit(
|
mutableVaultDataStateFlow.tryEmit(
|
||||||
value = DataState.Loaded(
|
value = DataState.Loaded(
|
||||||
data = VaultData(
|
data = VaultData(
|
||||||
@ -1212,7 +1172,6 @@ class VaultViewModelTest : BaseViewModelTest() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("MaxLineLength")
|
|
||||||
@Test
|
@Test
|
||||||
fun `vaultDataStateFlow NoNetwork with items should update state to Content`() =
|
fun `vaultDataStateFlow NoNetwork with items should update state to Content`() =
|
||||||
runTest {
|
runTest {
|
||||||
@ -1313,7 +1272,6 @@ class VaultViewModelTest : BaseViewModelTest() {
|
|||||||
@Test
|
@Test
|
||||||
fun `vaultDataStateFlow Loaded should include SSH key vault items`() =
|
fun `vaultDataStateFlow Loaded should include SSH key vault items`() =
|
||||||
runTest {
|
runTest {
|
||||||
mutableSshKeyVaultItemsEnabledFlow.value = true
|
|
||||||
mutableVaultDataStateFlow.tryEmit(
|
mutableVaultDataStateFlow.tryEmit(
|
||||||
value = DataState.Loaded(
|
value = DataState.Loaded(
|
||||||
data = VaultData(
|
data = VaultData(
|
||||||
@ -2593,7 +2551,6 @@ class VaultViewModelTest : BaseViewModelTest() {
|
|||||||
@Test
|
@Test
|
||||||
fun `SelectAddItemType action should set dialog state to SelectVaultAddItemType accordingly when RESTRICT_ITEM_TYPES is enabled`() =
|
fun `SelectAddItemType action should set dialog state to SelectVaultAddItemType accordingly when RESTRICT_ITEM_TYPES is enabled`() =
|
||||||
runTest {
|
runTest {
|
||||||
mutableRemoveCardPolicyFeatureFlow.value = true
|
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
mutableActivePoliciesFlow.emit(
|
mutableActivePoliciesFlow.emit(
|
||||||
listOf(
|
listOf(
|
||||||
@ -2672,7 +2629,6 @@ class VaultViewModelTest : BaseViewModelTest() {
|
|||||||
settingsRepository = settingsRepository,
|
settingsRepository = settingsRepository,
|
||||||
vaultRepository = vaultRepository,
|
vaultRepository = vaultRepository,
|
||||||
organizationEventManager = organizationEventManager,
|
organizationEventManager = organizationEventManager,
|
||||||
featureFlagManager = featureFlagManager,
|
|
||||||
firstTimeActionManager = firstTimeActionManager,
|
firstTimeActionManager = firstTimeActionManager,
|
||||||
snackbarRelayManager = snackbarRelayManager,
|
snackbarRelayManager = snackbarRelayManager,
|
||||||
reviewPromptManager = reviewPromptManager,
|
reviewPromptManager = reviewPromptManager,
|
||||||
@ -2787,5 +2743,5 @@ private fun createMockVaultState(
|
|||||||
showImportActionCard = true,
|
showImportActionCard = true,
|
||||||
isRefreshing = false,
|
isRefreshing = false,
|
||||||
flightRecorderSnackBar = null,
|
flightRecorderSnackBar = null,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
)
|
)
|
||||||
|
|||||||
@ -72,7 +72,7 @@ class VaultDataExtensionsTest {
|
|||||||
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
||||||
vaultFilterType = VaultFilterType.AllVaults,
|
vaultFilterType = VaultFilterType.AllVaults,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@ -144,7 +144,7 @@ class VaultDataExtensionsTest {
|
|||||||
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
||||||
vaultFilterType = VaultFilterType.MyVault,
|
vaultFilterType = VaultFilterType.MyVault,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@ -204,7 +204,7 @@ class VaultDataExtensionsTest {
|
|||||||
organizationName = "Mock Organization 1",
|
organizationName = "Mock Organization 1",
|
||||||
),
|
),
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@ -262,7 +262,7 @@ class VaultDataExtensionsTest {
|
|||||||
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
||||||
vaultFilterType = VaultFilterType.AllVaults,
|
vaultFilterType = VaultFilterType.AllVaults,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@ -289,7 +289,7 @@ class VaultDataExtensionsTest {
|
|||||||
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
||||||
vaultFilterType = VaultFilterType.AllVaults,
|
vaultFilterType = VaultFilterType.AllVaults,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@ -317,7 +317,7 @@ class VaultDataExtensionsTest {
|
|||||||
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
||||||
vaultFilterType = VaultFilterType.AllVaults,
|
vaultFilterType = VaultFilterType.AllVaults,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@ -359,7 +359,7 @@ class VaultDataExtensionsTest {
|
|||||||
isIconLoadingDisabled = false,
|
isIconLoadingDisabled = false,
|
||||||
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@ -403,7 +403,7 @@ class VaultDataExtensionsTest {
|
|||||||
isIconLoadingDisabled = false,
|
isIconLoadingDisabled = false,
|
||||||
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@ -447,7 +447,7 @@ class VaultDataExtensionsTest {
|
|||||||
isIconLoadingDisabled = false,
|
isIconLoadingDisabled = false,
|
||||||
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@ -675,7 +675,7 @@ class VaultDataExtensionsTest {
|
|||||||
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
||||||
vaultFilterType = VaultFilterType.AllVaults,
|
vaultFilterType = VaultFilterType.AllVaults,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@ -719,7 +719,7 @@ class VaultDataExtensionsTest {
|
|||||||
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
||||||
vaultFilterType = VaultFilterType.AllVaults,
|
vaultFilterType = VaultFilterType.AllVaults,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@ -766,7 +766,7 @@ class VaultDataExtensionsTest {
|
|||||||
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
||||||
vaultFilterType = VaultFilterType.AllVaults,
|
vaultFilterType = VaultFilterType.AllVaults,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@ -820,7 +820,7 @@ class VaultDataExtensionsTest {
|
|||||||
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
||||||
vaultFilterType = VaultFilterType.AllVaults,
|
vaultFilterType = VaultFilterType.AllVaults,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@ -891,7 +891,7 @@ class VaultDataExtensionsTest {
|
|||||||
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
||||||
vaultFilterType = VaultFilterType.AllVaults,
|
vaultFilterType = VaultFilterType.AllVaults,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@ -1087,7 +1087,7 @@ class VaultDataExtensionsTest {
|
|||||||
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
||||||
vaultFilterType = VaultFilterType.AllVaults,
|
vaultFilterType = VaultFilterType.AllVaults,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@ -1146,7 +1146,7 @@ class VaultDataExtensionsTest {
|
|||||||
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
||||||
vaultFilterType = VaultFilterType.AllVaults,
|
vaultFilterType = VaultFilterType.AllVaults,
|
||||||
hasMasterPassword = true,
|
hasMasterPassword = true,
|
||||||
restrictItemTypesPolicyOrgIds = null,
|
restrictItemTypesPolicyOrgIds = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
|||||||
@ -26,7 +26,6 @@ fun <T : Any> FlagKey<T>.ListItemContent(
|
|||||||
FlagKey.CipherKeyEncryption,
|
FlagKey.CipherKeyEncryption,
|
||||||
FlagKey.CredentialExchangeProtocolExport,
|
FlagKey.CredentialExchangeProtocolExport,
|
||||||
FlagKey.CredentialExchangeProtocolImport,
|
FlagKey.CredentialExchangeProtocolImport,
|
||||||
FlagKey.RemoveCardPolicy,
|
|
||||||
FlagKey.UserManagedPrivilegedApps,
|
FlagKey.UserManagedPrivilegedApps,
|
||||||
-> BooleanFlagItem(
|
-> BooleanFlagItem(
|
||||||
label = flagKey.getDisplayLabel(),
|
label = flagKey.getDisplayLabel(),
|
||||||
@ -72,7 +71,6 @@ private fun <T : Any> FlagKey<T>.getDisplayLabel(): String = when (this) {
|
|||||||
stringResource(BitwardenString.user_trusted_privileged_app_management)
|
stringResource(BitwardenString.user_trusted_privileged_app_management)
|
||||||
}
|
}
|
||||||
|
|
||||||
FlagKey.RemoveCardPolicy -> stringResource(BitwardenString.remove_card_policy)
|
|
||||||
FlagKey.BitwardenAuthenticationEnabled -> {
|
FlagKey.BitwardenAuthenticationEnabled -> {
|
||||||
stringResource(BitwardenString.bitwarden_authentication_enabled)
|
stringResource(BitwardenString.bitwarden_authentication_enabled)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,6 @@ sealed class FlagKey<out T : Any> {
|
|||||||
CredentialExchangeProtocolImport,
|
CredentialExchangeProtocolImport,
|
||||||
CredentialExchangeProtocolExport,
|
CredentialExchangeProtocolExport,
|
||||||
UserManagedPrivilegedApps,
|
UserManagedPrivilegedApps,
|
||||||
RemoveCardPolicy,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,15 +71,6 @@ sealed class FlagKey<out T : Any> {
|
|||||||
override val defaultValue: Boolean = false
|
override val defaultValue: Boolean = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Data object holding the feature flag key to enable the removal of card item types.
|
|
||||||
* This flag will hide card types from organizations with policy enable and individual vaults
|
|
||||||
*/
|
|
||||||
data object RemoveCardPolicy : FlagKey<Boolean>() {
|
|
||||||
override val keyName: String = "pm-16442-remove-card-item-type-policy"
|
|
||||||
override val defaultValue: Boolean = false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates the state of Bitwarden authentication.
|
* Indicates the state of Bitwarden authentication.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -24,10 +24,6 @@ class FlagKeyTest {
|
|||||||
FlagKey.UserManagedPrivilegedApps.keyName,
|
FlagKey.UserManagedPrivilegedApps.keyName,
|
||||||
"pm-18970-user-managed-privileged-apps",
|
"pm-18970-user-managed-privileged-apps",
|
||||||
)
|
)
|
||||||
assertEquals(
|
|
||||||
FlagKey.RemoveCardPolicy.keyName,
|
|
||||||
"pm-16442-remove-card-item-type-policy",
|
|
||||||
)
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
FlagKey.BitwardenAuthenticationEnabled.keyName,
|
FlagKey.BitwardenAuthenticationEnabled.keyName,
|
||||||
"bitwarden-authentication-enabled",
|
"bitwarden-authentication-enabled",
|
||||||
@ -42,7 +38,6 @@ class FlagKeyTest {
|
|||||||
FlagKey.CredentialExchangeProtocolExport,
|
FlagKey.CredentialExchangeProtocolExport,
|
||||||
FlagKey.CipherKeyEncryption,
|
FlagKey.CipherKeyEncryption,
|
||||||
FlagKey.UserManagedPrivilegedApps,
|
FlagKey.UserManagedPrivilegedApps,
|
||||||
FlagKey.RemoveCardPolicy,
|
|
||||||
FlagKey.BitwardenAuthenticationEnabled,
|
FlagKey.BitwardenAuthenticationEnabled,
|
||||||
).all {
|
).all {
|
||||||
!it.defaultValue
|
!it.defaultValue
|
||||||
|
|||||||
@ -22,7 +22,6 @@
|
|||||||
<string name="generate_error_report">Generate error report</string>
|
<string name="generate_error_report">Generate error report</string>
|
||||||
<string name="error_reports">Error reports</string>
|
<string name="error_reports">Error reports</string>
|
||||||
<string name="user_trusted_privileged_app_management">User-trusted privileged app management</string>
|
<string name="user_trusted_privileged_app_management">User-trusted privileged app management</string>
|
||||||
<string name="remove_card_policy">Remove Card Policy</string>
|
|
||||||
<string name="bitwarden_authentication_enabled">Bitwarden authentication enabled</string>
|
<string name="bitwarden_authentication_enabled">Bitwarden authentication enabled</string>
|
||||||
<string name="import_format_label_bitwarden_json">Bitwarden (.json)</string>
|
<string name="import_format_label_bitwarden_json">Bitwarden (.json)</string>
|
||||||
<string name="import_format_label_2fas_json">2FAS (no password)</string>
|
<string name="import_format_label_2fas_json">2FAS (no password)</string>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user