From 2e2d4de0d72b1e0f0a468ba6ceb283f2890f90eb Mon Sep 17 00:00:00 2001 From: David Perez Date: Thu, 30 Nov 2023 15:19:47 -0600 Subject: [PATCH] Expose the HaveIBeenPwned service via auth repo (#306) --- .../data/auth/repository/AuthRepository.kt | 6 ++++ .../auth/repository/AuthRepositoryImpl.kt | 9 ++++++ .../repository/model/BreachCountResult.kt | 16 ++++++++++ .../auth/repository/AuthRepositoryTest.kt | 32 +++++++++++++++++++ 4 files changed, 63 insertions(+) create mode 100644 app/src/main/java/com/x8bit/bitwarden/data/auth/repository/model/BreachCountResult.kt diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepository.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepository.kt index cfd2524984..6430876f41 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepository.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepository.kt @@ -1,6 +1,7 @@ package com.x8bit.bitwarden.data.auth.repository import com.x8bit.bitwarden.data.auth.repository.model.AuthState +import com.x8bit.bitwarden.data.auth.repository.model.BreachCountResult import com.x8bit.bitwarden.data.auth.repository.model.DeleteAccountResult import com.x8bit.bitwarden.data.auth.repository.model.LoginResult import com.x8bit.bitwarden.data.auth.repository.model.PasswordStrengthResult @@ -81,6 +82,11 @@ interface AuthRepository : AuthenticatorProvider { */ fun setCaptchaCallbackTokenResult(tokenResult: CaptchaCallbackTokenResult) + /** + * Attempts to get the number of times the given [password] has been breached. + */ + suspend fun getPasswordBreachCount(password: String): BreachCountResult + /** * Get the password strength for the given [email] and [password] combo. */ diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt index b5d597d1cb..fd02410130 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt @@ -15,6 +15,7 @@ import com.x8bit.bitwarden.data.auth.datasource.sdk.AuthSdkSource import com.x8bit.bitwarden.data.auth.datasource.sdk.model.PasswordStrength import com.x8bit.bitwarden.data.auth.datasource.sdk.util.toKdfTypeJson import com.x8bit.bitwarden.data.auth.repository.model.AuthState +import com.x8bit.bitwarden.data.auth.repository.model.BreachCountResult import com.x8bit.bitwarden.data.auth.repository.model.DeleteAccountResult import com.x8bit.bitwarden.data.auth.repository.model.LoginResult import com.x8bit.bitwarden.data.auth.repository.model.PasswordStrengthResult @@ -337,6 +338,14 @@ class AuthRepositoryImpl constructor( mutableCaptchaTokenFlow.tryEmit(tokenResult) } + override suspend fun getPasswordBreachCount(password: String): BreachCountResult = + haveIBeenPwnedService + .getPasswordBreachCount(password) + .fold( + onFailure = { BreachCountResult.Error }, + onSuccess = { BreachCountResult.Success(it) }, + ) + @Suppress("MagicNumber") override suspend fun getPasswordStrength( email: String, diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/model/BreachCountResult.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/model/BreachCountResult.kt new file mode 100644 index 0000000000..11c8adc9c8 --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/model/BreachCountResult.kt @@ -0,0 +1,16 @@ +package com.x8bit.bitwarden.data.auth.repository.model + +/** + * Models result of determining if a password has been breached. + */ +sealed class BreachCountResult { + /** + * Contains the number of breaches. + */ + data class Success(val breachCount: Int) : BreachCountResult() + + /** + * There was an error determining if the password has been breached. + */ + data object Error : BreachCountResult() +} diff --git a/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt index dd53465dfc..379c4e0ba8 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt @@ -25,6 +25,7 @@ import com.x8bit.bitwarden.data.auth.datasource.sdk.model.PasswordStrength.LEVEL import com.x8bit.bitwarden.data.auth.datasource.sdk.model.PasswordStrength.LEVEL_3 import com.x8bit.bitwarden.data.auth.datasource.sdk.model.PasswordStrength.LEVEL_4 import com.x8bit.bitwarden.data.auth.repository.model.AuthState +import com.x8bit.bitwarden.data.auth.repository.model.BreachCountResult import com.x8bit.bitwarden.data.auth.repository.model.DeleteAccountResult import com.x8bit.bitwarden.data.auth.repository.model.LoginResult import com.x8bit.bitwarden.data.auth.repository.model.PasswordStrengthResult @@ -1078,6 +1079,37 @@ class AuthRepositoryTest { } } + @Test + fun `getPasswordBreachCount should return failure when service returns failure`() = runTest { + val password = "password" + coEvery { + haveIBeenPwnedService.getPasswordBreachCount(password) + } returns Throwable("Fail").asFailure() + + val result = repository.getPasswordBreachCount(password) + + coVerify(exactly = 1) { + haveIBeenPwnedService.getPasswordBreachCount(password) + } + assertEquals(BreachCountResult.Error, result) + } + + @Test + fun `getPasswordBreachCount should return success when service returns success`() = runTest { + val password = "password" + val breachCount = 5 + coEvery { + haveIBeenPwnedService.getPasswordBreachCount(password) + } returns breachCount.asSuccess() + + val result = repository.getPasswordBreachCount(password) + + coVerify(exactly = 1) { + haveIBeenPwnedService.getPasswordBreachCount(password) + } + assertEquals(BreachCountResult.Success(breachCount), result) + } + @Test fun `getPasswordStrength should be based on password length`() = runTest { // TODO: Replace with SDK call (BIT-964)