From 0d2fd2d184f1e29d2264635774bfd79675823348 Mon Sep 17 00:00:00 2001 From: David Perez Date: Wed, 1 Jul 2026 09:03:36 -0500 Subject: [PATCH] PM-39765: bug: Improve error parsing for vault unlock (#7124) --- .../datasource/sdk/VaultSdkSourceImpl.kt | 40 ++++++++++++---- .../datasource/sdk/VaultSdkSourceTest.kt | 48 +++++++++++++------ 2 files changed, 63 insertions(+), 25 deletions(-) diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSourceImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSourceImpl.kt index cfbc654b71..d7c4534cbe 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSourceImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSourceImpl.kt @@ -5,12 +5,14 @@ import com.bitwarden.collections.CollectionId import com.bitwarden.collections.CollectionView import com.bitwarden.core.DeriveKeyConnectorException import com.bitwarden.core.DeriveKeyConnectorRequest +import com.bitwarden.core.EncryptionSettingsException import com.bitwarden.core.EnrollPinResponse import com.bitwarden.core.InitOrgCryptoRequest import com.bitwarden.core.InitUserCryptoRequest import com.bitwarden.core.UpdateKdfResponse import com.bitwarden.core.UpdatePasswordResponse import com.bitwarden.core.data.manager.dispatcher.DispatcherManager +import com.bitwarden.core.data.util.asFailure import com.bitwarden.crypto.Kdf import com.bitwarden.crypto.TrustDeviceResponse import com.bitwarden.exporters.Account @@ -194,12 +196,32 @@ class VaultSdkSourceImpl( getClient(userId = userId).crypto().initializeUserCrypto(req = request) } InitializeCryptoResult.Success - } catch (exception: BitwardenException) { - // The only truly expected error from the SDK is an incorrect key/password. - InitializeCryptoResult.AuthenticationError( - message = exception.message, - error = exception, - ) + } catch (exception: BitwardenException.EncryptionSettings) { + when (val error = exception.v1) { + is EncryptionSettingsException.Crypto, + is EncryptionSettingsException.WrongPin, + -> { + InitializeCryptoResult.AuthenticationError( + message = error.message, + error = error, + ) + } + + is EncryptionSettingsException.CryptoInitialization, + is EncryptionSettingsException.InvalidUpgradeToken, + is EncryptionSettingsException.KeyConnectorRetrievalFailed, + is EncryptionSettingsException.LocalUserDataKeyInitFailed, + is EncryptionSettingsException.LocalUserDataKeyLoadFailed, + is EncryptionSettingsException.LocalUserDataMigrationFailed, + is EncryptionSettingsException.MissingPrivateKey, + is EncryptionSettingsException.UserIdAlreadySet, + is EncryptionSettingsException.UserKeyStateRetrievalFailed, + is EncryptionSettingsException.UserKeyStateUpdateFailed, + -> { + Timber.w(error, "initializeCrypto error") + return error.asFailure() + } + } } } @@ -209,11 +231,9 @@ class VaultSdkSourceImpl( ): Result = runCatchingWithLogs { try { - getClient(userId = userId) - .crypto() - .initializeOrgCrypto(req = request) + getClient(userId = userId).crypto().initializeOrgCrypto(req = request) InitializeCryptoResult.Success - } catch (exception: BitwardenException) { + } catch (exception: BitwardenException.EncryptionSettings) { // The only truly expected error from the SDK is for incorrect keys. InitializeCryptoResult.AuthenticationError( message = exception.message, diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSourceTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSourceTest.kt index 1664453145..04ba6fde4d 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSourceTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSourceTest.kt @@ -4,6 +4,7 @@ import com.bitwarden.collections.Collection import com.bitwarden.collections.CollectionView import com.bitwarden.core.DeriveKeyConnectorException import com.bitwarden.core.DeriveKeyConnectorRequest +import com.bitwarden.core.EncryptionSettingsException import com.bitwarden.core.EnrollPinResponse import com.bitwarden.core.InitOrgCryptoRequest import com.bitwarden.core.InitUserCryptoRequest @@ -554,19 +555,38 @@ class VaultSdkSourceTest { @Test @Suppress("MaxLineLength") - fun `initializeUserCrypto with BitwardenException failure should return AuthenticationError with message`() = + fun `initializeUserCrypto with BitwardenException EncryptionSettings MissingPrivateKey failure should return an error result`() = + runBlocking { + val userId = "userId" + val mockInitCryptoRequest = mockk() + val expectedException = EncryptionSettingsException.MissingPrivateKey("Whoopsy") + val bitwardenException = BitwardenException.EncryptionSettings(v1 = expectedException) + coEvery { + clientCrypto.initializeUserCrypto(req = mockInitCryptoRequest) + } throws bitwardenException + val result = vaultSdkSource.initializeCrypto( + userId = userId, + request = mockInitCryptoRequest, + ) + assertEquals(expectedException.asFailure(), result) + coVerify { + clientCrypto.initializeUserCrypto(req = mockInitCryptoRequest) + sdkClientManager.getOrCreateClient(userId = userId) + } + } + + @Test + @Suppress("MaxLineLength") + fun `initializeUserCrypto with BitwardenException EncryptionSettings Crypto failure should return AuthenticationError with message`() = runBlocking { val userId = "userId" val mockInitCryptoRequest = mockk() val expectedErrorMessage = "Whoopsy" - val expectedException = BitwardenException.Crypto( - CryptoException.InvalidKey(expectedErrorMessage), - ) + val expectedException = EncryptionSettingsException.Crypto(expectedErrorMessage) + val bitwardenException = BitwardenException.EncryptionSettings(v1 = expectedException) coEvery { - clientCrypto.initializeUserCrypto( - req = mockInitCryptoRequest, - ) - } throws expectedException + clientCrypto.initializeUserCrypto(req = mockInitCryptoRequest) + } throws bitwardenException val result = vaultSdkSource.initializeCrypto( userId = userId, request = mockInitCryptoRequest, @@ -581,11 +601,9 @@ class VaultSdkSourceTest { result, ) coVerify { - clientCrypto.initializeUserCrypto( - req = mockInitCryptoRequest, - ) + clientCrypto.initializeUserCrypto(req = mockInitCryptoRequest) + sdkClientManager.getOrCreateClient(userId = userId) } - coVerify { sdkClientManager.getOrCreateClient(userId = userId) } } @Test @@ -642,13 +660,13 @@ class VaultSdkSourceTest { @Test @Suppress("MaxLineLength") - fun `initializeOrgCrypto with BitwardenException failure should return AuthenticationError with correct message`() = + fun `initializeOrgCrypto with BitwardenException EncryptionSettingsException failure should return AuthenticationError with correct message`() = runBlocking { val userId = "userId" val mockInitCryptoRequest = mockk() val expectedErrorMessage = "Whoopsy2" - val expectedException = BitwardenException.Crypto( - CryptoException.InvalidKey(expectedErrorMessage), + val expectedException = BitwardenException.EncryptionSettings( + v1 = EncryptionSettingsException.Crypto(expectedErrorMessage), ) coEvery { clientCrypto.initializeOrgCrypto(