From d07b1198026d53c77dbed68f1920a6710eaae75d Mon Sep 17 00:00:00 2001 From: aj-rosado <109146700+aj-rosado@users.noreply.github.com> Date: Fri, 31 Oct 2025 10:08:24 +0000 Subject: [PATCH] [PM-27120] cxp hide user account when remove individual export is enabled (#6089) --- .../data/auth/manager/UserStateManagerImpl.kt | 14 + .../repository/di/AuthRepositoryModule.kt | 2 + .../data/auth/repository/model/UserState.kt | 1 + .../util/UserStateJsonExtensions.kt | 17 ++ .../data/platform/manager/PolicyManager.kt | 8 + .../platform/manager/PolicyManagerImpl.kt | 12 + .../vault/manager/VaultSyncManagerImpl.kt | 15 +- .../platform/feature/rootnav/RootNavScreen.kt | 1 + .../feature/rootnav/RootNavViewModel.kt | 5 +- .../exportitems/ExportItemsNavigation.kt | 7 +- .../selectaccount/SelectAccountNavigation.kt | 2 +- .../selectaccount/SelectAccountScreen.kt | 4 +- .../selectaccount/SelectAccountViewModel.kt | 20 +- .../VerifyPasswordNavigation.kt | 9 +- .../verifypassword/VerifyPasswordViewModel.kt | 6 +- .../com/x8bit/bitwarden/MainViewModelTest.kt | 1 + .../data/auth/manager/UserStateManagerTest.kt | 48 ++++ .../util/UserStateJsonExtensionsTest.kt | 269 ++++++++++++++++++ .../CredentialProviderProcessorTest.kt | 1 + .../platform/manager/PolicyManagerTest.kt | 56 ++++ .../accountsetup/SetupUnlockViewModelTest.kt | 1 + .../feature/landing/LandingViewModelTest.kt | 6 + .../auth/feature/login/LoginViewModelTest.kt | 1 + .../RemovePasswordViewModelTest.kt | 1 + .../TrustedDeviceViewModelTest.kt | 1 + .../vaultunlock/VaultUnlockViewModelTest.kt | 3 + .../feature/rootnav/RootNavScreenTest.kt | 1 + .../feature/rootnav/RootNavViewModelTest.kt | 33 +++ .../feature/search/SearchViewModelTest.kt | 1 + .../AccountSecurityViewModelTest.kt | 1 + .../DeleteAccountViewModelTest.kt | 1 + .../LoginApprovalViewModelTest.kt | 2 + .../exportvault/ExportVaultViewModelTest.kt | 1 + .../generator/GeneratorViewModelTest.kt | 1 + .../tools/feature/send/SendViewModelTest.kt | 1 + .../send/addedit/AddEditSendViewModelTest.kt | 1 + .../addedit/VaultAddEditViewModelTest.kt | 1 + .../addedit/util/CipherViewExtensionsTest.kt | 1 + .../attachments/AttachmentsViewModelTest.kt | 1 + .../exportitems/SelectAccountScreenTest.kt | 3 +- .../exportitems/SelectAccountViewModelTest.kt | 13 +- .../reviewexport/ReviewExportViewModelTest.kt | 1 + .../VerifyPasswordScreenTest.kt | 1 + .../VerifyPasswordViewModelTest.kt | 3 + .../feature/item/VaultItemViewModelTest.kt | 1 + .../VaultItemListingViewModelTest.kt | 1 + .../VaultMoveToOrganizationViewModelTest.kt | 1 + .../VaultMoveToOrganizationExtensionsTest.kt | 1 + .../vault/feature/vault/VaultViewModelTest.kt | 4 + .../vault/util/UserStateExtensionsTest.kt | 10 + 50 files changed, 553 insertions(+), 43 deletions(-) diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/manager/UserStateManagerImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/manager/UserStateManagerImpl.kt index df596a3b80..83bc1d70e8 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/manager/UserStateManagerImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/manager/UserStateManagerImpl.kt @@ -1,6 +1,8 @@ package com.x8bit.bitwarden.data.auth.manager import com.bitwarden.data.manager.DispatcherManager +import com.bitwarden.network.model.PolicyTypeJson +import com.bitwarden.network.model.SyncResponseJson import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource import com.x8bit.bitwarden.data.auth.datasource.disk.model.OnboardingStatus import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson @@ -19,6 +21,7 @@ import com.x8bit.bitwarden.data.auth.repository.util.userKeyConnectorStateList import com.x8bit.bitwarden.data.auth.repository.util.userOrganizationsList import com.x8bit.bitwarden.data.auth.repository.util.userOrganizationsListFlow import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager +import com.x8bit.bitwarden.data.platform.manager.PolicyManager import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState import com.x8bit.bitwarden.data.vault.manager.VaultLockManager import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData @@ -39,6 +42,7 @@ class UserStateManagerImpl( private val authDiskSource: AuthDiskSource, firstTimeActionManager: FirstTimeActionManager, vaultLockManager: VaultLockManager, + private val policyManager: PolicyManager, dispatcherManager: DispatcherManager, ) : UserStateManager { private val unconfinedScope = CoroutineScope(dispatcherManager.unconfined) @@ -110,6 +114,7 @@ class UserStateManagerImpl( vaultUnlockTypeProvider = ::getVaultUnlockType, isDeviceTrustedProvider = ::isDeviceTrusted, firstTimeState = firstTimeState, + getUserPolicies = ::existingPolicies, ) } .filterNot { @@ -133,6 +138,7 @@ class UserStateManagerImpl( vaultUnlockTypeProvider = ::getVaultUnlockType, isDeviceTrustedProvider = ::isDeviceTrusted, firstTimeState = firstTimeActionManager.currentOrDefaultUserFirstTimeState, + getUserPolicies = ::existingPolicies, ), ) @@ -159,4 +165,12 @@ class UserStateManagerImpl( .getPinProtectedUserKeyEnvelope(userId = userId) ?.let { VaultUnlockType.PIN } ?: VaultUnlockType.MASTER_PASSWORD + + private fun existingPolicies( + userId: String, + policyType: PolicyTypeJson, + ): List = policyManager.getUserPolicies( + userId = userId, + type = policyType, + ) } diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/di/AuthRepositoryModule.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/di/AuthRepositoryModule.kt index 765b8e8749..db114209fc 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/di/AuthRepositoryModule.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/di/AuthRepositoryModule.kt @@ -102,11 +102,13 @@ object AuthRepositoryModule { authDiskSource: AuthDiskSource, firstTimeActionManager: FirstTimeActionManager, vaultLockManager: VaultLockManager, + policyManager: PolicyManager, dispatcherManager: DispatcherManager, ): UserStateManager = UserStateManagerImpl( authDiskSource = authDiskSource, firstTimeActionManager = firstTimeActionManager, vaultLockManager = vaultLockManager, + policyManager = policyManager, dispatcherManager = dispatcherManager, ) } diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/model/UserState.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/model/UserState.kt index 0befd19112..bedd3f805c 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/model/UserState.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/model/UserState.kt @@ -75,6 +75,7 @@ data class UserState( val isUsingKeyConnector: Boolean, val onboardingStatus: OnboardingStatus, val firstTimeState: FirstTimeState, + val isExportable: Boolean, ) { /** * Indicates that the user does or does not have a means to manually unlock the vault. diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/util/UserStateJsonExtensions.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/util/UserStateJsonExtensions.kt index 78ac8e757c..61580cdf01 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/util/UserStateJsonExtensions.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/util/UserStateJsonExtensions.kt @@ -3,6 +3,7 @@ package com.x8bit.bitwarden.data.auth.repository.util import com.bitwarden.data.repository.util.toEnvironmentUrlsOrDefault import com.bitwarden.network.model.KdfTypeJson import com.bitwarden.network.model.OrganizationType +import com.bitwarden.network.model.PolicyTypeJson import com.bitwarden.network.model.SyncResponseJson import com.bitwarden.network.model.UserDecryptionOptionsJson import com.bitwarden.ui.platform.base.util.toHexColorRepresentation @@ -164,6 +165,7 @@ fun UserStateJson.toUserState( isBiometricsEnabledProvider: (userId: String) -> Boolean, vaultUnlockTypeProvider: (userId: String) -> VaultUnlockType, isDeviceTrustedProvider: (userId: String) -> Boolean, + getUserPolicies: (userId: String, policy: PolicyTypeJson) -> List, ): UserState = UserState( activeUserId = this.activeUserId, @@ -203,6 +205,19 @@ fun UserStateJson.toUserState( hasManageResetPasswordPermission.takeIf { trustedDevice != null } val needsMasterPassword = decryptionOptions?.hasMasterPassword == false && (tdeUserNeedsMasterPassword ?: (keyConnectorOptions == null)) + + val hasPersonalOwnershipRestrictedOrg = getUserPolicies( + userId, + PolicyTypeJson.PERSONAL_OWNERSHIP, + ) + .any { it.isEnabled } + + val hasPersonalVaultExportRestrictedOrg = getUserPolicies( + userId, + PolicyTypeJson.DISABLE_PERSONAL_VAULT_EXPORT, + ) + .any { it.isEnabled } + UserState.Account( userId = userId, name = profile.name, @@ -231,6 +246,8 @@ fun UserStateJson.toUserState( // using the app prior to the release of the onboarding flow. onboardingStatus = onboardingStatus ?: OnboardingStatus.COMPLETE, firstTimeState = firstTimeState, + isExportable = !hasPersonalOwnershipRestrictedOrg && + !hasPersonalVaultExportRestrictedOrg, ) }, hasPendingAccountAddition = hasPendingAccountAddition, diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/PolicyManager.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/PolicyManager.kt index 2408e72408..7e61d5dbed 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/PolicyManager.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/PolicyManager.kt @@ -17,4 +17,12 @@ interface PolicyManager { * Get all the policies of the given [type] that are enabled and applicable to the user. */ fun getActivePolicies(type: PolicyTypeJson): List + + /** + * Get all the policies of the given [type] that are enabled and applicable to the [userId]. + */ + fun getUserPolicies( + userId: String, + type: PolicyTypeJson, + ): List } diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/PolicyManagerImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/PolicyManagerImpl.kt index f0513799ca..3197b81516 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/PolicyManagerImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/PolicyManagerImpl.kt @@ -54,6 +54,18 @@ class PolicyManagerImpl( } ?: emptyList() + override fun getUserPolicies( + userId: String, + type: PolicyTypeJson, + ): List = + this + .filterPolicies( + userId = userId, + type = type, + policies = authDiskSource.getPolicies(userId = userId), + ) + .orEmpty() + /** * A helper method to filter policies. */ diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultSyncManagerImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultSyncManagerImpl.kt index 061a34c286..2c86031528 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultSyncManagerImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultSyncManagerImpl.kt @@ -315,6 +315,15 @@ class VaultSyncManagerImpl( } } + // Treat absent network policies as known empty data to + // distinguish between unknown null data. + // The user state update will trigger flows that depend on the latest policies. + // We must store the new policies first to prevent old data on UserState. + authDiskSource.storePolicies( + userId = userId, + policies = syncResponse.policies.orEmpty(), + ) + // Update user information with additional information from sync response authDiskSource.userState = authDiskSource.userState?.toUpdatedUserStateJson( syncResponse = syncResponse, @@ -323,12 +332,6 @@ class VaultSyncManagerImpl( unlockVaultForOrganizationsIfNecessary(syncResponse = syncResponse) storeProfileData(syncResponse = syncResponse) - // Treat absent network policies as known empty data to - // distinguish between unknown null data. - authDiskSource.storePolicies( - userId = userId, - policies = syncResponse.policies.orEmpty(), - ) settingsDiskSource.storeLastSyncTime( userId = userId, lastSyncTime = clock.instant(), diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavScreen.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavScreen.kt index 326f4741e4..82cc882f09 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavScreen.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavScreen.kt @@ -297,6 +297,7 @@ fun RootNavScreen( navController.navigateToVerifyPassword( userId = currentState.userId, navOptions = rootNavOptions, + hasOtherAccounts = false, ) } } diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavViewModel.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavViewModel.kt index b9702ac8d2..623f3185fd 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavViewModel.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavViewModel.kt @@ -89,9 +89,10 @@ class RootNavViewModel @Inject constructor( } specialCircumstance is SpecialCircumstance.CredentialExchangeExport -> { - if (userState.accounts.size == 1) { + val exportableAccounts = userState.accounts.filter { it.isExportable } + if (exportableAccounts.size == 1) { RootNavState.CredentialExchangeExportSkipAccountSelection( - userId = userState.accounts.first().userId, + userId = exportableAccounts.first().userId, ) } else { RootNavState.CredentialExchangeExport diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/ExportItemsNavigation.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/ExportItemsNavigation.kt index 82f03b7094..c9e7a77bc7 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/ExportItemsNavigation.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/ExportItemsNavigation.kt @@ -40,8 +40,11 @@ fun NavGraphBuilder.exportItemsGraph( startDestination = SelectAccountRoute, ) { selectAccountDestination( - onAccountSelected = { - navController.navigateToVerifyPassword(userId = it) + onAccountSelected = { userId, hasOtherAccounts -> + navController.navigateToVerifyPassword( + userId = userId, + hasOtherAccounts = hasOtherAccounts, + ) }, ) verifyPasswordDestination( diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/selectaccount/SelectAccountNavigation.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/selectaccount/SelectAccountNavigation.kt index e36b3fb468..4cdaf756cb 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/selectaccount/SelectAccountNavigation.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/selectaccount/SelectAccountNavigation.kt @@ -20,7 +20,7 @@ data object SelectAccountRoute * Add the [SelectAccountScreen] to the nav graph. */ fun NavGraphBuilder.selectAccountDestination( - onAccountSelected: (id: String) -> Unit, + onAccountSelected: (id: String, hasOtherAccounts: Boolean) -> Unit, ) { composableWithRootPushTransitions { SelectAccountScreen( diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/selectaccount/SelectAccountScreen.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/selectaccount/SelectAccountScreen.kt index 075c9eb87a..679b39b87b 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/selectaccount/SelectAccountScreen.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/selectaccount/SelectAccountScreen.kt @@ -51,7 +51,7 @@ import kotlinx.collections.immutable.persistentListOf @Composable @Suppress("LongMethod") fun SelectAccountScreen( - onAccountSelected: (userId: String) -> Unit, + onAccountSelected: (userId: String, hasOtherAccounts: Boolean) -> Unit, viewModel: SelectAccountViewModel = hiltViewModel(), credentialExchangeCompletionManager: CredentialExchangeCompletionManager = LocalCredentialExchangeCompletionManager.current, @@ -74,7 +74,7 @@ fun SelectAccountScreen( } is SelectAccountEvent.NavigateToPasswordVerification -> { - onAccountSelected(event.userId) + onAccountSelected(event.userId, event.hasOtherAccounts) } is SelectAccountEvent.ValidateImportRequest -> { diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/selectaccount/SelectAccountViewModel.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/selectaccount/SelectAccountViewModel.kt index 58c2d148fb..28a7bf1861 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/selectaccount/SelectAccountViewModel.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/selectaccount/SelectAccountViewModel.kt @@ -99,8 +99,9 @@ class SelectAccountViewModel @Inject constructor( private fun handleAccountClick(action: SelectAccountAction.AccountClick) { sendEvent( - SelectAccountEvent.NavigateToPasswordVerification( - action.userId, + event = SelectAccountEvent.NavigateToPasswordVerification( + userId = action.userId, + hasOtherAccounts = true, ), ) } @@ -119,19 +120,14 @@ class SelectAccountViewModel @Inject constructor( val itemRestrictedOrgIds = action.itemRestrictedOrgs .filter { it.isEnabled } .map { it.organizationId } - val personalOwnershipRestrictedOrgIds = action - .personalOwnershipOrgs - .filter { it.isEnabled } - .map { it.organizationId } val accountSelectionListItems = action.userState ?.accounts .orEmpty() // We only want accounts that do not restrict personal vault ownership + // or vault export .filter { account -> - account - .organizations - .none { org -> org.id in personalOwnershipRestrictedOrgIds } + account.isExportable } .map { account -> AccountSelectionListItem( @@ -164,12 +160,10 @@ class SelectAccountViewModel @Inject constructor( combine( authRepository.userStateFlow, policyManager.getActivePoliciesFlow(PolicyTypeJson.RESTRICT_ITEM_TYPES), - policyManager.getActivePoliciesFlow(PolicyTypeJson.PERSONAL_OWNERSHIP), - ) { userState, itemRestrictedOrgs, personalOwnershipOrgs -> + ) { userState, itemRestrictedOrgs -> SelectAccountAction.Internal.SelectionDataReceive( userState = userState, itemRestrictedOrgs = itemRestrictedOrgs, - personalOwnershipOrgs = personalOwnershipOrgs, ) } .onEach(::handleAction) @@ -255,7 +249,6 @@ sealed class SelectAccountAction { data class SelectionDataReceive( val userState: UserState?, val itemRestrictedOrgs: List, - val personalOwnershipOrgs: List, ) : Internal() } } @@ -282,5 +275,6 @@ sealed class SelectAccountEvent { */ data class NavigateToPasswordVerification( val userId: String, + val hasOtherAccounts: Boolean, ) : SelectAccountEvent() } diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/verifypassword/VerifyPasswordNavigation.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/verifypassword/VerifyPasswordNavigation.kt index 992ad03865..9291c99764 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/verifypassword/VerifyPasswordNavigation.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/verifypassword/VerifyPasswordNavigation.kt @@ -22,6 +22,7 @@ import kotlinx.serialization.Serializable @OmitFromCoverage data class VerifyPasswordRoute( val userId: String, + val hasOtherAccounts: Boolean, ) : Parcelable { /** @@ -38,6 +39,7 @@ data class VerifyPasswordRoute( @OmitFromCoverage data class VerifyPasswordArgs( val userId: String, + val hasOtherAccounts: Boolean, ) /** @@ -47,6 +49,7 @@ fun SavedStateHandle.toVerifyPasswordArgs(): VerifyPasswordArgs { val route = this.toRoute() return VerifyPasswordArgs( userId = route.userId, + hasOtherAccounts = route.hasOtherAccounts, ) } @@ -70,10 +73,14 @@ fun NavGraphBuilder.verifyPasswordDestination( */ fun NavController.navigateToVerifyPassword( userId: String, + hasOtherAccounts: Boolean, navOptions: NavOptions? = null, ) { navigate( - route = VerifyPasswordRoute(userId = userId), + route = VerifyPasswordRoute( + userId = userId, + hasOtherAccounts = hasOtherAccounts, + ), navOptions = navOptions, ) } diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/verifypassword/VerifyPasswordViewModel.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/verifypassword/VerifyPasswordViewModel.kt index 9cd15fa32a..acfa5ed8d1 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/verifypassword/VerifyPasswordViewModel.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/verifypassword/VerifyPasswordViewModel.kt @@ -56,11 +56,7 @@ class VerifyPasswordViewModel @Inject constructor( ?.firstOrNull { it.userId == args.userId } ?: throw IllegalStateException("Account not found") - val singleAccount = authRepository - .userStateFlow - .value - ?.accounts - ?.size == 1 + val singleAccount = !args.hasOtherAccounts val restrictedItemPolicyOrgIds = policyManager .getActivePolicies(PolicyTypeJson.RESTRICT_ITEM_TYPES) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/MainViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/MainViewModelTest.kt index 153b1d62d3..bc490c9def 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/MainViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/MainViewModelTest.kt @@ -1281,6 +1281,7 @@ private val DEFAULT_ACCOUNT = UserState.Account( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = DEFAULT_FIRST_TIME_STATE, + isExportable = true, ) private val DEFAULT_USER_STATE = UserState( diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/manager/UserStateManagerTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/manager/UserStateManagerTest.kt index db7db615e7..35dedba16e 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/manager/UserStateManagerTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/manager/UserStateManagerTest.kt @@ -6,6 +6,8 @@ import com.bitwarden.data.datasource.disk.model.EnvironmentUrlDataJson import com.bitwarden.data.manager.DispatcherManager import com.bitwarden.network.model.GetTokenResponseJson import com.bitwarden.network.model.KdfTypeJson +import com.bitwarden.network.model.PolicyTypeJson +import com.bitwarden.network.model.SyncResponseJson import com.bitwarden.network.model.createMockOrganization import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountJson import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson @@ -16,6 +18,7 @@ import com.x8bit.bitwarden.data.auth.repository.model.VaultUnlockType import com.x8bit.bitwarden.data.auth.repository.util.toOrganizations import com.x8bit.bitwarden.data.auth.repository.util.toUserState import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager +import com.x8bit.bitwarden.data.platform.manager.PolicyManager import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState import com.x8bit.bitwarden.data.vault.manager.VaultLockManager import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData @@ -48,12 +51,16 @@ class UserStateManagerTest { every { isActiveUserUnlockingFlow } returns mutableIsActiveUserUnlockingFlow } private val dispatcherManager: DispatcherManager = FakeDispatcherManager() + private val policyManager: PolicyManager = mockk { + every { getUserPolicies(any(), any()) } returns emptyList() + } private val userStateManager: UserStateManager = UserStateManagerImpl( authDiskSource = fakeAuthDiskSource, firstTimeActionManager = firstTimeActionManager, vaultLockManager = vaultLockManager, dispatcherManager = dispatcherManager, + policyManager = policyManager, ) @BeforeEach @@ -87,6 +94,7 @@ class UserStateManagerTest { vaultUnlockTypeProvider = { VaultUnlockType.MASTER_PASSWORD }, isDeviceTrustedProvider = { false }, firstTimeState = FIRST_TIME_STATE, + getUserPolicies = { _, _ -> emptyList() }, ), awaitItem(), ) @@ -114,6 +122,7 @@ class UserStateManagerTest { isDeviceTrustedProvider = { false }, onboardingStatus = null, firstTimeState = FIRST_TIME_STATE, + getUserPolicies = { _, _ -> emptyList() }, ), awaitItem(), ) @@ -132,6 +141,7 @@ class UserStateManagerTest { isDeviceTrustedProvider = { false }, onboardingStatus = null, firstTimeState = FIRST_TIME_STATE, + getUserPolicies = { _, _ -> emptyList() }, ), awaitItem(), ) @@ -162,6 +172,7 @@ class UserStateManagerTest { isDeviceTrustedProvider = { false }, onboardingStatus = null, firstTimeState = FIRST_TIME_STATE, + getUserPolicies = { _, _ -> emptyList() }, ), awaitItem(), ) @@ -181,6 +192,7 @@ class UserStateManagerTest { isDeviceTrustedProvider = { false }, onboardingStatus = null, firstTimeState = FIRST_TIME_STATE, + getUserPolicies = { _, _ -> emptyList() }, ) val finalUserState = SINGLE_USER_STATE_2.toUserState( vaultState = VAULT_UNLOCK_DATA, @@ -193,6 +205,7 @@ class UserStateManagerTest { isDeviceTrustedProvider = { false }, onboardingStatus = null, firstTimeState = FIRST_TIME_STATE, + getUserPolicies = { _, _ -> emptyList() }, ) fakeAuthDiskSource.userState = SINGLE_USER_STATE_1 @@ -242,6 +255,41 @@ class UserStateManagerTest { userStateManager.hasPendingAccountDeletion = false assertFalse(userStateManager.hasPendingAccountDeletion) } + + @Test + fun `userStateFlow should update isExportable when getUserPolicies returns policies`() = + runTest { + val policy = SyncResponseJson.Policy( + id = "policyId", + organizationId = "mockId-1", + type = PolicyTypeJson.DISABLE_PERSONAL_VAULT_EXPORT, + data = null, + isEnabled = true, + ) + every { policyManager.getUserPolicies(any(), any()) } returns listOf(policy) + + fakeAuthDiskSource.userState = SINGLE_USER_STATE_1 + + val userState = SINGLE_USER_STATE_1.toUserState( + vaultState = VAULT_UNLOCK_DATA, + userAccountTokens = emptyList(), + userOrganizationsList = emptyList(), + userIsUsingKeyConnectorList = emptyList(), + hasPendingAccountAddition = false, + isBiometricsEnabledProvider = { false }, + vaultUnlockTypeProvider = { VaultUnlockType.MASTER_PASSWORD }, + isDeviceTrustedProvider = { false }, + onboardingStatus = null, + firstTimeState = FIRST_TIME_STATE, + getUserPolicies = { _, _ -> listOf(policy) }, + ) + + // Assert + userStateManager.userStateFlow.test { + val actualItem = awaitItem() + assertEquals(userState, actualItem) + } + } } private const val EMAIL_1 = "test@bitwarden.com" diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/util/UserStateJsonExtensionsTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/util/UserStateJsonExtensionsTest.kt index 6090cdb607..2e8bbc5c0d 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/util/UserStateJsonExtensionsTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/util/UserStateJsonExtensionsTest.kt @@ -6,6 +6,7 @@ import com.bitwarden.network.model.KdfTypeJson import com.bitwarden.network.model.KeyConnectorUserDecryptionOptionsJson import com.bitwarden.network.model.MasterPasswordUnlockDataJson import com.bitwarden.network.model.OrganizationType +import com.bitwarden.network.model.PolicyTypeJson import com.bitwarden.network.model.SyncResponseJson import com.bitwarden.network.model.TrustedDeviceUserDecryptionOptionsJson import com.bitwarden.network.model.UserDecryptionJson @@ -389,6 +390,7 @@ class UserStateJsonExtensionsTest { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.NOT_STARTED, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), ), @@ -462,6 +464,7 @@ class UserStateJsonExtensionsTest { isDeviceTrustedProvider = { false }, onboardingStatus = OnboardingStatus.NOT_STARTED, firstTimeState = FirstTimeState(showImportLoginsCard = true), + getUserPolicies = { _, _ -> emptyList() }, ), ) } @@ -502,6 +505,7 @@ class UserStateJsonExtensionsTest { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.NOT_STARTED, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), hasPendingAccountAddition = true, @@ -571,6 +575,7 @@ class UserStateJsonExtensionsTest { isDeviceTrustedProvider = { false }, onboardingStatus = OnboardingStatus.NOT_STARTED, firstTimeState = FirstTimeState(showImportLoginsCard = true), + getUserPolicies = { _, _ -> emptyList() }, ), ) } @@ -617,6 +622,7 @@ class UserStateJsonExtensionsTest { isUsingKeyConnector = true, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), hasPendingAccountAddition = true, @@ -689,6 +695,7 @@ class UserStateJsonExtensionsTest { isDeviceTrustedProvider = { true }, onboardingStatus = null, firstTimeState = FirstTimeState(showImportLoginsCard = true), + getUserPolicies = { _, _ -> emptyList() }, ), ) } @@ -735,6 +742,7 @@ class UserStateJsonExtensionsTest { isUsingKeyConnector = true, onboardingStatus = OnboardingStatus.AUTOFILL_SETUP, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), hasPendingAccountAddition = true, @@ -807,6 +815,7 @@ class UserStateJsonExtensionsTest { isDeviceTrustedProvider = { true }, onboardingStatus = OnboardingStatus.AUTOFILL_SETUP, firstTimeState = FirstTimeState(showImportLoginsCard = true), + getUserPolicies = { _, _ -> emptyList() }, ), ) } @@ -853,6 +862,7 @@ class UserStateJsonExtensionsTest { isUsingKeyConnector = true, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), hasPendingAccountAddition = true, @@ -925,6 +935,7 @@ class UserStateJsonExtensionsTest { isDeviceTrustedProvider = { true }, onboardingStatus = null, firstTimeState = FirstTimeState(showImportLoginsCard = true), + getUserPolicies = { _, _ -> emptyList() }, ), ) } @@ -975,6 +986,7 @@ class UserStateJsonExtensionsTest { isUsingKeyConnector = true, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), hasPendingAccountAddition = true, @@ -1047,6 +1059,7 @@ class UserStateJsonExtensionsTest { isDeviceTrustedProvider = { true }, onboardingStatus = null, firstTimeState = FirstTimeState(showImportLoginsCard = true), + getUserPolicies = { _, _ -> emptyList() }, ), ) } @@ -1076,6 +1089,7 @@ class UserStateJsonExtensionsTest { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), hasPendingAccountAddition = true, @@ -1126,6 +1140,7 @@ class UserStateJsonExtensionsTest { isDeviceTrustedProvider = { true }, onboardingStatus = null, firstTimeState = FirstTimeState(showImportLoginsCard = true), + getUserPolicies = { _, _ -> emptyList() }, ), ) } @@ -1155,6 +1170,7 @@ class UserStateJsonExtensionsTest { isUsingKeyConnector = true, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), hasPendingAccountAddition = true, @@ -1207,6 +1223,7 @@ class UserStateJsonExtensionsTest { isDeviceTrustedProvider = { true }, onboardingStatus = null, firstTimeState = FirstTimeState(showImportLoginsCard = true), + getUserPolicies = { _, _ -> emptyList() }, ), ) } @@ -1254,6 +1271,7 @@ class UserStateJsonExtensionsTest { isUsingKeyConnector = true, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), hasPendingAccountAddition = true, @@ -1328,6 +1346,7 @@ class UserStateJsonExtensionsTest { isDeviceTrustedProvider = { true }, onboardingStatus = null, firstTimeState = FirstTimeState(showImportLoginsCard = true), + getUserPolicies = { _, _ -> emptyList() }, ), ) } @@ -1376,6 +1395,7 @@ class UserStateJsonExtensionsTest { firstTimeState = FirstTimeState( showImportLoginsCard = false, ), + isExportable = true, ), ), hasPendingAccountAddition = true, @@ -1450,6 +1470,255 @@ class UserStateJsonExtensionsTest { firstTimeState = FirstTimeState( showImportLoginsCard = false, ), + getUserPolicies = { _, _ -> emptyList() }, + ), + ) + } + + @Test + fun `toUserState isExportable should be false if organization match policies`() { + assertEquals( + UserState( + activeUserId = "activeUserId", + accounts = listOf( + UserState.Account( + userId = "activeUserId", + name = "activeName", + email = "activeEmail", + avatarColorHex = "activeAvatarColorHex", + environment = Environment.Eu, + isPremium = false, + isLoggedIn = true, + isVaultUnlocked = true, + needsPasswordReset = false, + organizations = listOf( + Organization( + id = "organizationId", + name = "organizationName", + shouldManageResetPassword = false, + shouldUseKeyConnector = false, + role = OrganizationType.ADMIN, + keyConnectorUrl = null, + userIsClaimedByOrganization = false, + ), + ), + isBiometricsEnabled = false, + vaultUnlockType = VaultUnlockType.PIN, + needsMasterPassword = false, + trustedDevice = null, + hasMasterPassword = true, + isUsingKeyConnector = false, + onboardingStatus = OnboardingStatus.NOT_STARTED, + firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = false, + ), + ), + ), + UserStateJson( + activeUserId = "activeUserId", + accounts = mapOf( + "activeUserId" to AccountJson( + profile = mockk { + every { userId } returns "activeUserId" + every { name } returns "activeName" + every { email } returns "activeEmail" + every { avatarColorHex } returns "activeAvatarColorHex" + every { hasPremium } returns null + every { forcePasswordResetReason } returns null + every { userDecryptionOptions } returns UserDecryptionOptionsJson( + hasMasterPassword = true, + trustedDeviceUserDecryptionOptions = null, + keyConnectorUserDecryptionOptions = null, + masterPasswordUnlock = null, + ) + }, + tokens = AccountTokensJson( + accessToken = "accessToken", + refreshToken = "refreshToken", + ), + settings = AccountJson.Settings( + environmentUrlData = EnvironmentUrlDataJson.DEFAULT_EU, + ), + ), + ), + ) + .toUserState( + vaultState = listOf( + VaultUnlockData( + userId = "activeUserId", + status = VaultUnlockData.Status.UNLOCKED, + ), + ), + userAccountTokens = listOf( + UserAccountTokens( + userId = "activeUserId", + accessToken = "accessToken", + refreshToken = "refreshToken", + ), + ), + userOrganizationsList = listOf( + UserOrganizations( + userId = "activeUserId", + organizations = listOf( + Organization( + id = "organizationId", + name = "organizationName", + shouldManageResetPassword = false, + shouldUseKeyConnector = false, + role = OrganizationType.ADMIN, + keyConnectorUrl = null, + userIsClaimedByOrganization = false, + ), + ), + ), + ), + userIsUsingKeyConnectorList = listOf( + UserKeyConnectorState( + userId = "activeUserId", + isUsingKeyConnector = false, + ), + ), + hasPendingAccountAddition = false, + isBiometricsEnabledProvider = { false }, + vaultUnlockTypeProvider = { VaultUnlockType.PIN }, + isDeviceTrustedProvider = { false }, + onboardingStatus = OnboardingStatus.NOT_STARTED, + firstTimeState = FirstTimeState(showImportLoginsCard = true), + getUserPolicies = { _, _ -> + listOf( + SyncResponseJson.Policy( + id = "policyId", + organizationId = "organizationId", + type = PolicyTypeJson.DISABLE_PERSONAL_VAULT_EXPORT, + data = null, + isEnabled = true, + ), + ) + }, + ), + ) + } + + @Test + fun `toUserState isExportable should be true if policies is not enabled`() { + assertEquals( + UserState( + activeUserId = "activeUserId", + accounts = listOf( + UserState.Account( + userId = "activeUserId", + name = "activeName", + email = "activeEmail", + avatarColorHex = "activeAvatarColorHex", + environment = Environment.Eu, + isPremium = false, + isLoggedIn = true, + isVaultUnlocked = true, + needsPasswordReset = false, + organizations = listOf( + Organization( + id = "organizationId", + name = "organizationName", + shouldManageResetPassword = false, + shouldUseKeyConnector = false, + role = OrganizationType.ADMIN, + keyConnectorUrl = null, + userIsClaimedByOrganization = false, + ), + ), + isBiometricsEnabled = false, + vaultUnlockType = VaultUnlockType.PIN, + needsMasterPassword = false, + trustedDevice = null, + hasMasterPassword = true, + isUsingKeyConnector = false, + onboardingStatus = OnboardingStatus.NOT_STARTED, + firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, + ), + ), + ), + UserStateJson( + activeUserId = "activeUserId", + accounts = mapOf( + "activeUserId" to AccountJson( + profile = mockk { + every { userId } returns "activeUserId" + every { name } returns "activeName" + every { email } returns "activeEmail" + every { avatarColorHex } returns "activeAvatarColorHex" + every { hasPremium } returns null + every { forcePasswordResetReason } returns null + every { userDecryptionOptions } returns UserDecryptionOptionsJson( + hasMasterPassword = true, + trustedDeviceUserDecryptionOptions = null, + keyConnectorUserDecryptionOptions = null, + masterPasswordUnlock = null, + ) + }, + tokens = AccountTokensJson( + accessToken = "accessToken", + refreshToken = "refreshToken", + ), + settings = AccountJson.Settings( + environmentUrlData = EnvironmentUrlDataJson.DEFAULT_EU, + ), + ), + ), + ) + .toUserState( + vaultState = listOf( + VaultUnlockData( + userId = "activeUserId", + status = VaultUnlockData.Status.UNLOCKED, + ), + ), + userAccountTokens = listOf( + UserAccountTokens( + userId = "activeUserId", + accessToken = "accessToken", + refreshToken = "refreshToken", + ), + ), + userOrganizationsList = listOf( + UserOrganizations( + userId = "activeUserId", + organizations = listOf( + Organization( + id = "organizationId", + name = "organizationName", + shouldManageResetPassword = false, + shouldUseKeyConnector = false, + role = OrganizationType.ADMIN, + keyConnectorUrl = null, + userIsClaimedByOrganization = false, + ), + ), + ), + ), + userIsUsingKeyConnectorList = listOf( + UserKeyConnectorState( + userId = "activeUserId", + isUsingKeyConnector = false, + ), + ), + hasPendingAccountAddition = false, + isBiometricsEnabledProvider = { false }, + vaultUnlockTypeProvider = { VaultUnlockType.PIN }, + isDeviceTrustedProvider = { false }, + onboardingStatus = OnboardingStatus.NOT_STARTED, + firstTimeState = FirstTimeState(showImportLoginsCard = true), + getUserPolicies = { _, _ -> + listOf( + SyncResponseJson.Policy( + id = "policyId", + organizationId = "organizationId", + type = PolicyTypeJson.DISABLE_PERSONAL_VAULT_EXPORT, + data = null, + isEnabled = false, + ), + ) + }, ), ) } diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/credentials/processor/CredentialProviderProcessorTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/credentials/processor/CredentialProviderProcessorTest.kt index c2023fae89..7e896e71ca 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/credentials/processor/CredentialProviderProcessorTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/credentials/processor/CredentialProviderProcessorTest.kt @@ -526,6 +526,7 @@ private fun createMockAccounts(number: Int): List { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ) } diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/PolicyManagerTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/PolicyManagerTest.kt index 07b9e0f2de..e5581c0404 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/PolicyManagerTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/PolicyManagerTest.kt @@ -221,6 +221,62 @@ class PolicyManagerTest { assertTrue(policyManager.getActivePolicies(type = PolicyTypeJson.RESTRICT_ITEM_TYPES).any()) } + + @Test + fun `getUserPolicies returns empty list if policies is null`() { + every { + authDiskSource.userState + } returns null + + every { + authDiskSource.getPolicies(USER_ID) + } returns null + + assertEquals( + emptyList(), + policyManager.getUserPolicies( + userId = USER_ID, + type = PolicyTypeJson.PERSONAL_OWNERSHIP, + ), + ) + } + + @Test + fun `getUserPolicies returns active and applied Disabled personal vault export policies`() { + val userState: UserStateJson = mockk { + every { activeUserId } returns USER_ID + } + every { authDiskSource.userState } returns userState + every { + authDiskSource.getOrganizations(USER_ID) + } returns listOf( + createMockOrganization( + number = 3, + isEnabled = true, + shouldUsePolicies = true, + type = OrganizationType.USER, + ), + ) + + val listOfPolicies = listOf( + createMockPolicy( + organizationId = "mockId-3", + isEnabled = true, + type = PolicyTypeJson.DISABLE_PERSONAL_VAULT_EXPORT, + ), + ) + every { + authDiskSource.getPolicies(USER_ID) + } returns listOfPolicies + + assertEquals( + listOfPolicies, + policyManager.getUserPolicies( + userId = USER_ID, + type = PolicyTypeJson.DISABLE_PERSONAL_VAULT_EXPORT, + ), + ) + } } private const val USER_ID = "userId" diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/accountsetup/SetupUnlockViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/accountsetup/SetupUnlockViewModelTest.kt index 5dd78563ad..b3a7c71ac2 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/accountsetup/SetupUnlockViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/accountsetup/SetupUnlockViewModelTest.kt @@ -445,6 +445,7 @@ private val DEFAULT_USER_ACCOUNT = UserState.Account( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.ACCOUNT_LOCK_SETUP, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) private val CIPHER = mockk() diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/landing/LandingViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/landing/LandingViewModelTest.kt index 008797ca2f..53b1da992c 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/landing/LandingViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/landing/LandingViewModelTest.kt @@ -95,6 +95,7 @@ class LandingViewModelTest : BaseViewModelTest() { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), ) @@ -247,6 +248,7 @@ class LandingViewModelTest : BaseViewModelTest() { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) val userState = UserState( activeUserId = "activeUserId", @@ -304,6 +306,7 @@ class LandingViewModelTest : BaseViewModelTest() { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) val userState = UserState( activeUserId = "activeUserId", @@ -365,6 +368,7 @@ class LandingViewModelTest : BaseViewModelTest() { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) val userState = UserState( activeUserId = "activeUserId", @@ -528,6 +532,7 @@ class LandingViewModelTest : BaseViewModelTest() { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) val userState = UserState( @@ -564,6 +569,7 @@ class LandingViewModelTest : BaseViewModelTest() { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) val userState = UserState( diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/login/LoginViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/login/LoginViewModelTest.kt index b6aa750b40..51176d60c9 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/login/LoginViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/login/LoginViewModelTest.kt @@ -132,6 +132,7 @@ class LoginViewModelTest : BaseViewModelTest() { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), ) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/removepassword/RemovePasswordViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/removepassword/RemovePasswordViewModelTest.kt index dab6cb2346..4304d53945 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/removepassword/RemovePasswordViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/removepassword/RemovePasswordViewModelTest.kt @@ -304,6 +304,7 @@ private val DEFAULT_ACCOUNT = UserState.Account( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) private val DEFAULT_USER_STATE = UserState( diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/trusteddevice/TrustedDeviceViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/trusteddevice/TrustedDeviceViewModelTest.kt index ffd355ca49..5548580a08 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/trusteddevice/TrustedDeviceViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/trusteddevice/TrustedDeviceViewModelTest.kt @@ -293,6 +293,7 @@ private val DEFAULT_ACCOUNT = UserState.Account( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) private val DEFAULT_USER_STATE = UserState( diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/vaultunlock/VaultUnlockViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/vaultunlock/VaultUnlockViewModelTest.kt index beb1aeddc5..34f7c69df0 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/vaultunlock/VaultUnlockViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/auth/feature/vaultunlock/VaultUnlockViewModelTest.kt @@ -269,6 +269,7 @@ class VaultUnlockViewModelTest : BaseViewModelTest() { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), ) @@ -309,6 +310,7 @@ class VaultUnlockViewModelTest : BaseViewModelTest() { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), ) @@ -1413,6 +1415,7 @@ private val DEFAULT_ACCOUNT = UserState.Account( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) private val DEFAULT_USER_STATE = UserState( diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavScreenTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavScreenTest.kt index a3a7693cca..5dca1e5e2c 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavScreenTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavScreenTest.kt @@ -466,6 +466,7 @@ class RootNavScreenTest : BitwardenComposeTest() { mockNavHostController.navigate( route = VerifyPasswordRoute( userId = "activeUserId", + hasOtherAccounts = false, ), navOptions = expectedNavOptions, ) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavViewModelTest.kt index ea4fab0f3a..ceeaa4ae4d 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavViewModelTest.kt @@ -114,6 +114,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -151,6 +152,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -185,6 +187,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -229,6 +232,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -270,6 +274,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -311,6 +316,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -349,6 +355,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), hasPendingAccountAddition = true, @@ -402,6 +409,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -437,6 +445,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -477,6 +486,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -515,6 +525,7 @@ class RootNavViewModelTest : BaseViewModelTest() { isUsingKeyConnector = false, firstTimeState = FirstTimeState(false), onboardingStatus = OnboardingStatus.COMPLETE, + isExportable = true, ), ), ), @@ -558,6 +569,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -601,6 +613,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -651,6 +664,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -699,6 +713,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -744,6 +759,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -789,6 +805,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -924,6 +941,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -978,6 +996,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -1040,6 +1059,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -1082,6 +1102,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -1119,6 +1140,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -1154,6 +1176,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -1192,6 +1215,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -1230,6 +1254,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -1268,6 +1293,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -1306,6 +1332,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -1344,6 +1371,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -1382,6 +1410,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -1420,6 +1449,7 @@ class RootNavViewModelTest : BaseViewModelTest() { firstTimeState = FirstTimeState( showImportLoginsCard = true, ), + isExportable = true, ), ), ), @@ -1504,6 +1534,7 @@ private val MOCK_VAULT_UNLOCKED_USER_STATE = UserState( isUsingKeyConnector = false, firstTimeState = FirstTimeState(false), onboardingStatus = OnboardingStatus.COMPLETE, + isExportable = true, ), ), ) @@ -1529,6 +1560,7 @@ private val MOCK_VAULT_UNLOCKED_USER_MULTIPLE_ACCOUNTS_STATE = UserState( isUsingKeyConnector = false, firstTimeState = FirstTimeState(false), onboardingStatus = OnboardingStatus.COMPLETE, + isExportable = true, ), UserState.Account( @@ -1549,6 +1581,7 @@ private val MOCK_VAULT_UNLOCKED_USER_MULTIPLE_ACCOUNTS_STATE = UserState( isUsingKeyConnector = false, firstTimeState = FirstTimeState(false), onboardingStatus = OnboardingStatus.COMPLETE, + isExportable = true, ), ), ) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt index 0a736731b9..ecadb5c4ed 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/search/SearchViewModelTest.kt @@ -1863,6 +1863,7 @@ private val DEFAULT_USER_STATE = UserState( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), ) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModelTest.kt index 386c94e203..fb308297c3 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModelTest.kt @@ -981,6 +981,7 @@ private val DEFAULT_USER_STATE = UserState( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), ) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/deleteaccount/DeleteAccountViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/deleteaccount/DeleteAccountViewModelTest.kt index 008373b064..f4a15f527c 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/deleteaccount/DeleteAccountViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/deleteaccount/DeleteAccountViewModelTest.kt @@ -248,6 +248,7 @@ private val DEFAULT_USER_STATE: UserState = UserState( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), ) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/loginapproval/LoginApprovalViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/loginapproval/LoginApprovalViewModelTest.kt index ef75d74486..fc1c3da34e 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/loginapproval/LoginApprovalViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/loginapproval/LoginApprovalViewModelTest.kt @@ -496,6 +496,7 @@ private val DEFAULT_USER_STATE = UserState( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), UserState.Account( userId = USER_ID_2, @@ -515,6 +516,7 @@ private val DEFAULT_USER_STATE = UserState( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), ) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/exportvault/ExportVaultViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/exportvault/ExportVaultViewModelTest.kt index 9c0ea4c67d..0d8e88a2b6 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/exportvault/ExportVaultViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/platform/feature/settings/exportvault/ExportVaultViewModelTest.kt @@ -855,6 +855,7 @@ private val DEFAULT_USER_STATE = UserState( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), ) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/tools/feature/generator/GeneratorViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/tools/feature/generator/GeneratorViewModelTest.kt index d13b9efdd1..ebb6a618e1 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/tools/feature/generator/GeneratorViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/tools/feature/generator/GeneratorViewModelTest.kt @@ -2635,6 +2635,7 @@ private val DEFAULT_USER_STATE = UserState( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), ) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModelTest.kt index 5fd741211b..c898bfc862 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModelTest.kt @@ -706,6 +706,7 @@ private val DEFAULT_USER_ACCOUNT_STATE = UserState.Account( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) private val DEFAULT_USER_STATE = UserState( diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/tools/feature/send/addedit/AddEditSendViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/tools/feature/send/addedit/AddEditSendViewModelTest.kt index f0203b92f5..4e39c6721e 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/tools/feature/send/addedit/AddEditSendViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/tools/feature/send/addedit/AddEditSendViewModelTest.kt @@ -1075,6 +1075,7 @@ private val DEFAULT_ACCOUNT = UserState.Account( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) private val DEFAULT_USER_STATE = UserState( diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt index 6134a179e1..baba75b44f 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt @@ -4782,6 +4782,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), hasPendingAccountAddition = false, diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensionsTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensionsTest.kt index dbcec749a8..7a30728f66 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensionsTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensionsTest.kt @@ -629,6 +629,7 @@ class CipherViewExtensionsTest { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) } diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/attachments/AttachmentsViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/attachments/AttachmentsViewModelTest.kt index 6e92ec9c9e..54eb9b6172 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/attachments/AttachmentsViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/attachments/AttachmentsViewModelTest.kt @@ -659,6 +659,7 @@ private val DEFAULT_USER_STATE = UserState( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), ) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/SelectAccountScreenTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/SelectAccountScreenTest.kt index e836704fc9..0a8fb5f168 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/SelectAccountScreenTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/SelectAccountScreenTest.kt @@ -53,7 +53,7 @@ class SelectAccountScreenTest : BitwardenComposeTest() { credentialExchangeRequestValidator = credentialExchangeRequestValidator, ) { SelectAccountScreen( - onAccountSelected = { onAccountSelectedCalled = true }, + onAccountSelected = { _, _ -> onAccountSelectedCalled = true }, viewModel = viewModel, ) } @@ -126,6 +126,7 @@ class SelectAccountScreenTest : BitwardenComposeTest() { mockEventFlow.emit( SelectAccountEvent.NavigateToPasswordVerification( userId = ACTIVE_ACCOUNT_SUMMARY.userId, + hasOtherAccounts = true, ), ) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/SelectAccountViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/SelectAccountViewModelTest.kt index d6e8f63b0f..d306f1c65b 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/SelectAccountViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/SelectAccountViewModelTest.kt @@ -127,7 +127,6 @@ class SelectAccountViewModelTest : BaseViewModelTest() { verify(Ordering.ORDERED) { authRepository.userStateFlow policyManager.getActivePoliciesFlow(PolicyTypeJson.RESTRICT_ITEM_TYPES) - policyManager.getActivePoliciesFlow(PolicyTypeJson.PERSONAL_OWNERSHIP) } } @@ -146,7 +145,6 @@ class SelectAccountViewModelTest : BaseViewModelTest() { SelectAccountAction.Internal.SelectionDataReceive( userState = DEFAULT_USER_STATE, itemRestrictedOrgs = emptyList(), - personalOwnershipOrgs = emptyList(), ), ) @@ -166,6 +164,7 @@ class SelectAccountViewModelTest : BaseViewModelTest() { val viewModel = createViewModel() val organizationId = "mockOrganizationId-1" val accountInOrg = DEFAULT_ACCOUNT.copy( + isExportable = false, organizations = listOf( Organization( id = organizationId, @@ -183,13 +182,6 @@ class SelectAccountViewModelTest : BaseViewModelTest() { SelectAccountAction.Internal.SelectionDataReceive( userState = DEFAULT_USER_STATE.copy(accounts = listOf(accountInOrg)), itemRestrictedOrgs = emptyList(), - personalOwnershipOrgs = listOf( - createMockPolicy( - number = 1, - id = organizationId, - isEnabled = true, - ), - ), ), ) assertEquals( @@ -237,7 +229,6 @@ class SelectAccountViewModelTest : BaseViewModelTest() { isEnabled = true, ), ), - personalOwnershipOrgs = emptyList(), ), ) assertEquals( @@ -277,6 +268,7 @@ class SelectAccountViewModelTest : BaseViewModelTest() { assertEquals( SelectAccountEvent.NavigateToPasswordVerification( userId = DEFAULT_ACCOUNT.userId, + hasOtherAccounts = true, ), awaitItem(), ) @@ -308,6 +300,7 @@ private val DEFAULT_ACCOUNT = UserState.Account( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) private val DEFAULT_USER_STATE = UserState( diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/reviewexport/ReviewExportViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/reviewexport/ReviewExportViewModelTest.kt index 20f25ef464..18ccbffbfa 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/reviewexport/ReviewExportViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/reviewexport/ReviewExportViewModelTest.kt @@ -459,6 +459,7 @@ private val DEFAULT_USER_STATE = UserState( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), ) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/verifypassword/VerifyPasswordScreenTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/verifypassword/VerifyPasswordScreenTest.kt index ef335c579e..86e314cddd 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/verifypassword/VerifyPasswordScreenTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/verifypassword/VerifyPasswordScreenTest.kt @@ -281,6 +281,7 @@ private val DEFAULT_USER_STATE = UserState( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), ) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/verifypassword/VerifyPasswordViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/verifypassword/VerifyPasswordViewModelTest.kt index d57b9fb6a3..18f2568145 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/verifypassword/VerifyPasswordViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/verifypassword/VerifyPasswordViewModelTest.kt @@ -708,6 +708,7 @@ class VerifyPasswordViewModelTest : BaseViewModelTest() { toVerifyPasswordArgs() } returns VerifyPasswordArgs( userId = DEFAULT_USER_ID, + hasOtherAccounts = true, ) }, ) @@ -746,6 +747,7 @@ private val DEFAULT_USER_STATE = UserState( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), UserState.Account( @@ -776,6 +778,7 @@ private val DEFAULT_USER_STATE = UserState( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), ) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModelTest.kt index 76cadc87a7..e55a624a06 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModelTest.kt @@ -2580,6 +2580,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) private val DEFAULT_USER_STATE: UserState = UserState( diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt index f58fc6c379..78e09ee31d 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt @@ -5878,6 +5878,7 @@ private val DEFAULT_ACCOUNT = UserState.Account( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) private val DEFAULT_USER_STATE = UserState( diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/VaultMoveToOrganizationViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/VaultMoveToOrganizationViewModelTest.kt index 67b6918345..c3d5a6f140 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/VaultMoveToOrganizationViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/VaultMoveToOrganizationViewModelTest.kt @@ -556,6 +556,7 @@ private val DEFAULT_USER_STATE = UserState( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), ) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/util/VaultMoveToOrganizationExtensionsTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/util/VaultMoveToOrganizationExtensionsTest.kt index f38cb86916..789da1bb88 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/util/VaultMoveToOrganizationExtensionsTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/movetoorganization/util/VaultMoveToOrganizationExtensionsTest.kt @@ -138,6 +138,7 @@ private fun createMockUserState(hasOrganizations: Boolean = true): UserState = isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), ) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModelTest.kt index 0e84772992..f801758d23 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModelTest.kt @@ -309,6 +309,7 @@ class VaultViewModelTest : BaseViewModelTest() { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = DEFAULT_FIRST_TIME_STATE, + isExportable = true, ), ), ) @@ -397,6 +398,7 @@ class VaultViewModelTest : BaseViewModelTest() { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = DEFAULT_FIRST_TIME_STATE, + isExportable = true, ), ), ) @@ -3166,6 +3168,7 @@ private val DEFAULT_USER_STATE = UserState( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = DEFAULT_FIRST_TIME_STATE, + isExportable = true, ), UserState.Account( userId = "lockedUserId", @@ -3185,6 +3188,7 @@ private val DEFAULT_USER_STATE = UserState( isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = DEFAULT_FIRST_TIME_STATE, + isExportable = true, ), ), ) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/util/UserStateExtensionsTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/util/UserStateExtensionsTest.kt index 51c3f172f3..3de647979b 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/util/UserStateExtensionsTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/vault/util/UserStateExtensionsTest.kt @@ -91,6 +91,7 @@ class UserStateExtensionsTest { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), UserState.Account( userId = "lockedUserId", @@ -120,6 +121,7 @@ class UserStateExtensionsTest { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), UserState.Account( userId = "unlockedUserId", @@ -153,6 +155,7 @@ class UserStateExtensionsTest { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), UserState.Account( userId = "loggedOutUserId", @@ -186,6 +189,7 @@ class UserStateExtensionsTest { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), ) @@ -234,6 +238,7 @@ class UserStateExtensionsTest { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) .toAccountSummary(isActive = true), ) @@ -280,6 +285,7 @@ class UserStateExtensionsTest { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) .toAccountSummary(isActive = false), ) @@ -330,6 +336,7 @@ class UserStateExtensionsTest { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ), ), ) @@ -358,6 +365,7 @@ class UserStateExtensionsTest { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) .toVaultFilterData(isIndividualVaultDisabled = false), ) @@ -419,6 +427,7 @@ class UserStateExtensionsTest { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) .toVaultFilterData( isIndividualVaultDisabled = false, @@ -481,6 +490,7 @@ class UserStateExtensionsTest { isUsingKeyConnector = false, onboardingStatus = OnboardingStatus.COMPLETE, firstTimeState = FirstTimeState(showImportLoginsCard = true), + isExportable = true, ) .toVaultFilterData( isIndividualVaultDisabled = true,