From 150d671e9dd218d5e001c68e8b2c001da27305bb Mon Sep 17 00:00:00 2001 From: David Perez Date: Thu, 26 Mar 2026 15:39:17 -0500 Subject: [PATCH] PM-34193: Rollback SDK update for Vault lockout bug --- .../manager/sdk/SdkRepositoryFactoryImpl.kt | 5 - .../SdkLocalUserDataKeyStateRepository.kt | 49 ----- .../vault/manager/VaultLockManagerImpl.kt | 1 - .../util/InitUserCryptoMethodExtensions.kt | 1 - .../SdkLocalUserDataKeyStateRepositoryTest.kt | 171 ------------------ gradle/libs.versions.toml | 2 +- 6 files changed, 1 insertion(+), 228 deletions(-) delete mode 100644 app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/sdk/repository/SdkLocalUserDataKeyStateRepository.kt delete mode 100644 app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/sdk/repository/SdkLocalUserDataKeyStateRepositoryTest.kt diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/sdk/SdkRepositoryFactoryImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/sdk/SdkRepositoryFactoryImpl.kt index adeb833a95..30f11cc50b 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/sdk/SdkRepositoryFactoryImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/sdk/SdkRepositoryFactoryImpl.kt @@ -7,7 +7,6 @@ import com.bitwarden.sdk.ServerCommunicationConfigRepository import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource import com.x8bit.bitwarden.data.platform.datasource.disk.CookieDiskSource import com.x8bit.bitwarden.data.platform.manager.sdk.repository.SdkCipherRepository -import com.x8bit.bitwarden.data.platform.manager.sdk.repository.SdkLocalUserDataKeyStateRepository import com.x8bit.bitwarden.data.platform.manager.sdk.repository.SdkTokenRepository import com.x8bit.bitwarden.data.platform.manager.sdk.repository.ServerCommunicationConfigRepositoryImpl import com.x8bit.bitwarden.data.vault.datasource.disk.VaultDiskSource @@ -26,10 +25,6 @@ class SdkRepositoryFactoryImpl( cipher = getSdkRepository(userId = userId), folder = null, userKeyState = null, - localUserDataKeyState = SdkLocalUserDataKeyStateRepository( - authDiskSource = authDiskSource, - ), - ephemeralPinEnvelopeState = null, ) override fun getClientManagedTokens( diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/sdk/repository/SdkLocalUserDataKeyStateRepository.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/sdk/repository/SdkLocalUserDataKeyStateRepository.kt deleted file mode 100644 index d483553e03..0000000000 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/sdk/repository/SdkLocalUserDataKeyStateRepository.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.x8bit.bitwarden.data.platform.manager.sdk.repository - -import com.bitwarden.core.LocalUserDataKeyState -import com.bitwarden.sdk.LocalUserDataKeyStateRepository -import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource - -/** - * An implementation of a Bitwarden SDK [LocalUserDataKeyStateRepository]. - */ -class SdkLocalUserDataKeyStateRepository( - private val authDiskSource: AuthDiskSource, -) : LocalUserDataKeyStateRepository { - override suspend fun get(id: String): LocalUserDataKeyState? { - return authDiskSource - .getLocalUserDataKey(userId = id) - ?.let { LocalUserDataKeyState(wrappedKey = it) } - } - - override suspend fun has( - id: String, - ): Boolean = authDiskSource.getLocalUserDataKey(userId = id) != null - - override suspend fun list(): List = - authDiskSource - .userState - ?.accounts - ?.mapNotNull { get(id = it.key) } - .orEmpty() - - override suspend fun remove(id: String) { - authDiskSource.storeLocalUserDataKey(userId = id, wrappedKey = null) - } - - override suspend fun removeAll() { - removeBulk(keys = authDiskSource.userState?.accounts.orEmpty().keys.toList()) - } - - override suspend fun removeBulk(keys: List) { - keys.forEach { remove(id = it) } - } - - override suspend fun set(id: String, value: LocalUserDataKeyState) { - authDiskSource.storeLocalUserDataKey(userId = id, value.wrappedKey) - } - - override suspend fun setBulk(values: Map) { - values.forEach { (id, value) -> set(id = id, value = value) } - } -} diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManagerImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManagerImpl.kt index b6cf173e79..e5fd83d460 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManagerImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManagerImpl.kt @@ -711,7 +711,6 @@ class VaultLockManagerImpl( is InitUserCryptoMethod.DecryptedKey, is InitUserCryptoMethod.DeviceKey, is InitUserCryptoMethod.KeyConnector, - is InitUserCryptoMethod.KeyConnectorUrl, is InitUserCryptoMethod.Pin, is InitUserCryptoMethod.PinEnvelope, -> return diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/InitUserCryptoMethodExtensions.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/InitUserCryptoMethodExtensions.kt index edc5b1d004..22916e705b 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/InitUserCryptoMethodExtensions.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/InitUserCryptoMethodExtensions.kt @@ -14,6 +14,5 @@ val InitUserCryptoMethod.logTag: String is InitUserCryptoMethod.KeyConnector -> "Key Connector" is InitUserCryptoMethod.Pin -> "Pin" is InitUserCryptoMethod.PinEnvelope -> "Pin Envelope" - is InitUserCryptoMethod.KeyConnectorUrl -> "Key Connector Url" is InitUserCryptoMethod.MasterPasswordUnlock -> "Master Password Unlock" } diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/sdk/repository/SdkLocalUserDataKeyStateRepositoryTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/sdk/repository/SdkLocalUserDataKeyStateRepositoryTest.kt deleted file mode 100644 index 37568595c2..0000000000 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/sdk/repository/SdkLocalUserDataKeyStateRepositoryTest.kt +++ /dev/null @@ -1,171 +0,0 @@ -package com.x8bit.bitwarden.data.platform.manager.sdk.repository - -import com.bitwarden.core.LocalUserDataKeyState -import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson -import com.x8bit.bitwarden.data.auth.datasource.disk.util.FakeAuthDiskSource -import io.mockk.mockk -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertFalse -import org.junit.jupiter.api.Assertions.assertNull -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.Test - -class SdkLocalUserDataKeyStateRepositoryTest { - - private val fakeAuthDiskSource = FakeAuthDiskSource() - - private val repository = SdkLocalUserDataKeyStateRepository( - authDiskSource = fakeAuthDiskSource, - ) - - @Test - fun `get should return null when no key is stored for the given id`() = runTest { - assertNull(repository.get(id = USER_ID)) - } - - @Test - fun `get should return LocalUserDataKeyState when key is stored for the given id`() = runTest { - fakeAuthDiskSource.storeLocalUserDataKey(userId = USER_ID, wrappedKey = WRAPPED_KEY) - - assertEquals( - LocalUserDataKeyState(wrappedKey = WRAPPED_KEY), - repository.get(id = USER_ID), - ) - } - - @Test - fun `has should return false when no key is stored for the given id`() = runTest { - assertFalse(repository.has(id = USER_ID)) - } - - @Test - fun `has should return true when a key is stored for the given id`() = runTest { - fakeAuthDiskSource.storeLocalUserDataKey(userId = USER_ID, wrappedKey = WRAPPED_KEY) - - assertTrue(repository.has(id = USER_ID)) - } - - @Test - fun `list should return empty list when userState is null`() = runTest { - fakeAuthDiskSource.userState = null - - assertEquals(emptyList(), repository.list()) - } - - @Test - fun `list should return empty list when no keys are stored for any account`() = runTest { - fakeAuthDiskSource.userState = UserStateJson( - activeUserId = USER_ID, - accounts = mapOf(USER_ID to mockk()), - ) - - assertEquals(emptyList(), repository.list()) - } - - @Test - fun `list should return LocalUserDataKeyState for each account that has a stored key`() = - runTest { - fakeAuthDiskSource.userState = UserStateJson( - activeUserId = USER_ID, - accounts = mapOf( - USER_ID to mockk(), - USER_ID_2 to mockk(), - ), - ) - fakeAuthDiskSource.storeLocalUserDataKey(userId = USER_ID, wrappedKey = WRAPPED_KEY) - fakeAuthDiskSource.storeLocalUserDataKey(userId = USER_ID_2, wrappedKey = WRAPPED_KEY_2) - - assertEquals( - listOf( - LocalUserDataKeyState(wrappedKey = WRAPPED_KEY), - LocalUserDataKeyState(wrappedKey = WRAPPED_KEY_2), - ), - repository.list(), - ) - } - - @Test - fun `list should omit accounts that have no stored key`() = runTest { - fakeAuthDiskSource.userState = UserStateJson( - activeUserId = USER_ID, - accounts = mapOf(USER_ID to mockk(), USER_ID_2 to mockk()), - ) - fakeAuthDiskSource.storeLocalUserDataKey(userId = USER_ID, wrappedKey = WRAPPED_KEY) - - assertEquals( - listOf(LocalUserDataKeyState(wrappedKey = WRAPPED_KEY)), - repository.list(), - ) - } - - @Test - fun `remove should clear the stored key for the given id`() = runTest { - fakeAuthDiskSource.storeLocalUserDataKey(userId = USER_ID, wrappedKey = WRAPPED_KEY) - - repository.remove(id = USER_ID) - - assertNull(fakeAuthDiskSource.getLocalUserDataKey(userId = USER_ID)) - } - - @Test - fun `removeAll should clear the stored key for all accounts`() = runTest { - fakeAuthDiskSource.userState = UserStateJson( - activeUserId = USER_ID, - accounts = mapOf( - USER_ID to mockk(), - USER_ID_2 to mockk(), - ), - ) - fakeAuthDiskSource.storeLocalUserDataKey(userId = USER_ID, wrappedKey = WRAPPED_KEY) - fakeAuthDiskSource.storeLocalUserDataKey(userId = USER_ID_2, wrappedKey = WRAPPED_KEY_2) - - repository.removeAll() - - assertNull(fakeAuthDiskSource.getLocalUserDataKey(userId = USER_ID)) - assertNull(fakeAuthDiskSource.getLocalUserDataKey(userId = USER_ID_2)) - } - - @Test - fun `removeAll should do nothing when userState is null`() = runTest { - fakeAuthDiskSource.userState = null - - repository.removeAll() - } - - @Test - fun `removeBulk should clear the stored key for each given id`() = runTest { - fakeAuthDiskSource.storeLocalUserDataKey(userId = USER_ID, wrappedKey = WRAPPED_KEY) - fakeAuthDiskSource.storeLocalUserDataKey(userId = USER_ID_2, wrappedKey = WRAPPED_KEY_2) - - repository.removeBulk(keys = listOf(USER_ID, USER_ID_2)) - - assertNull(fakeAuthDiskSource.getLocalUserDataKey(userId = USER_ID)) - assertNull(fakeAuthDiskSource.getLocalUserDataKey(userId = USER_ID_2)) - } - - @Test - fun `set should store the wrapped key for the given id`() = runTest { - repository.set(id = USER_ID, value = LocalUserDataKeyState(wrappedKey = WRAPPED_KEY)) - - assertEquals(WRAPPED_KEY, fakeAuthDiskSource.getLocalUserDataKey(userId = USER_ID)) - } - - @Test - fun `setBulk should store the wrapped key for each given id`() = runTest { - repository.setBulk( - values = mapOf( - USER_ID to LocalUserDataKeyState(wrappedKey = WRAPPED_KEY), - USER_ID_2 to LocalUserDataKeyState(wrappedKey = WRAPPED_KEY_2), - ), - ) - - assertEquals(WRAPPED_KEY, fakeAuthDiskSource.getLocalUserDataKey(userId = USER_ID)) - assertEquals(WRAPPED_KEY_2, fakeAuthDiskSource.getLocalUserDataKey(userId = USER_ID_2)) - } -} - -private const val USER_ID: String = "userId" -private const val USER_ID_2: String = "userId2" -private const val WRAPPED_KEY: String = "wrappedKey" -private const val WRAPPED_KEY_2: String = "wrappedKey2" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 09bc669cc9..1d717cdc14 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.4" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.1" -bitwardenSdk = "2.0.0-5676-14521973" +bitwardenSdk = "2.0.0-5451-c73f9161" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.10.0"