Skip to content

Commit d07b119

Browse files
authored
[PM-27120] cxp hide user account when remove individual export is enabled (#6089)
1 parent dbf2e9f commit d07b119

File tree

50 files changed

+553
-43
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+553
-43
lines changed

app/src/main/kotlin/com/x8bit/bitwarden/data/auth/manager/UserStateManagerImpl.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.x8bit.bitwarden.data.auth.manager
22

33
import com.bitwarden.data.manager.DispatcherManager
4+
import com.bitwarden.network.model.PolicyTypeJson
5+
import com.bitwarden.network.model.SyncResponseJson
46
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
57
import com.x8bit.bitwarden.data.auth.datasource.disk.model.OnboardingStatus
68
import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson
@@ -19,6 +21,7 @@ import com.x8bit.bitwarden.data.auth.repository.util.userKeyConnectorStateList
1921
import com.x8bit.bitwarden.data.auth.repository.util.userOrganizationsList
2022
import com.x8bit.bitwarden.data.auth.repository.util.userOrganizationsListFlow
2123
import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager
24+
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
2225
import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState
2326
import com.x8bit.bitwarden.data.vault.manager.VaultLockManager
2427
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData
@@ -39,6 +42,7 @@ class UserStateManagerImpl(
3942
private val authDiskSource: AuthDiskSource,
4043
firstTimeActionManager: FirstTimeActionManager,
4144
vaultLockManager: VaultLockManager,
45+
private val policyManager: PolicyManager,
4246
dispatcherManager: DispatcherManager,
4347
) : UserStateManager {
4448
private val unconfinedScope = CoroutineScope(dispatcherManager.unconfined)
@@ -110,6 +114,7 @@ class UserStateManagerImpl(
110114
vaultUnlockTypeProvider = ::getVaultUnlockType,
111115
isDeviceTrustedProvider = ::isDeviceTrusted,
112116
firstTimeState = firstTimeState,
117+
getUserPolicies = ::existingPolicies,
113118
)
114119
}
115120
.filterNot {
@@ -133,6 +138,7 @@ class UserStateManagerImpl(
133138
vaultUnlockTypeProvider = ::getVaultUnlockType,
134139
isDeviceTrustedProvider = ::isDeviceTrusted,
135140
firstTimeState = firstTimeActionManager.currentOrDefaultUserFirstTimeState,
141+
getUserPolicies = ::existingPolicies,
136142
),
137143
)
138144

@@ -159,4 +165,12 @@ class UserStateManagerImpl(
159165
.getPinProtectedUserKeyEnvelope(userId = userId)
160166
?.let { VaultUnlockType.PIN }
161167
?: VaultUnlockType.MASTER_PASSWORD
168+
169+
private fun existingPolicies(
170+
userId: String,
171+
policyType: PolicyTypeJson,
172+
): List<SyncResponseJson.Policy> = policyManager.getUserPolicies(
173+
userId = userId,
174+
type = policyType,
175+
)
162176
}

app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/di/AuthRepositoryModule.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,13 @@ object AuthRepositoryModule {
102102
authDiskSource: AuthDiskSource,
103103
firstTimeActionManager: FirstTimeActionManager,
104104
vaultLockManager: VaultLockManager,
105+
policyManager: PolicyManager,
105106
dispatcherManager: DispatcherManager,
106107
): UserStateManager = UserStateManagerImpl(
107108
authDiskSource = authDiskSource,
108109
firstTimeActionManager = firstTimeActionManager,
109110
vaultLockManager = vaultLockManager,
111+
policyManager = policyManager,
110112
dispatcherManager = dispatcherManager,
111113
)
112114
}

app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/model/UserState.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ data class UserState(
7575
val isUsingKeyConnector: Boolean,
7676
val onboardingStatus: OnboardingStatus,
7777
val firstTimeState: FirstTimeState,
78+
val isExportable: Boolean,
7879
) {
7980
/**
8081
* Indicates that the user does or does not have a means to manually unlock the vault.

app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/util/UserStateJsonExtensions.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.x8bit.bitwarden.data.auth.repository.util
33
import com.bitwarden.data.repository.util.toEnvironmentUrlsOrDefault
44
import com.bitwarden.network.model.KdfTypeJson
55
import com.bitwarden.network.model.OrganizationType
6+
import com.bitwarden.network.model.PolicyTypeJson
67
import com.bitwarden.network.model.SyncResponseJson
78
import com.bitwarden.network.model.UserDecryptionOptionsJson
89
import com.bitwarden.ui.platform.base.util.toHexColorRepresentation
@@ -164,6 +165,7 @@ fun UserStateJson.toUserState(
164165
isBiometricsEnabledProvider: (userId: String) -> Boolean,
165166
vaultUnlockTypeProvider: (userId: String) -> VaultUnlockType,
166167
isDeviceTrustedProvider: (userId: String) -> Boolean,
168+
getUserPolicies: (userId: String, policy: PolicyTypeJson) -> List<SyncResponseJson.Policy>,
167169
): UserState =
168170
UserState(
169171
activeUserId = this.activeUserId,
@@ -203,6 +205,19 @@ fun UserStateJson.toUserState(
203205
hasManageResetPasswordPermission.takeIf { trustedDevice != null }
204206
val needsMasterPassword = decryptionOptions?.hasMasterPassword == false &&
205207
(tdeUserNeedsMasterPassword ?: (keyConnectorOptions == null))
208+
209+
val hasPersonalOwnershipRestrictedOrg = getUserPolicies(
210+
userId,
211+
PolicyTypeJson.PERSONAL_OWNERSHIP,
212+
)
213+
.any { it.isEnabled }
214+
215+
val hasPersonalVaultExportRestrictedOrg = getUserPolicies(
216+
userId,
217+
PolicyTypeJson.DISABLE_PERSONAL_VAULT_EXPORT,
218+
)
219+
.any { it.isEnabled }
220+
206221
UserState.Account(
207222
userId = userId,
208223
name = profile.name,
@@ -231,6 +246,8 @@ fun UserStateJson.toUserState(
231246
// using the app prior to the release of the onboarding flow.
232247
onboardingStatus = onboardingStatus ?: OnboardingStatus.COMPLETE,
233248
firstTimeState = firstTimeState,
249+
isExportable = !hasPersonalOwnershipRestrictedOrg &&
250+
!hasPersonalVaultExportRestrictedOrg,
234251
)
235252
},
236253
hasPendingAccountAddition = hasPendingAccountAddition,

app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/PolicyManager.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,12 @@ interface PolicyManager {
1717
* Get all the policies of the given [type] that are enabled and applicable to the user.
1818
*/
1919
fun getActivePolicies(type: PolicyTypeJson): List<SyncResponseJson.Policy>
20+
21+
/**
22+
* Get all the policies of the given [type] that are enabled and applicable to the [userId].
23+
*/
24+
fun getUserPolicies(
25+
userId: String,
26+
type: PolicyTypeJson,
27+
): List<SyncResponseJson.Policy>
2028
}

app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/PolicyManagerImpl.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@ class PolicyManagerImpl(
5454
}
5555
?: emptyList()
5656

57+
override fun getUserPolicies(
58+
userId: String,
59+
type: PolicyTypeJson,
60+
): List<SyncResponseJson.Policy> =
61+
this
62+
.filterPolicies(
63+
userId = userId,
64+
type = type,
65+
policies = authDiskSource.getPolicies(userId = userId),
66+
)
67+
.orEmpty()
68+
5769
/**
5870
* A helper method to filter policies.
5971
*/

app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultSyncManagerImpl.kt

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,15 @@ class VaultSyncManagerImpl(
315315
}
316316
}
317317

318+
// Treat absent network policies as known empty data to
319+
// distinguish between unknown null data.
320+
// The user state update will trigger flows that depend on the latest policies.
321+
// We must store the new policies first to prevent old data on UserState.
322+
authDiskSource.storePolicies(
323+
userId = userId,
324+
policies = syncResponse.policies.orEmpty(),
325+
)
326+
318327
// Update user information with additional information from sync response
319328
authDiskSource.userState = authDiskSource.userState?.toUpdatedUserStateJson(
320329
syncResponse = syncResponse,
@@ -323,12 +332,6 @@ class VaultSyncManagerImpl(
323332
unlockVaultForOrganizationsIfNecessary(syncResponse = syncResponse)
324333
storeProfileData(syncResponse = syncResponse)
325334

326-
// Treat absent network policies as known empty data to
327-
// distinguish between unknown null data.
328-
authDiskSource.storePolicies(
329-
userId = userId,
330-
policies = syncResponse.policies.orEmpty(),
331-
)
332335
settingsDiskSource.storeLastSyncTime(
333336
userId = userId,
334337
lastSyncTime = clock.instant(),

app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavScreen.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ fun RootNavScreen(
297297
navController.navigateToVerifyPassword(
298298
userId = currentState.userId,
299299
navOptions = rootNavOptions,
300+
hasOtherAccounts = false,
300301
)
301302
}
302303
}

app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavViewModel.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,10 @@ class RootNavViewModel @Inject constructor(
8989
}
9090

9191
specialCircumstance is SpecialCircumstance.CredentialExchangeExport -> {
92-
if (userState.accounts.size == 1) {
92+
val exportableAccounts = userState.accounts.filter { it.isExportable }
93+
if (exportableAccounts.size == 1) {
9394
RootNavState.CredentialExchangeExportSkipAccountSelection(
94-
userId = userState.accounts.first().userId,
95+
userId = exportableAccounts.first().userId,
9596
)
9697
} else {
9798
RootNavState.CredentialExchangeExport

app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/exportitems/ExportItemsNavigation.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,11 @@ fun NavGraphBuilder.exportItemsGraph(
4040
startDestination = SelectAccountRoute,
4141
) {
4242
selectAccountDestination(
43-
onAccountSelected = {
44-
navController.navigateToVerifyPassword(userId = it)
43+
onAccountSelected = { userId, hasOtherAccounts ->
44+
navController.navigateToVerifyPassword(
45+
userId = userId,
46+
hasOtherAccounts = hasOtherAccounts,
47+
)
4548
},
4649
)
4750
verifyPasswordDestination(

0 commit comments

Comments
 (0)