User settings repo to get biometrics enabled info (#824)

This commit is contained in:
David Perez 2024-01-27 22:23:30 -06:00 committed by Álison Fernandes
parent 9fcc326df3
commit aacb955720
5 changed files with 31 additions and 69 deletions

View file

@ -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.
*/

View file

@ -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 }

View file

@ -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()
}
}

View file

@ -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`() {

View file

@ -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<UserState?>(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),
)