mirror of
https://github.com/bitwarden/android.git
synced 2026-07-29 23:28:08 -05:00
[PM-18092] Update cipher delete restore permissions (#5075)
Co-authored-by: Patrick Honkonen <1883101+SaintPatrck@users.noreply.github.com>
This commit is contained in:
co-authored by
Patrick Honkonen
parent
639ca02739
commit
1a2beea770
@@ -41,6 +41,7 @@ sealed class FlagKey<out T : Any> {
|
||||
ChromeAutofill,
|
||||
MobileErrorReporting,
|
||||
FlightRecorder,
|
||||
RestrictCipherItemDeletion,
|
||||
PreAuthSettings,
|
||||
)
|
||||
}
|
||||
@@ -194,6 +195,15 @@ sealed class FlagKey<out T : Any> {
|
||||
override val isRemotelyConfigured: Boolean = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Data object holding the feature flag key to enable the restriction of cipher item deletion
|
||||
*/
|
||||
data object RestrictCipherItemDeletion : FlagKey<Boolean>() {
|
||||
override val keyName: String = "pm-15493-restrict-item-deletion-to-can-manage-permission"
|
||||
override val defaultValue: Boolean = false
|
||||
override val isRemotelyConfigured: Boolean = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Data object holding the feature flag key to enable the settings menu before login.
|
||||
*/
|
||||
|
||||
+11
-2
@@ -4,6 +4,7 @@ import com.bitwarden.core.annotation.OmitFromCoverage
|
||||
import com.bitwarden.fido.Fido2CredentialAutofillView
|
||||
import com.bitwarden.sdk.Fido2CredentialStore
|
||||
import com.bitwarden.vault.Cipher
|
||||
import com.bitwarden.vault.CipherListView
|
||||
import com.bitwarden.vault.CipherView
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.autofill.util.isActiveWithFido2Credentials
|
||||
@@ -24,15 +25,23 @@ class Fido2CredentialStoreImpl(
|
||||
/**
|
||||
* Return all active ciphers that contain FIDO 2 credentials.
|
||||
*/
|
||||
override suspend fun allCredentials(): List<CipherView> {
|
||||
override suspend fun allCredentials(): List<CipherListView> {
|
||||
val syncResult = vaultRepository.syncForResult()
|
||||
if (syncResult is SyncVaultDataResult.Error) {
|
||||
syncResult.throwable
|
||||
?.let { throw it }
|
||||
?: throw IllegalStateException("Sync failed.")
|
||||
}
|
||||
return vaultRepository.ciphersStateFlow.value.data
|
||||
val activeCipherIds = vaultRepository.ciphersStateFlow.value.data
|
||||
?.filter { it.isActiveWithFido2Credentials }
|
||||
?.map { it.id }
|
||||
?: emptyList()
|
||||
|
||||
return vaultRepository.ciphersListViewStateFlow.value.data
|
||||
?.filter { clv ->
|
||||
activeCipherIds
|
||||
.contains(clv.id)
|
||||
}
|
||||
?: emptyList()
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.bitwarden.fido.Fido2CredentialAutofillView
|
||||
import com.bitwarden.sdk.Fido2CredentialStore
|
||||
import com.bitwarden.send.SendType
|
||||
import com.bitwarden.send.SendView
|
||||
import com.bitwarden.vault.CipherListView
|
||||
import com.bitwarden.vault.CipherView
|
||||
import com.bitwarden.vault.CollectionView
|
||||
import com.bitwarden.vault.FolderView
|
||||
@@ -65,6 +66,14 @@ interface VaultRepository : CipherManager, VaultLockManager {
|
||||
*/
|
||||
val ciphersStateFlow: StateFlow<DataState<List<CipherView>>>
|
||||
|
||||
/**
|
||||
* Flow that represents all ciphers for the active user.
|
||||
*
|
||||
* Note that the [StateFlow.value] will return the last known value but the [StateFlow] itself
|
||||
* must be collected in order to trigger state changes.
|
||||
*/
|
||||
val ciphersListViewStateFlow: StateFlow<DataState<List<CipherListView>>>
|
||||
|
||||
/**
|
||||
* Flow that represents all collections for the active user.
|
||||
*
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.bitwarden.sdk.Fido2CredentialStore
|
||||
import com.bitwarden.send.Send
|
||||
import com.bitwarden.send.SendType
|
||||
import com.bitwarden.send.SendView
|
||||
import com.bitwarden.vault.CipherListView
|
||||
import com.bitwarden.vault.CipherType
|
||||
import com.bitwarden.vault.CipherView
|
||||
import com.bitwarden.vault.CollectionView
|
||||
@@ -169,6 +170,9 @@ class VaultRepositoryImpl(
|
||||
private val mutableCiphersStateFlow =
|
||||
MutableStateFlow<DataState<List<CipherView>>>(DataState.Loading)
|
||||
|
||||
private val mutableCiphersListViewStateFlow =
|
||||
MutableStateFlow<DataState<List<CipherListView>>>(DataState.Loading)
|
||||
|
||||
private val mutableFoldersStateFlow =
|
||||
MutableStateFlow<DataState<List<FolderView>>>(DataState.Loading)
|
||||
|
||||
@@ -214,6 +218,9 @@ class VaultRepositoryImpl(
|
||||
override val ciphersStateFlow: StateFlow<DataState<List<CipherView>>>
|
||||
get() = mutableCiphersStateFlow.asStateFlow()
|
||||
|
||||
override val ciphersListViewStateFlow: StateFlow<DataState<List<CipherListView>>>
|
||||
get() = mutableCiphersListViewStateFlow.asStateFlow()
|
||||
|
||||
override val domainsStateFlow: StateFlow<DataState<DomainsData>>
|
||||
get() = mutableDomainsStateFlow.asStateFlow()
|
||||
|
||||
@@ -260,6 +267,15 @@ class VaultRepositoryImpl(
|
||||
}
|
||||
.launchIn(unconfinedScope)
|
||||
|
||||
mutableCiphersListViewStateFlow
|
||||
.observeWhenSubscribedAndUnlocked(
|
||||
userStateFlow = authDiskSource.userStateFlow,
|
||||
vaultUnlockFlow = vaultUnlockDataStateFlow,
|
||||
) { activeUserId ->
|
||||
observeVaultDiskCiphersToCipherListView(activeUserId)
|
||||
}
|
||||
.launchIn(unconfinedScope)
|
||||
|
||||
// Setup domains MutableStateFlow
|
||||
mutableDomainsStateFlow
|
||||
.observeWhenSubscribedAndLoggedIn(
|
||||
@@ -1071,6 +1087,27 @@ class VaultRepositoryImpl(
|
||||
.map { it.orLoadingIfNotSynced(userId = userId) }
|
||||
.onEach { mutableCiphersStateFlow.value = it }
|
||||
|
||||
private fun observeVaultDiskCiphersToCipherListView(
|
||||
userId: String,
|
||||
): Flow<DataState<List<CipherListView>>> =
|
||||
vaultDiskSource
|
||||
.getCiphers(userId = userId)
|
||||
.onStart { mutableCiphersListViewStateFlow.updateToPendingOrLoading() }
|
||||
.map {
|
||||
waitUntilUnlocked(userId = userId)
|
||||
vaultSdkSource
|
||||
.decryptCipherListCollection(
|
||||
userId = userId,
|
||||
cipherList = it.toEncryptedSdkCipherList(),
|
||||
)
|
||||
.fold(
|
||||
onSuccess = { ciphers -> DataState.Loaded(ciphers.sortAlphabetically()) },
|
||||
onFailure = { throwable -> DataState.Error(throwable) },
|
||||
)
|
||||
}
|
||||
.map { it.orLoadingIfNotSynced(userId = userId) }
|
||||
.onEach { mutableCiphersListViewStateFlow.value = it }
|
||||
|
||||
private fun observeVaultDiskDomains(
|
||||
userId: String,
|
||||
): Flow<DataState<DomainsData>> =
|
||||
|
||||
+38
@@ -15,6 +15,8 @@ import com.bitwarden.network.model.UriMatchTypeJson
|
||||
import com.bitwarden.vault.Attachment
|
||||
import com.bitwarden.vault.Card
|
||||
import com.bitwarden.vault.Cipher
|
||||
import com.bitwarden.vault.CipherListView
|
||||
import com.bitwarden.vault.CipherPermissions
|
||||
import com.bitwarden.vault.CipherRepromptType
|
||||
import com.bitwarden.vault.CipherType
|
||||
import com.bitwarden.vault.CipherView
|
||||
@@ -68,6 +70,7 @@ fun Cipher.toEncryptedNetworkCipherResponse(): SyncResponseJson.Cipher =
|
||||
notes = notes,
|
||||
reprompt = reprompt.toNetworkRepromptType(),
|
||||
passwordHistory = passwordHistory?.toEncryptedNetworkPasswordHistoryList(),
|
||||
permissions = permissions?.toEncryptedNetworkCipherPermissions(),
|
||||
type = type.toNetworkCipherType(),
|
||||
login = login?.toEncryptedNetworkLogin(),
|
||||
secureNote = secureNote?.toEncryptedNetworkSecureNote(),
|
||||
@@ -299,6 +302,17 @@ private fun PasswordHistory.toEncryptedNetworkPasswordHistory(): SyncResponseJso
|
||||
lastUsedDate = ZonedDateTime.ofInstant(lastUsedDate, ZoneOffset.UTC),
|
||||
)
|
||||
|
||||
/**
|
||||
* Converts a Bitwarden SDK [CipherPermissions] object to a corresponding
|
||||
* [SyncResponseJson.Cipher.CipherPermissions] object.
|
||||
*/
|
||||
@Suppress("MaxLineLength")
|
||||
private fun CipherPermissions.toEncryptedNetworkCipherPermissions(): SyncResponseJson.Cipher.CipherPermissions =
|
||||
SyncResponseJson.Cipher.CipherPermissions(
|
||||
delete = delete,
|
||||
restore = restore,
|
||||
)
|
||||
|
||||
/**
|
||||
* Converts a Bitwarden SDK [CipherRepromptType] object to a corresponding
|
||||
* [CipherRepromptTypeJson] object.
|
||||
@@ -357,6 +371,7 @@ fun SyncResponseJson.Cipher.toEncryptedSdkCipher(): Cipher =
|
||||
attachments = attachments?.toSdkAttachmentList(),
|
||||
fields = fields?.toSdkFieldList(),
|
||||
passwordHistory = passwordHistory?.toSdkPasswordHistoryList(),
|
||||
permissions = permissions?.toSdkPermissions(),
|
||||
creationDate = creationDate.toInstant(),
|
||||
deletedDate = deletedDate?.toInstant(),
|
||||
revisionDate = revisionDate.toInstant(),
|
||||
@@ -531,6 +546,16 @@ fun SyncResponseJson.Cipher.PasswordHistory.toSdkPasswordHistory(): PasswordHist
|
||||
lastUsedDate = lastUsedDate.toInstant(),
|
||||
)
|
||||
|
||||
/**
|
||||
* Transforms a [SyncResponseJson.Cipher.CipherPermissions] into
|
||||
* a corresponding Bitwarden SDK [CipherPermissions].
|
||||
*/
|
||||
fun SyncResponseJson.Cipher.CipherPermissions.toSdkPermissions(): CipherPermissions =
|
||||
CipherPermissions(
|
||||
delete = delete,
|
||||
restore = restore,
|
||||
)
|
||||
|
||||
/**
|
||||
* Transforms a [CipherTypeJson] to the corresponding Bitwarden SDK [CipherType].
|
||||
*/
|
||||
@@ -588,3 +613,16 @@ fun List<CipherView>.sortAlphabetically(): List<CipherView> {
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the data in alphabetical order by name. Using lexicographical sorting but giving
|
||||
* precedence to special characters over letters and digits.
|
||||
*/
|
||||
@JvmName("toAlphabeticallySortedCipherListView")
|
||||
fun List<CipherListView>.sortAlphabetically(): List<CipherListView> {
|
||||
return this.sortedWith(
|
||||
comparator = { cipher1, cipher2 ->
|
||||
SpecialCharWithPrecedenceComparator.compare(cipher1.name, cipher2.name)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
+2
@@ -41,6 +41,7 @@ fun <T : Any> FlagKey<T>.ListItemContent(
|
||||
FlagKey.ChromeAutofill,
|
||||
FlagKey.MobileErrorReporting,
|
||||
FlagKey.FlightRecorder,
|
||||
FlagKey.RestrictCipherItemDeletion,
|
||||
FlagKey.PreAuthSettings,
|
||||
-> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@@ -102,5 +103,6 @@ private fun <T : Any> FlagKey<T>.getDisplayLabel(): String = when (this) {
|
||||
FlagKey.ChromeAutofill -> stringResource(R.string.enable_chrome_autofill)
|
||||
FlagKey.MobileErrorReporting -> stringResource(R.string.enable_error_reporting_dialog)
|
||||
FlagKey.FlightRecorder -> stringResource(R.string.enable_flight_recorder)
|
||||
FlagKey.RestrictCipherItemDeletion -> stringResource(R.string.restrict_item_deletion)
|
||||
FlagKey.PreAuthSettings -> stringResource(R.string.enable_pre_auth_settings)
|
||||
}
|
||||
|
||||
+21
-4
@@ -26,12 +26,14 @@ import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2RegisterCredentialResu
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.model.UserVerificationRequirement
|
||||
import com.x8bit.bitwarden.data.autofill.fido2.util.getCreatePasskeyCredentialRequestOrNull
|
||||
import com.x8bit.bitwarden.data.autofill.util.isActiveWithFido2Credentials
|
||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.CoachMarkTourType
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent
|
||||
import com.x8bit.bitwarden.data.platform.manager.network.NetworkConnectionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.util.toAutofillSaveItemOrNull
|
||||
@@ -119,6 +121,7 @@ class VaultAddEditViewModel @Inject constructor(
|
||||
private val organizationEventManager: OrganizationEventManager,
|
||||
private val networkConnectionManager: NetworkConnectionManager,
|
||||
private val firstTimeActionManager: FirstTimeActionManager,
|
||||
private val featureFlagManager: FeatureFlagManager,
|
||||
) : BaseViewModel<VaultAddEditState, VaultAddEditEvent, VaultAddEditAction>(
|
||||
// We load the state from the savedStateHandle for testing purposes.
|
||||
initialState = savedStateHandle[KEY_STATE]
|
||||
@@ -1719,6 +1722,10 @@ class VaultAddEditViewModel @Inject constructor(
|
||||
vaultData: VaultData?,
|
||||
userData: UserState?,
|
||||
): VaultAddEditState {
|
||||
val restrictCipherItemDeletionEnabled = featureFlagManager
|
||||
.getFeatureFlag(
|
||||
FlagKey.RestrictCipherItemDeletion,
|
||||
)
|
||||
val internalVaultData = vaultData
|
||||
?: VaultData(
|
||||
cipherViewList = emptyList(),
|
||||
@@ -1737,10 +1744,15 @@ class VaultAddEditViewModel @Inject constructor(
|
||||
currentAccount = userData?.activeAccount,
|
||||
vaultAddEditType = vaultAddEditType,
|
||||
) { currentAccount, cipherView ->
|
||||
|
||||
val canDelete = internalVaultData
|
||||
.collectionViewList
|
||||
.hasDeletePermissionInAtLeastOneCollection(cipherView?.collectionIds)
|
||||
val canDelete = if (restrictCipherItemDeletionEnabled &&
|
||||
cipherView?.permissions?.delete != null
|
||||
) {
|
||||
cipherView.permissions?.delete == true
|
||||
} else {
|
||||
internalVaultData
|
||||
.collectionViewList
|
||||
.hasDeletePermissionInAtLeastOneCollection(cipherView?.collectionIds)
|
||||
}
|
||||
|
||||
val canAssignToCollections = internalVaultData
|
||||
.collectionViewList
|
||||
@@ -2241,16 +2253,21 @@ data class VaultAddEditState(
|
||||
* This is only present when editing a pre-existing cipher.
|
||||
* @property name Represents the name for the item type. This is an abstract property
|
||||
* that must be overridden to save the item.
|
||||
* @property isUnlockWithPasswordEnabled Indicates whether the user is allowed to
|
||||
* unlock with a password.
|
||||
* @property masterPasswordReprompt Indicates if a master password reprompt is required.
|
||||
* @property favorite Indicates whether this item is marked as a favorite.
|
||||
* @property customFieldData Additional custom fields associated with the item.
|
||||
* @property notes Any additional notes or comments associated with the item.
|
||||
* @property selectedCollectionId The ID of the collection that this item belongs to.
|
||||
* @property selectedFolderId The ID of the folder that this item belongs to.
|
||||
* @property availableFolders The list of folders that this item could be added too.
|
||||
* @property selectedOwnerId The ID of the owner associated with the item.
|
||||
* @property availableOwners A list of available owners.
|
||||
* @property hasOrganizations Indicates if the user is part of any organizations.
|
||||
* @property canDelete Indicates whether the current user can delete the item.
|
||||
* @property canAssignToCollections Indicates whether the current user can assign the
|
||||
* item to a collection.
|
||||
*/
|
||||
@Parcelize
|
||||
data class Common(
|
||||
|
||||
@@ -166,7 +166,7 @@ fun VaultItemScreen(
|
||||
{ viewModel.trySendAction(VaultItemAction.Common.CloseClick) }
|
||||
},
|
||||
actions = {
|
||||
if (state.isCipherDeleted && state.canDelete) {
|
||||
if (state.canRestore) {
|
||||
BitwardenTextButton(
|
||||
label = stringResource(id = R.string.restore),
|
||||
onClick = remember(viewModel) {
|
||||
|
||||
@@ -17,8 +17,10 @@ import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.BreachCountResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.ValidatePasswordResult
|
||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent
|
||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
@@ -70,6 +72,7 @@ class VaultItemViewModel @Inject constructor(
|
||||
private val organizationEventManager: OrganizationEventManager,
|
||||
private val environmentRepository: EnvironmentRepository,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val featureFlagManager: FeatureFlagManager,
|
||||
) : BaseViewModel<VaultItemState, VaultItemEvent, VaultItemAction>(
|
||||
// We load the state from the savedStateHandle for testing purposes.
|
||||
initialState = savedStateHandle[KEY_STATE] ?: run {
|
||||
@@ -105,6 +108,10 @@ class VaultItemViewModel @Inject constructor(
|
||||
vaultRepository.collectionsStateFlow,
|
||||
vaultRepository.foldersStateFlow,
|
||||
) { cipherViewState, userState, authCodeState, collectionsState, folderState ->
|
||||
val restrictCipherItemDeletionEnabled = featureFlagManager
|
||||
.getFeatureFlag(
|
||||
FlagKey.RestrictCipherItemDeletion,
|
||||
)
|
||||
val totpCodeData = authCodeState.data?.let {
|
||||
TotpCodeItemData(
|
||||
periodSeconds = it.periodSeconds,
|
||||
@@ -126,10 +133,24 @@ class VaultItemViewModel @Inject constructor(
|
||||
}
|
||||
.mapNullable {
|
||||
val cipherView = cipherViewState.data
|
||||
val canDelete = collectionsState.data
|
||||
.hasDeletePermissionInAtLeastOneCollection(
|
||||
val canDelete = if (restrictCipherItemDeletionEnabled &&
|
||||
cipherView?.permissions?.delete != null
|
||||
) {
|
||||
cipherView.permissions?.delete == true
|
||||
} else {
|
||||
collectionsState.data.hasDeletePermissionInAtLeastOneCollection(
|
||||
collectionIds = cipherView?.collectionIds,
|
||||
)
|
||||
}
|
||||
|
||||
val canRestore = if (restrictCipherItemDeletionEnabled &&
|
||||
cipherView?.permissions?.restore != null
|
||||
) {
|
||||
cipherView.permissions?.restore == true &&
|
||||
cipherView.deletedDate != null
|
||||
} else {
|
||||
canDelete && cipherView?.deletedDate != null
|
||||
}
|
||||
|
||||
val canAssignToCollections = collectionsState.data
|
||||
.canAssignToCollections(cipherView?.collectionIds)
|
||||
@@ -167,6 +188,7 @@ class VaultItemViewModel @Inject constructor(
|
||||
cipher = cipherView,
|
||||
totpCodeItemData = totpCodeData,
|
||||
canDelete = canDelete,
|
||||
canRestore = canRestore,
|
||||
canAssociateToCollections = canAssignToCollections,
|
||||
canEdit = canEdit,
|
||||
relatedLocations = relatedLocations,
|
||||
@@ -1200,6 +1222,7 @@ class VaultItemViewModel @Inject constructor(
|
||||
hasMasterPassword = account.hasMasterPassword,
|
||||
totpCodeItemData = this.data?.totpCodeItemData,
|
||||
canDelete = this.data?.canDelete == true,
|
||||
canRestore = this.data?.canRestore == true,
|
||||
canAssignToCollections = this.data?.canAssociateToCollections == true,
|
||||
canEdit = this.data?.canEdit == true,
|
||||
baseIconUrl = environmentRepository.environment.environmentUrlData.baseIconUrl,
|
||||
@@ -1496,6 +1519,14 @@ data class VaultItemState(
|
||||
?.common
|
||||
?.canDelete == true
|
||||
|
||||
/**
|
||||
* Whether or not the cipher can be deleted.
|
||||
*/
|
||||
val canRestore: Boolean
|
||||
get() = viewState.asContentOrNull()
|
||||
?.common
|
||||
?.canRestore == true
|
||||
|
||||
val canAssignToCollections: Boolean
|
||||
get() = viewState.asContentOrNull()
|
||||
?.common
|
||||
@@ -1555,6 +1586,7 @@ data class VaultItemState(
|
||||
* @property currentCipher The cipher that is currently being viewed (nullable).
|
||||
* @property attachments A list of attachments associated with the cipher.
|
||||
* @property canDelete Indicates if the cipher can be deleted.
|
||||
* @property canRestore Indicates if the cipher can be restored.
|
||||
* @property canAssignToCollections Indicates if the cipher can be assigned to
|
||||
* collections.
|
||||
* @property favorite Indicates that the cipher is favorite.
|
||||
@@ -1572,6 +1604,7 @@ data class VaultItemState(
|
||||
val currentCipher: CipherView? = null,
|
||||
val attachments: List<AttachmentItem>?,
|
||||
val canDelete: Boolean,
|
||||
val canRestore: Boolean,
|
||||
val canAssignToCollections: Boolean,
|
||||
val canEdit: Boolean,
|
||||
val favorite: Boolean,
|
||||
|
||||
+1
@@ -17,6 +17,7 @@ data class VaultItemStateData(
|
||||
val cipher: CipherView?,
|
||||
val totpCodeItemData: TotpCodeItemData?,
|
||||
val canDelete: Boolean,
|
||||
val canRestore: Boolean,
|
||||
val canAssociateToCollections: Boolean,
|
||||
val canEdit: Boolean,
|
||||
val relatedLocations: ImmutableList<VaultItemLocation>,
|
||||
|
||||
+2
@@ -45,6 +45,7 @@ fun CipherView.toViewState(
|
||||
totpCodeItemData: TotpCodeItemData?,
|
||||
clock: Clock = Clock.systemDefaultZone(),
|
||||
canDelete: Boolean,
|
||||
canRestore: Boolean,
|
||||
canAssignToCollections: Boolean,
|
||||
canEdit: Boolean,
|
||||
baseIconUrl: String,
|
||||
@@ -98,6 +99,7 @@ fun CipherView.toViewState(
|
||||
}
|
||||
.orEmpty(),
|
||||
canDelete = canDelete,
|
||||
canRestore = canRestore,
|
||||
canAssignToCollections = canAssignToCollections,
|
||||
canEdit = canEdit,
|
||||
favorite = this.favorite,
|
||||
|
||||
+1
@@ -40,6 +40,7 @@ fun VaultAddEditState.ViewState.Content.toCipherView(): CipherView =
|
||||
attachments = common.originalCipher?.attachments,
|
||||
organizationUseTotp = common.originalCipher?.organizationUseTotp ?: false,
|
||||
passwordHistory = toPasswordHistory(),
|
||||
permissions = common.originalCipher?.permissions,
|
||||
creationDate = common.originalCipher?.creationDate ?: Instant.now(),
|
||||
deletedDate = common.originalCipher?.deletedDate,
|
||||
revisionDate = common.originalCipher?.revisionDate ?: Instant.now(),
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
<string name="enable_chrome_autofill">Enable chrome autofill</string>
|
||||
<string name="enable_error_reporting_dialog">Enable error reporting dialog</string>
|
||||
<string name="enable_flight_recorder">Enable flight recorder</string>
|
||||
<string name="restrict_item_deletion">Restrict item deletion</string>
|
||||
<string name="enable_pre_auth_settings">Enabled pre-auth settings</string>
|
||||
<!-- /Debug Menu -->
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user