From aacb95572009b29d4edcc9257fdba78050c465cd Mon Sep 17 00:00:00 2001 From: David Perez Date: Sat, 27 Jan 2024 22:23:30 -0600 Subject: [PATCH] User settings repo to get biometrics enabled info (#824) --- .../platform/repository/SettingsRepository.kt | 5 +++ .../repository/SettingsRepositoryImpl.kt | 5 +++ .../AccountSecurityViewModel.kt | 34 +---------------- .../repository/SettingsRepositoryTest.kt | 18 +++++++++ .../AccountSecurityViewModelTest.kt | 38 +------------------ 5 files changed, 31 insertions(+), 69 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepository.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepository.kt index ae495d574..9baa428c9 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepository.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepository.kt @@ -66,6 +66,11 @@ interface SettingsRepository { */ var defaultUriMatchType: UriMatchType + /** + * Whether or not biometric unlocking is enabled for the current user. + */ + val isUnlockWithBiometricsEnabled: Boolean + /** * Whether or not PIN unlocking is enabled for the current user. */ diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryImpl.kt index 1e41d9044..130281320 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryImpl.kt @@ -151,6 +151,11 @@ class SettingsRepositoryImpl( ) } + override val isUnlockWithBiometricsEnabled: Boolean + get() = activeUserId + ?.let { authDiskSource.getUserBiometricUnlockKey(userId = it) != null } + ?: false + override val isUnlockWithPinEnabled: Boolean get() = activeUserId ?.let { authDiskSource.getEncryptedPin(userId = it) != null } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModel.kt index 1df6829bc..9e106c8c0 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModel.kt @@ -6,7 +6,6 @@ import androidx.lifecycle.viewModelScope import com.x8bit.bitwarden.R import com.x8bit.bitwarden.data.auth.repository.AuthRepository import com.x8bit.bitwarden.data.auth.repository.model.UserFingerprintResult -import com.x8bit.bitwarden.data.auth.repository.model.UserState import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository import com.x8bit.bitwarden.data.platform.repository.SettingsRepository import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeout @@ -18,7 +17,6 @@ import com.x8bit.bitwarden.ui.platform.base.util.Text import com.x8bit.bitwarden.ui.platform.base.util.asText import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch @@ -44,11 +42,7 @@ class AccountSecurityViewModel @Inject constructor( dialog = null, fingerprintPhrase = "".asText(), // This will be filled in dynamically isApproveLoginRequestsEnabled = settingsRepository.isApprovePasswordlessLoginsEnabled, - isUnlockWithBiometricsEnabled = authRepository - .userStateFlow - .value - ?.activeAccount - ?.isBiometricsEnabled == true, + isUnlockWithBiometricsEnabled = settingsRepository.isUnlockWithBiometricsEnabled, isUnlockWithPinEnabled = settingsRepository.isUnlockWithPinEnabled, vaultTimeout = settingsRepository.vaultTimeout, vaultTimeoutAction = settingsRepository.vaultTimeoutAction, @@ -75,12 +69,6 @@ class AccountSecurityViewModel @Inject constructor( ), ) } - - authRepository - .userStateFlow - .map { AccountSecurityAction.Internal.UserStateReceive(it) } - .onEach(::sendAction) - .launchIn(viewModelScope) } override fun handleAction(action: AccountSecurityAction): Unit = when (action) { @@ -263,8 +251,6 @@ class AccountSecurityViewModel @Inject constructor( is AccountSecurityAction.Internal.FingerprintResultReceive -> { handleFingerprintResultReceived(action) } - - is AccountSecurityAction.Internal.UserStateReceive -> handleUserStateReceive(action) } } @@ -281,17 +267,6 @@ class AccountSecurityViewModel @Inject constructor( ) } } - - private fun handleUserStateReceive(action: AccountSecurityAction.Internal.UserStateReceive) { - mutableStateFlow.update { - it.copy( - isUnlockWithBiometricsEnabled = action - .userState - ?.activeAccount - ?.isBiometricsEnabled == true, - ) - } - } } /** @@ -546,12 +521,5 @@ sealed class AccountSecurityAction { data class FingerprintResultReceive( val fingerprintResult: UserFingerprintResult, ) : Internal() - - /** - * The updated [userState] has been received. - */ - data class UserStateReceive( - val userState: UserState?, - ) : Internal() } } diff --git a/app/src/test/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryTest.kt index 13c7d6f48..62c02ddef 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryTest.kt @@ -412,6 +412,24 @@ class SettingsRepositoryTest { } } + @Suppress("MaxLineLength") + @Test + fun `isUnlockWithBiometricsEnabled should return a value that tracks the existence of a biometrics key for the current user`() { + val userId = "userId" + fakeAuthDiskSource.userState = MOCK_USER_STATE + fakeAuthDiskSource.storeUserBiometricUnlockKey( + userId = userId, + biometricsKey = null, + ) + assertFalse(settingsRepository.isUnlockWithBiometricsEnabled) + + fakeAuthDiskSource.storeUserBiometricUnlockKey( + userId = userId, + biometricsKey = "biometricsKey", + ) + assertTrue(settingsRepository.isUnlockWithBiometricsEnabled) + } + @Suppress("MaxLineLength") @Test fun `isUnlockWithPinEnabled should return a value that tracks the existence of an encrypted PIN for the current user`() { diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModelTest.kt index 23f017894..c2ff0ff63 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/accountsecurity/AccountSecurityViewModelTest.kt @@ -4,7 +4,6 @@ import androidx.lifecycle.SavedStateHandle import app.cash.turbine.test import com.x8bit.bitwarden.data.auth.repository.AuthRepository import com.x8bit.bitwarden.data.auth.repository.model.UserFingerprintResult -import com.x8bit.bitwarden.data.auth.repository.model.UserState import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository import com.x8bit.bitwarden.data.platform.repository.SettingsRepository import com.x8bit.bitwarden.data.platform.repository.model.Environment @@ -21,7 +20,6 @@ import io.mockk.just import io.mockk.mockk import io.mockk.runs import io.mockk.verify -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertFalse @@ -31,12 +29,10 @@ import org.junit.jupiter.api.Test class AccountSecurityViewModelTest : BaseViewModelTest() { private val fakeEnvironmentRepository = FakeEnvironmentRepository() - private val mutableUserStateFlow = MutableStateFlow(DEFAULT_USER_STATE) - private val authRepository: AuthRepository = mockk(relaxed = true) { - every { userStateFlow } returns mutableUserStateFlow - } + private val authRepository: AuthRepository = mockk(relaxed = true) private val vaultRepository: VaultRepository = mockk(relaxed = true) private val settingsRepository: SettingsRepository = mockk { + every { isUnlockWithBiometricsEnabled } returns false every { isApprovePasswordlessLoginsEnabled } returns false every { isUnlockWithPinEnabled } returns false every { vaultTimeout } returns VaultTimeout.ThirtyMinutes @@ -62,18 +58,6 @@ class AccountSecurityViewModelTest : BaseViewModelTest() { coVerify { settingsRepository.getUserFingerprint() } } - @Test - fun `userState with biometrics should update state`() { - mutableUserStateFlow.value = DEFAULT_USER_STATE.copy( - accounts = listOf(DEFAULT_USER_ACCOUNT.copy(isBiometricsEnabled = true)), - ) - val viewModel = createViewModel(initialState = null) - assertEquals( - DEFAULT_STATE.copy(isUnlockWithBiometricsEnabled = true), - viewModel.stateFlow.value, - ) - } - @Test fun `on FingerprintResultReceive should update the fingerprint phrase`() = runTest { val fingerprint = "fingerprint" @@ -466,21 +450,3 @@ private val DEFAULT_STATE: AccountSecurityState = AccountSecurityState( vaultTimeout = VaultTimeout.ThirtyMinutes, vaultTimeoutAction = VaultTimeoutAction.LOCK, ) - -private val DEFAULT_USER_ACCOUNT: UserState.Account = UserState.Account( - userId = "activeUserId", - name = "Active User", - email = "active@bitwarden.com", - avatarColorHex = "#aa00aa", - environment = Environment.Us, - isPremium = true, - isLoggedIn = true, - isVaultUnlocked = true, - isBiometricsEnabled = false, - organizations = emptyList(), -) - -private val DEFAULT_USER_STATE: UserState = UserState( - activeUserId = "activeUserId", - accounts = listOf(DEFAULT_USER_ACCOUNT), -)