From b715a5118859556be7b3f2670cb7e023afe8339e Mon Sep 17 00:00:00 2001 From: aj-rosado <109146700+aj-rosado@users.noreply.github.com> Date: Thu, 6 Nov 2025 16:54:22 +0000 Subject: [PATCH] [PM-27806] Reverted changes to order of StorePolicies after sync (#6130) --- .../vault/manager/VaultSyncManagerImpl.kt | 76 ++++++++++--------- .../vault/manager/di/VaultManagerModule.kt | 3 + .../vault/manager/VaultSyncManagerTest.kt | 7 ++ 3 files changed, 50 insertions(+), 36 deletions(-) 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 7c6fffa4f2..b2356ccfb9 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 @@ -14,6 +14,7 @@ import com.bitwarden.vault.DecryptCipherListResult import com.bitwarden.vault.FolderView import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource import com.x8bit.bitwarden.data.auth.manager.UserLogoutManager +import com.x8bit.bitwarden.data.auth.manager.UserStateManager import com.x8bit.bitwarden.data.auth.repository.model.LogoutReason import com.x8bit.bitwarden.data.auth.repository.util.toUpdatedUserStateJson import com.x8bit.bitwarden.data.auth.repository.util.userSwitchingChangesFlow @@ -78,6 +79,7 @@ class VaultSyncManagerImpl( private val vaultDiskSource: VaultDiskSource, private val vaultSdkSource: VaultSdkSource, private val userLogoutManager: UserLogoutManager, + private val userStateManager: UserStateManager, private val vaultLockManager: VaultLockManager, private val clock: Clock, databaseSchemeManager: DatabaseSchemeManager, @@ -301,44 +303,46 @@ class VaultSyncManagerImpl( return syncService.sync().fold( onSuccess = { syncResponse -> - val localSecurityStamp = authDiskSource.userState?.activeAccount?.profile?.stamp - val serverSecurityStamp = syncResponse.profile.securityStamp - // Log the user out if the stamps do not match - localSecurityStamp?.let { - if (serverSecurityStamp != localSecurityStamp) { - // Ensure UserLogoutManager is available - userLogoutManager.softLogout( - userId = userId, - reason = LogoutReason.SecurityStamp, - ) - return SyncVaultDataResult.Error(SecurityStampMismatchException()) + userStateManager.userStateTransaction { + val localSecurityStamp = authDiskSource.userState?.activeAccount?.profile?.stamp + val serverSecurityStamp = syncResponse.profile.securityStamp + // Log the user out if the stamps do not match + localSecurityStamp?.let { + if (serverSecurityStamp != localSecurityStamp) { + // Ensure UserLogoutManager is available + userLogoutManager.softLogout( + userId = userId, + reason = LogoutReason.SecurityStamp, + ) + return@userStateTransaction SyncVaultDataResult.Error( + SecurityStampMismatchException(), + ) + } } + + // Update user information with additional information from sync response + authDiskSource.userState = authDiskSource.userState?.toUpdatedUserStateJson( + syncResponse = syncResponse, + ) + + 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(), + ) + vaultDiskSource.replaceVaultData(userId = userId, vault = syncResponse) + val itemsAvailable = syncResponse.ciphers?.isNotEmpty() == true + SyncVaultDataResult.Success(itemsAvailable = itemsAvailable) } - - // 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, - ) - - unlockVaultForOrganizationsIfNecessary(syncResponse = syncResponse) - storeProfileData(syncResponse = syncResponse) - - settingsDiskSource.storeLastSyncTime( - userId = userId, - lastSyncTime = clock.instant(), - ) - vaultDiskSource.replaceVaultData(userId = userId, vault = syncResponse) - val itemsAvailable = syncResponse.ciphers?.isNotEmpty() == true - SyncVaultDataResult.Success(itemsAvailable = itemsAvailable) }, onFailure = { updateVaultStateFlowsToError(throwable = it) diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/di/VaultManagerModule.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/di/VaultManagerModule.kt index 8f61ba9512..74d9372ff8 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/di/VaultManagerModule.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/di/VaultManagerModule.kt @@ -13,6 +13,7 @@ import com.x8bit.bitwarden.data.auth.datasource.sdk.AuthSdkSource import com.x8bit.bitwarden.data.auth.manager.KdfManager import com.x8bit.bitwarden.data.auth.manager.TrustedDeviceManager import com.x8bit.bitwarden.data.auth.manager.UserLogoutManager +import com.x8bit.bitwarden.data.auth.manager.UserStateManager import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource import com.x8bit.bitwarden.data.platform.manager.AppStateManager import com.x8bit.bitwarden.data.platform.manager.DatabaseSchemeManager @@ -182,6 +183,7 @@ object VaultManagerModule { vaultDiskSource: VaultDiskSource, vaultSdkSource: VaultSdkSource, userLogoutManager: UserLogoutManager, + userStateManager: UserStateManager, vaultLockManager: VaultLockManager, clock: Clock, databaseSchemeManager: DatabaseSchemeManager, @@ -194,6 +196,7 @@ object VaultManagerModule { vaultDiskSource = vaultDiskSource, vaultSdkSource = vaultSdkSource, userLogoutManager = userLogoutManager, + userStateManager = userStateManager, vaultLockManager = vaultLockManager, clock = clock, databaseSchemeManager = databaseSchemeManager, diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultSyncManagerTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultSyncManagerTest.kt index 3bd1a71961..7a4291240a 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultSyncManagerTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultSyncManagerTest.kt @@ -29,6 +29,7 @@ import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountTokensJson import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson import com.x8bit.bitwarden.data.auth.datasource.disk.util.FakeAuthDiskSource import com.x8bit.bitwarden.data.auth.manager.UserLogoutManager +import com.x8bit.bitwarden.data.auth.manager.UserStateManager import com.x8bit.bitwarden.data.auth.repository.model.LogoutReason import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource import com.x8bit.bitwarden.data.platform.error.MissingPropertyException @@ -64,6 +65,7 @@ import io.mockk.just import io.mockk.mockk import io.mockk.mockkConstructor import io.mockk.runs +import io.mockk.slot import io.mockk.unmockkConstructor import io.mockk.verify import kotlinx.coroutines.flow.Flow @@ -126,6 +128,10 @@ class VaultSyncManagerTest { private val userLogoutManager: UserLogoutManager = mockk { every { softLogout(any(), any()) } just runs } + private val userStateManager: UserStateManager = mockk { + val blockSlot = slot SyncVaultDataResult>() + coEvery { userStateTransaction(capture(blockSlot)) } coAnswers { blockSlot.captured() } + } private val mutableFullSyncFlow = bufferedMutableSharedFlow() private val pushManager: PushManager = mockk { every { fullSyncFlow } returns mutableFullSyncFlow @@ -142,6 +148,7 @@ class VaultSyncManagerTest { vaultDiskSource = vaultDiskSource, vaultSdkSource = vaultSdkSource, userLogoutManager = userLogoutManager, + userStateManager = userStateManager, vaultLockManager = vaultLockManager, clock = clock, databaseSchemeManager = databaseSchemeManager,