From 29d84d69f573ccd38f43837db34b94a7eb27c7fc Mon Sep 17 00:00:00 2001 From: Patrick Honkonen <1883101+SaintPatrck@users.noreply.github.com> Date: Mon, 5 Jan 2026 17:08:21 -0500 Subject: [PATCH] [PM-28271] Rename validatePin to validatePinUserKey and update SDK usage (#6323) --- .../data/auth/repository/AuthRepository.kt | 6 +- .../auth/repository/AuthRepositoryImpl.kt | 8 +- .../vault/datasource/sdk/VaultSdkSource.kt | 7 +- .../datasource/sdk/VaultSdkSourceImpl.kt | 10 +- .../feature/addedit/VaultAddEditViewModel.kt | 2 +- .../itemlisting/VaultItemListingViewModel.kt | 2 +- .../auth/repository/AuthRepositoryTest.kt | 104 +++++++++--------- .../datasource/sdk/VaultSdkSourceTest.kt | 16 ++- .../addedit/VaultAddEditViewModelTest.kt | 16 +-- .../VaultItemListingViewModelTest.kt | 20 ++-- 10 files changed, 102 insertions(+), 89 deletions(-) diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepository.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepository.kt index c9f8295664..8607c10248 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepository.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepository.kt @@ -359,14 +359,14 @@ interface AuthRepository : suspend fun getPasswordStrength(email: String? = null, password: String): PasswordStrengthResult /** - * Validates the master password for the current logged in user. + * Validates the master password for the current logged-in user. */ suspend fun validatePassword(password: String): ValidatePasswordResult /** - * Validates the PIN for the current logged in user. + * Validates the PIN for the current logged-in user. */ - suspend fun validatePin(pin: String): ValidatePinResult + suspend fun validatePinUserKey(pin: String): ValidatePinResult /** * Validates the given [password] against the master password diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt index e9ce261edc..935490c574 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt @@ -1296,7 +1296,7 @@ class AuthRepositoryImpl( } } - override suspend fun validatePin(pin: String): ValidatePinResult { + override suspend fun validatePinUserKey(pin: String): ValidatePinResult { val activeAccount = authDiskSource .userState ?.activeAccount @@ -1305,13 +1305,13 @@ class AuthRepositoryImpl( val pinProtectedUserKeyEnvelope = authDiskSource .getPinProtectedUserKeyEnvelope(userId = activeAccount.userId) ?: return ValidatePinResult.Error( - error = MissingPropertyException("Pin Protected User Key"), + error = MissingPropertyException("Pin Protected User Key Envelope"), ) return vaultSdkSource - .validatePin( + .validatePinUserKey( userId = activeAccount.userId, pin = pin, - pinProtectedUserKey = pinProtectedUserKeyEnvelope, + pinProtectedUserKeyEnvelope = pinProtectedUserKeyEnvelope, ) .fold( onSuccess = { ValidatePinResult.Success(isValid = it) }, diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSource.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSource.kt index c2c2cd10b8..5e9b9b2f25 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSource.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSource.kt @@ -97,12 +97,13 @@ interface VaultSdkSource { ): Result /** - * Validate the user pin using the [pinProtectedUserKey]. + * Validates that the given PIN with the encrypted user key and returns `true` if the PIN is + * correct, otherwise `false`. */ - suspend fun validatePin( + suspend fun validatePinUserKey( userId: String, pin: String, - pinProtectedUserKey: String, + pinProtectedUserKeyEnvelope: String, ): Result /** 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 2f18c9e91c..58c5a14dfe 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 @@ -100,6 +100,7 @@ class VaultSdkSourceImpl( is DeriveKeyConnectorException.WrongPassword -> { DeriveKeyConnectorResult.WrongPasswordError } + is DeriveKeyConnectorException.Crypto -> { DeriveKeyConnectorResult.Error(error = ex) } @@ -129,15 +130,18 @@ class VaultSdkSourceImpl( .enrollPinWithEncryptedPin(encryptedPin = encryptedPin) } - override suspend fun validatePin( + override suspend fun validatePinUserKey( userId: String, pin: String, - pinProtectedUserKey: String, + pinProtectedUserKeyEnvelope: String, ): Result = runCatchingWithLogs { getClient(userId = userId) .auth() - .validatePin(pin = pin, pinProtectedUserKey = pinProtectedUserKey) + .validatePinProtectedUserKeyEnvelope( + pin = pin, + pinProtectedUserKeyEnvelope = pinProtectedUserKeyEnvelope, + ) } override suspend fun getAuthRequestKey( diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt index bff43daecf..248b25c410 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt @@ -734,7 +734,7 @@ class VaultAddEditViewModel @Inject constructor( action: VaultAddEditAction.Common.PinFido2VerificationSubmit, ) { viewModelScope.launch { - val result = authRepository.validatePin(action.pin) + val result = authRepository.validatePinUserKey(action.pin) sendAction( VaultAddEditAction.Internal.ValidateFido2PinResultReceive( result = result, diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt index 6d24a0cec9..4c663b9bab 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt @@ -542,7 +542,7 @@ class VaultItemListingViewModel @Inject constructor( action: VaultItemListingsAction.PinUserVerificationSubmit, ) { viewModelScope.launch { - val result = authRepository.validatePin(action.pin) + val result = authRepository.validatePinUserKey(action.pin) sendAction( VaultItemListingsAction.Internal.ValidateUserVerificationPinResultReceive( result = result, diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt index e9b3856aa7..8f341abe63 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt @@ -6767,7 +6767,7 @@ class AuthRepositoryTest { val pin = "PIN" fakeAuthDiskSource.userState = null - val result = repository.validatePin(pin = pin) + val result = repository.validatePinUserKey(pin = pin) assertEquals( ValidatePinResult.Error(error = NoActiveUserException()), @@ -6775,8 +6775,9 @@ class AuthRepositoryTest { ) } + @Suppress("MaxLineLength") @Test - fun `validatePin returns ValidatePinResult Error when no pin protected user key found`() = + fun `validatePinUserKey returns ValidatePinResult Error when no pin protected user key found`() = runTest { val pin = "PIN" fakeAuthDiskSource.userState = SINGLE_USER_STATE_1 @@ -6785,7 +6786,7 @@ class AuthRepositoryTest { pinProtectedUserKey = null, ) - val result = repository.validatePin(pin = pin) + val result = repository.validatePinUserKey(pin = pin) assertEquals( ValidatePinResult.Error(MissingPropertyException("Pin Protected User Key")), @@ -6794,75 +6795,42 @@ class AuthRepositoryTest { } @Test - fun `validatePin returns ValidatePinResult Error when SDK validatePin fails`() = runTest { - val pin = "PIN" - val pinProtectedUserKey = "pinProtectedUserKey" - val error = Throwable("Fail!") - fakeAuthDiskSource.userState = SINGLE_USER_STATE_1 - fakeAuthDiskSource.storePinProtectedUserKeyEnvelope( - userId = SINGLE_USER_STATE_1.activeUserId, - pinProtectedUserKeyEnvelope = pinProtectedUserKey, - ) - coEvery { - vaultSdkSource.validatePin( - userId = SINGLE_USER_STATE_1.activeUserId, - pin = pin, - pinProtectedUserKey = pinProtectedUserKey, - ) - } returns error.asFailure() - - val result = repository.validatePin(pin = pin) - - assertEquals( - ValidatePinResult.Error(error = error), - result, - ) - coVerify(exactly = 1) { - vaultSdkSource.validatePin( - userId = SINGLE_USER_STATE_1.activeUserId, - pin = pin, - pinProtectedUserKey = pinProtectedUserKey, - ) - } - } - - @Suppress("MaxLineLength") - @Test - fun `validatePin returns ValidatePinResult Success with valid false when SDK validatePin returns false`() = + fun `validatePinUserKey returns ValidatePinResult Error when SDK validatePin fails`() = runTest { val pin = "PIN" val pinProtectedUserKey = "pinProtectedUserKey" + val error = Throwable("Fail!") fakeAuthDiskSource.userState = SINGLE_USER_STATE_1 fakeAuthDiskSource.storePinProtectedUserKeyEnvelope( userId = SINGLE_USER_STATE_1.activeUserId, pinProtectedUserKeyEnvelope = pinProtectedUserKey, ) coEvery { - vaultSdkSource.validatePin( + vaultSdkSource.validatePinUserKey( userId = SINGLE_USER_STATE_1.activeUserId, pin = pin, - pinProtectedUserKey = pinProtectedUserKey, + pinProtectedUserKeyEnvelope = pinProtectedUserKey, ) - } returns false.asSuccess() + } returns error.asFailure() - val result = repository.validatePin(pin = pin) + val result = repository.validatePinUserKey(pin = pin) assertEquals( - ValidatePinResult.Success(isValid = false), + ValidatePinResult.Error(error = error), result, ) coVerify(exactly = 1) { - vaultSdkSource.validatePin( + vaultSdkSource.validatePinUserKey( userId = SINGLE_USER_STATE_1.activeUserId, pin = pin, - pinProtectedUserKey = pinProtectedUserKey, + pinProtectedUserKeyEnvelope = pinProtectedUserKey, ) } } @Suppress("MaxLineLength") @Test - fun `validatePin returns ValidatePinResult Success with valid true when SDK validatePin returns true`() = + fun `validatePinUserKey returns ValidatePinResult Success with valid false when SDK validatePin returns false`() = runTest { val pin = "PIN" val pinProtectedUserKey = "pinProtectedUserKey" @@ -6872,24 +6840,58 @@ class AuthRepositoryTest { pinProtectedUserKeyEnvelope = pinProtectedUserKey, ) coEvery { - vaultSdkSource.validatePin( + vaultSdkSource.validatePinUserKey( userId = SINGLE_USER_STATE_1.activeUserId, pin = pin, - pinProtectedUserKey = pinProtectedUserKey, + pinProtectedUserKeyEnvelope = pinProtectedUserKey, + ) + } returns false.asSuccess() + + val result = repository.validatePinUserKey(pin = pin) + + assertEquals( + ValidatePinResult.Success(isValid = false), + result, + ) + coVerify(exactly = 1) { + vaultSdkSource.validatePinUserKey( + userId = SINGLE_USER_STATE_1.activeUserId, + pin = pin, + pinProtectedUserKeyEnvelope = pinProtectedUserKey, + ) + } + } + + @Suppress("MaxLineLength") + @Test + fun `validatePinUserKey returns ValidatePinResult Success with valid true when SDK validatePin returns true`() = + runTest { + val pin = "PIN" + val pinProtectedUserKey = "pinProtectedUserKey" + fakeAuthDiskSource.userState = SINGLE_USER_STATE_1 + fakeAuthDiskSource.storePinProtectedUserKeyEnvelope( + userId = SINGLE_USER_STATE_1.activeUserId, + pinProtectedUserKeyEnvelope = pinProtectedUserKey, + ) + coEvery { + vaultSdkSource.validatePinUserKey( + userId = SINGLE_USER_STATE_1.activeUserId, + pin = pin, + pinProtectedUserKeyEnvelope = pinProtectedUserKey, ) } returns true.asSuccess() - val result = repository.validatePin(pin = pin) + val result = repository.validatePinUserKey(pin = pin) assertEquals( ValidatePinResult.Success(isValid = true), result, ) coVerify(exactly = 1) { - vaultSdkSource.validatePin( + vaultSdkSource.validatePinUserKey( userId = SINGLE_USER_STATE_1.activeUserId, pin = pin, - pinProtectedUserKey = pinProtectedUserKey, + pinProtectedUserKeyEnvelope = pinProtectedUserKey, ) } } 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 3925d97cd8..6c69d4f26b 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 @@ -384,25 +384,31 @@ class VaultSdkSourceTest { } @Test - fun `validatePin should call SDK and return a Result with the correct data`() = + fun `validatePinUserKey should call SDK and return a Result with the correct data`() = runBlocking { val userId = "userId" val pin = "pin" val pinProtectedUserKey = "pinProtectedUserKey" val expectedResult = true coEvery { - clientAuth.validatePin(pin = pin, pinProtectedUserKey = pinProtectedUserKey) + clientAuth.validatePinProtectedUserKeyEnvelope( + pin = pin, + pinProtectedUserKeyEnvelope = pinProtectedUserKey, + ) } returns expectedResult - val result = vaultSdkSource.validatePin( + val result = vaultSdkSource.validatePinUserKey( userId = userId, pin = pin, - pinProtectedUserKey = pinProtectedUserKey, + pinProtectedUserKeyEnvelope = pinProtectedUserKey, ) assertEquals(expectedResult.asSuccess(), result) coVerify(exactly = 1) { - clientAuth.validatePin(pin = pin, pinProtectedUserKey = pinProtectedUserKey) + clientAuth.validatePinProtectedUserKeyEnvelope( + pin = pin, + pinProtectedUserKeyEnvelope = pinProtectedUserKey, + ) sdkClientManager.getOrCreateClient(userId = userId) } } 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 5b97c14dff..dae550e885 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 @@ -4242,7 +4242,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { fun `PinFido2VerificationSubmit should display CredentialError when Pin verification fails`() { val pin = "PIN" coEvery { - authRepository.validatePin(pin = pin) + authRepository.validatePinUserKey(pin = pin) } returns ValidatePinResult.Error(error = Throwable("Fail!")) viewModel.trySendAction( @@ -4259,7 +4259,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { viewModel.stateFlow.value.dialog, ) coVerify { - authRepository.validatePin(pin = pin) + authRepository.validatePinUserKey(pin = pin) } } @@ -4268,7 +4268,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { fun `PinFido2VerificationSubmit should display Fido2PinError when user has retries remaining`() { val pin = "PIN" coEvery { - authRepository.validatePin(pin = pin) + authRepository.validatePinUserKey(pin = pin) } returns ValidatePinResult.Success(isValid = false) viewModel.trySendAction( @@ -4282,7 +4282,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { viewModel.stateFlow.value.dialog, ) coVerify { - authRepository.validatePin(pin = pin) + authRepository.validatePinUserKey(pin = pin) } } @@ -4292,7 +4292,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { val pin = "PIN" every { bitwardenCredentialManager.hasAuthenticationAttemptsRemaining() } returns false coEvery { - authRepository.validatePin(pin = pin) + authRepository.validatePinUserKey(pin = pin) } returns ValidatePinResult.Success(isValid = false) viewModel.trySendAction( @@ -4309,7 +4309,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { viewModel.stateFlow.value.dialog, ) coVerify { - authRepository.validatePin(pin = pin) + authRepository.validatePinUserKey(pin = pin) } } @@ -4318,7 +4318,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { fun `PinFido2VerificationSubmit should register credential when pin authenticated successfully`() { val pin = "PIN" coEvery { - authRepository.validatePin(pin = pin) + authRepository.validatePinUserKey(pin = pin) } returns ValidatePinResult.Success(isValid = true) viewModel.trySendAction( @@ -4327,7 +4327,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { ), ) coVerify { - authRepository.validatePin(pin = pin) + authRepository.validatePinUserKey(pin = pin) } } 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 0ae28df249..97ffe879b2 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 @@ -4734,7 +4734,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { val selectedCipherId = "selectedCipherId" val pin = "PIN" coEvery { - authRepository.validatePin(pin = pin) + authRepository.validatePinUserKey(pin = pin) } returns ValidatePinResult.Error(error = Throwable("Fail!")) viewModel.trySendAction( @@ -4754,7 +4754,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { viewModel.stateFlow.value.dialogState, ) coVerify { - authRepository.validatePin(pin = pin) + authRepository.validatePinUserKey(pin = pin) } } @@ -4765,7 +4765,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { val selectedCipherId = "selectedCipherId" val pin = "PIN" coEvery { - authRepository.validatePin(pin = pin) + authRepository.validatePinUserKey(pin = pin) } returns ValidatePinResult.Success(isValid = false) viewModel.trySendAction( @@ -4784,7 +4784,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { viewModel.stateFlow.value.dialogState, ) coVerify { - authRepository.validatePin(pin = pin) + authRepository.validatePinUserKey(pin = pin) } } @@ -4796,7 +4796,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { val pin = "PIN" every { bitwardenCredentialManager.hasAuthenticationAttemptsRemaining() } returns false coEvery { - authRepository.validatePin(pin = pin) + authRepository.validatePinUserKey(pin = pin) } returns ValidatePinResult.Success(isValid = false) viewModel.trySendAction( @@ -4816,7 +4816,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { viewModel.stateFlow.value.dialogState, ) coVerify { - authRepository.validatePin(pin = pin) + authRepository.validatePinUserKey(pin = pin) } } @@ -4827,7 +4827,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { val selectedCipherId = "selectedCipherId" val pin = "PIN" coEvery { - authRepository.validatePin(pin = pin) + authRepository.validatePinUserKey(pin = pin) } returns ValidatePinResult.Success(isValid = true) coEvery { vaultRepository.getCipher("selectedCipherId") @@ -4850,7 +4850,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { viewModel.stateFlow.value.dialogState, ) coVerify { - authRepository.validatePin(pin = pin) + authRepository.validatePinUserKey(pin = pin) } } @@ -4874,7 +4874,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { ), ) coEvery { - authRepository.validatePin(pin = pin) + authRepository.validatePinUserKey(pin = pin) } returns ValidatePinResult.Success(isValid = true) viewModel.trySendAction( @@ -4884,7 +4884,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { ), ) coVerify { - authRepository.validatePin(pin = pin) + authRepository.validatePinUserKey(pin = pin) } }