Add isBiometricsEnabled boolean to UserState (#806)

This commit is contained in:
David Perez 2024-01-26 16:52:54 -06:00 committed by Álison Fernandes
parent b1c6567df2
commit 9338a51d68
19 changed files with 100 additions and 46 deletions

View file

@ -153,6 +153,7 @@ class AuthRepositoryImpl(
vaultState = vaultState, vaultState = vaultState,
userOrganizationsList = userOrganizationsList, userOrganizationsList = userOrganizationsList,
hasPendingAccountAddition = hasPendingAccountAddition, hasPendingAccountAddition = hasPendingAccountAddition,
isBiometricsEnabledProvider = ::isBiometricsEnabled,
vaultUnlockTypeProvider = ::getVaultUnlockType, vaultUnlockTypeProvider = ::getVaultUnlockType,
) )
} }
@ -170,6 +171,7 @@ class AuthRepositoryImpl(
vaultState = vaultRepository.vaultStateFlow.value, vaultState = vaultRepository.vaultStateFlow.value,
userOrganizationsList = authDiskSource.userOrganizationsList, userOrganizationsList = authDiskSource.userOrganizationsList,
hasPendingAccountAddition = mutableHasPendingAccountAdditionStateFlow.value, hasPendingAccountAddition = mutableHasPendingAccountAdditionStateFlow.value,
isBiometricsEnabledProvider = ::isBiometricsEnabled,
vaultUnlockTypeProvider = ::getVaultUnlockType, vaultUnlockTypeProvider = ::getVaultUnlockType,
), ),
) )
@ -710,6 +712,10 @@ class AuthRepositoryImpl(
) )
} }
private fun isBiometricsEnabled(
userId: String,
): Boolean = authDiskSource.getUserBiometricUnlockKey(userId = userId) != null
private fun getVaultUnlockType( private fun getVaultUnlockType(
userId: String, userId: String,
): VaultUnlockType = ): VaultUnlockType =

View file

@ -12,7 +12,6 @@ import com.x8bit.bitwarden.data.platform.repository.model.Environment
* that user. * that user.
* @property hasPendingAccountAddition Returns `true` if there is an additional account that is * @property hasPendingAccountAddition Returns `true` if there is an additional account that is
* pending login/registration in order to have multiple accounts available. * pending login/registration in order to have multiple accounts available.
* @property specialCircumstance A special circumstance (if any) that may be present.
*/ */
data class UserState( data class UserState(
val activeUserId: String, val activeUserId: String,
@ -42,6 +41,8 @@ data class UserState(
* authentication to view their vault. * authentication to view their vault.
* @property isVaultUnlocked Whether or not the user's vault is currently unlocked. * @property isVaultUnlocked Whether or not the user's vault is currently unlocked.
* @property organizations List of [Organization]s the user is associated with, if any. * @property organizations List of [Organization]s the user is associated with, if any.
* @property isBiometricsEnabled Indicates that the biometrics mechanism for unlocking the
* user's vault is enabled.
* @property vaultUnlockType The mechanism by which the user's vault may be unlocked. * @property vaultUnlockType The mechanism by which the user's vault may be unlocked.
*/ */
data class Account( data class Account(
@ -54,6 +55,7 @@ data class UserState(
val isLoggedIn: Boolean, val isLoggedIn: Boolean,
val isVaultUnlocked: Boolean, val isVaultUnlocked: Boolean,
val organizations: List<Organization>, val organizations: List<Organization>,
val isBiometricsEnabled: Boolean,
val vaultUnlockType: VaultUnlockType = VaultUnlockType.MASTER_PASSWORD, val vaultUnlockType: VaultUnlockType = VaultUnlockType.MASTER_PASSWORD,
) )
} }

View file

@ -41,13 +41,13 @@ fun UserStateJson.toUpdatedUserStateJson(
} }
/** /**
* Converts the given [UserStateJson] to a [UserState] using the given [vaultState] and * Converts the given [UserStateJson] to a [UserState] using the given [vaultState].
* [specialCircumstance].
*/ */
fun UserStateJson.toUserState( fun UserStateJson.toUserState(
vaultState: VaultState, vaultState: VaultState,
userOrganizationsList: List<UserOrganizations>, userOrganizationsList: List<UserOrganizations>,
hasPendingAccountAddition: Boolean, hasPendingAccountAddition: Boolean,
isBiometricsEnabledProvider: (userId: String) -> Boolean,
vaultUnlockTypeProvider: (userId: String) -> VaultUnlockType, vaultUnlockTypeProvider: (userId: String) -> VaultUnlockType,
): UserState = ): UserState =
UserState( UserState(
@ -74,6 +74,7 @@ fun UserStateJson.toUserState(
.find { it.userId == userId } .find { it.userId == userId }
?.organizations ?.organizations
.orEmpty(), .orEmpty(),
isBiometricsEnabled = isBiometricsEnabledProvider(userId),
vaultUnlockType = vaultUnlockTypeProvider(userId), vaultUnlockType = vaultUnlockTypeProvider(userId),
) )
}, },

View file

@ -1,8 +1,8 @@
package com.x8bit.bitwarden package com.x8bit.bitwarden
import android.content.Intent import android.content.Intent
import app.cash.turbine.test
import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.SavedStateHandle
import app.cash.turbine.test
import com.x8bit.bitwarden.data.auth.repository.AuthRepository import com.x8bit.bitwarden.data.auth.repository.AuthRepository
import com.x8bit.bitwarden.data.auth.repository.model.UserState import com.x8bit.bitwarden.data.auth.repository.model.UserState
import com.x8bit.bitwarden.data.auth.repository.util.getCaptchaCallbackTokenResult import com.x8bit.bitwarden.data.auth.repository.util.getCaptchaCallbackTokenResult
@ -193,6 +193,7 @@ class MainViewModelTest : BaseViewModelTest() {
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
), ),
), ),

View file

@ -243,6 +243,7 @@ class AuthRepositoryTest {
vaultState = VAULT_STATE, vaultState = VAULT_STATE,
userOrganizationsList = emptyList(), userOrganizationsList = emptyList(),
hasPendingAccountAddition = false, hasPendingAccountAddition = false,
isBiometricsEnabledProvider = { false },
vaultUnlockTypeProvider = { VaultUnlockType.MASTER_PASSWORD }, vaultUnlockTypeProvider = { VaultUnlockType.MASTER_PASSWORD },
), ),
repository.userStateFlow.value, repository.userStateFlow.value,
@ -264,6 +265,7 @@ class AuthRepositoryTest {
vaultState = VAULT_STATE, vaultState = VAULT_STATE,
userOrganizationsList = emptyList(), userOrganizationsList = emptyList(),
hasPendingAccountAddition = false, hasPendingAccountAddition = false,
isBiometricsEnabledProvider = { false },
vaultUnlockTypeProvider = { VaultUnlockType.PIN }, vaultUnlockTypeProvider = { VaultUnlockType.PIN },
), ),
repository.userStateFlow.value, repository.userStateFlow.value,
@ -279,6 +281,7 @@ class AuthRepositoryTest {
vaultState = emptyVaultState, vaultState = emptyVaultState,
userOrganizationsList = emptyList(), userOrganizationsList = emptyList(),
hasPendingAccountAddition = false, hasPendingAccountAddition = false,
isBiometricsEnabledProvider = { false },
vaultUnlockTypeProvider = { VaultUnlockType.PIN }, vaultUnlockTypeProvider = { VaultUnlockType.PIN },
), ),
repository.userStateFlow.value, repository.userStateFlow.value,
@ -303,6 +306,7 @@ class AuthRepositoryTest {
vaultState = emptyVaultState, vaultState = emptyVaultState,
userOrganizationsList = USER_ORGANIZATIONS, userOrganizationsList = USER_ORGANIZATIONS,
hasPendingAccountAddition = false, hasPendingAccountAddition = false,
isBiometricsEnabledProvider = { false },
vaultUnlockTypeProvider = { VaultUnlockType.MASTER_PASSWORD }, vaultUnlockTypeProvider = { VaultUnlockType.MASTER_PASSWORD },
), ),
repository.userStateFlow.value, repository.userStateFlow.value,
@ -347,12 +351,14 @@ class AuthRepositoryTest {
vaultState = VAULT_STATE, vaultState = VAULT_STATE,
userOrganizationsList = emptyList(), userOrganizationsList = emptyList(),
hasPendingAccountAddition = false, hasPendingAccountAddition = false,
isBiometricsEnabledProvider = { false },
vaultUnlockTypeProvider = { VaultUnlockType.MASTER_PASSWORD }, vaultUnlockTypeProvider = { VaultUnlockType.MASTER_PASSWORD },
) )
val finalUserState = SINGLE_USER_STATE_2.toUserState( val finalUserState = SINGLE_USER_STATE_2.toUserState(
vaultState = VAULT_STATE, vaultState = VAULT_STATE,
userOrganizationsList = emptyList(), userOrganizationsList = emptyList(),
hasPendingAccountAddition = false, hasPendingAccountAddition = false,
isBiometricsEnabledProvider = { false },
vaultUnlockTypeProvider = { VaultUnlockType.MASTER_PASSWORD }, vaultUnlockTypeProvider = { VaultUnlockType.MASTER_PASSWORD },
) )
val kdf = SINGLE_USER_STATE_1.activeAccount.profile.toSdkParams() val kdf = SINGLE_USER_STATE_1.activeAccount.profile.toSdkParams()
@ -1252,9 +1258,9 @@ class AuthRepositoryTest {
} }
} }
@Suppress("MaxLineLength")
@Test @Test
fun `SSO login get token returns two factor request should return TwoFactorRequired`() = runTest { fun `SSO login get token returns two factor request should return TwoFactorRequired`() =
runTest {
coEvery { coEvery {
identityService.getToken( identityService.getToken(
email = EMAIL, email = EMAIL,
@ -1980,6 +1986,7 @@ class AuthRepositoryTest {
vaultState = VAULT_STATE, vaultState = VAULT_STATE,
userOrganizationsList = emptyList(), userOrganizationsList = emptyList(),
hasPendingAccountAddition = false, hasPendingAccountAddition = false,
isBiometricsEnabledProvider = { false },
vaultUnlockTypeProvider = { VaultUnlockType.MASTER_PASSWORD }, vaultUnlockTypeProvider = { VaultUnlockType.MASTER_PASSWORD },
) )
fakeAuthDiskSource.userState = SINGLE_USER_STATE_1 fakeAuthDiskSource.userState = SINGLE_USER_STATE_1
@ -2010,6 +2017,7 @@ class AuthRepositoryTest {
vaultState = VAULT_STATE, vaultState = VAULT_STATE,
userOrganizationsList = emptyList(), userOrganizationsList = emptyList(),
hasPendingAccountAddition = false, hasPendingAccountAddition = false,
isBiometricsEnabledProvider = { false },
vaultUnlockTypeProvider = { VaultUnlockType.MASTER_PASSWORD }, vaultUnlockTypeProvider = { VaultUnlockType.MASTER_PASSWORD },
) )
fakeAuthDiskSource.userState = SINGLE_USER_STATE_1 fakeAuthDiskSource.userState = SINGLE_USER_STATE_1
@ -2038,6 +2046,7 @@ class AuthRepositoryTest {
vaultState = VAULT_STATE, vaultState = VAULT_STATE,
userOrganizationsList = emptyList(), userOrganizationsList = emptyList(),
hasPendingAccountAddition = false, hasPendingAccountAddition = false,
isBiometricsEnabledProvider = { false },
vaultUnlockTypeProvider = { VaultUnlockType.MASTER_PASSWORD }, vaultUnlockTypeProvider = { VaultUnlockType.MASTER_PASSWORD },
) )
fakeAuthDiskSource.userState = MULTI_USER_STATE fakeAuthDiskSource.userState = MULTI_USER_STATE

View file

@ -113,6 +113,7 @@ class UserStateJsonExtensionsTest {
name = "organizationName", name = "organizationName",
), ),
), ),
isBiometricsEnabled = false,
vaultUnlockType = VaultUnlockType.PIN, vaultUnlockType = VaultUnlockType.PIN,
), ),
), ),
@ -155,6 +156,7 @@ class UserStateJsonExtensionsTest {
), ),
), ),
hasPendingAccountAddition = false, hasPendingAccountAddition = false,
isBiometricsEnabledProvider = { false },
vaultUnlockTypeProvider = { VaultUnlockType.PIN }, vaultUnlockTypeProvider = { VaultUnlockType.PIN },
), ),
) )
@ -182,6 +184,7 @@ class UserStateJsonExtensionsTest {
name = "organizationName", name = "organizationName",
), ),
), ),
isBiometricsEnabled = true,
vaultUnlockType = VaultUnlockType.MASTER_PASSWORD, vaultUnlockType = VaultUnlockType.MASTER_PASSWORD,
), ),
), ),
@ -225,6 +228,7 @@ class UserStateJsonExtensionsTest {
), ),
), ),
hasPendingAccountAddition = true, hasPendingAccountAddition = true,
isBiometricsEnabledProvider = { true },
vaultUnlockTypeProvider = { VaultUnlockType.MASTER_PASSWORD }, vaultUnlockTypeProvider = { VaultUnlockType.MASTER_PASSWORD },
), ),
) )

View file

@ -71,6 +71,7 @@ class LandingViewModelTest : BaseViewModelTest() {
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
), ),
), ),
@ -201,6 +202,7 @@ class LandingViewModelTest : BaseViewModelTest() {
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
) )
val userState = UserState( val userState = UserState(
@ -250,6 +252,7 @@ class LandingViewModelTest : BaseViewModelTest() {
isPremium = true, isPremium = true,
isLoggedIn = false, isLoggedIn = false,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
) )
val userState = UserState( val userState = UserState(

View file

@ -127,6 +127,7 @@ class LoginViewModelTest : BaseViewModelTest() {
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
), ),
), ),

View file

@ -112,6 +112,7 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
), ),
), ),
@ -144,6 +145,7 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = false, isVaultUnlocked = false,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
), ),
), ),
@ -567,6 +569,7 @@ private val DEFAULT_ACCOUNT = UserState.Account(
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
) )

View file

@ -46,6 +46,7 @@ class RootNavViewModelTest : BaseViewModelTest() {
isPremium = true, isPremium = true,
isLoggedIn = false, isLoggedIn = false,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
), ),
), ),
@ -71,6 +72,7 @@ class RootNavViewModelTest : BaseViewModelTest() {
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
), ),
), ),
@ -96,6 +98,7 @@ class RootNavViewModelTest : BaseViewModelTest() {
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
), ),
), ),
@ -129,6 +132,7 @@ class RootNavViewModelTest : BaseViewModelTest() {
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
), ),
), ),
@ -156,6 +160,7 @@ class RootNavViewModelTest : BaseViewModelTest() {
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = false, isVaultUnlocked = false,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
), ),
), ),

View file

@ -926,6 +926,7 @@ private val DEFAULT_USER_STATE = UserState(
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
), ),
), ),

View file

@ -1786,6 +1786,7 @@ private val DEFAULT_USER_STATE = UserState(
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
), ),
), ),

View file

@ -1002,6 +1002,7 @@ class AddSendViewModelTest : BaseViewModelTest() {
isPremium = false, isPremium = false,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
) )

View file

@ -553,6 +553,7 @@ private val DEFAULT_USER_STATE = UserState(
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
), ),
), ),

View file

@ -1166,6 +1166,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
), ),
), ),

View file

@ -421,6 +421,7 @@ private val DEFAULT_USER_STATE = UserState(
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = listOf( organizations = listOf(
Organization( Organization(
id = "mockOrganizationId-1", id = "mockOrganizationId-1",

View file

@ -94,6 +94,7 @@ private fun createMockUserState(hasOrganizations: Boolean = true): UserState =
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = if (hasOrganizations) { organizations = if (hasOrganizations) {
listOf( listOf(
Organization( Organization(

View file

@ -153,6 +153,7 @@ class VaultViewModelTest : BaseViewModelTest() {
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = listOf( organizations = listOf(
Organization( Organization(
id = "organiationId", id = "organiationId",
@ -1223,6 +1224,7 @@ private val DEFAULT_USER_STATE = UserState(
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
), ),
UserState.Account( UserState.Account(
@ -1234,6 +1236,7 @@ private val DEFAULT_USER_STATE = UserState(
isPremium = false, isPremium = false,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = false, isVaultUnlocked = false,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
), ),
), ),

View file

@ -69,6 +69,7 @@ class UserStateExtensionsTest {
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = listOf( organizations = listOf(
Organization( Organization(
id = "organizationId", id = "organizationId",
@ -85,6 +86,7 @@ class UserStateExtensionsTest {
isPremium = false, isPremium = false,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = false, isVaultUnlocked = false,
isBiometricsEnabled = false,
organizations = listOf( organizations = listOf(
Organization( Organization(
id = "organizationId", id = "organizationId",
@ -105,6 +107,7 @@ class UserStateExtensionsTest {
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = listOf( organizations = listOf(
Organization( Organization(
id = "organizationId", id = "organizationId",
@ -125,6 +128,7 @@ class UserStateExtensionsTest {
isPremium = true, isPremium = true,
isLoggedIn = false, isLoggedIn = false,
isVaultUnlocked = false, isVaultUnlocked = false,
isBiometricsEnabled = false,
organizations = listOf( organizations = listOf(
Organization( Organization(
id = "organizationId", id = "organizationId",
@ -160,6 +164,7 @@ class UserStateExtensionsTest {
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = listOf( organizations = listOf(
Organization( Organization(
id = "organizationId", id = "organizationId",
@ -193,6 +198,7 @@ class UserStateExtensionsTest {
isPremium = false, isPremium = false,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = false, isVaultUnlocked = false,
isBiometricsEnabled = false,
organizations = listOf( organizations = listOf(
Organization( Organization(
id = "organizationId", id = "organizationId",
@ -230,6 +236,7 @@ class UserStateExtensionsTest {
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = listOf( organizations = listOf(
Organization( Organization(
id = "organizationId", id = "organizationId",
@ -255,6 +262,7 @@ class UserStateExtensionsTest {
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = emptyList(), organizations = emptyList(),
) )
.toVaultFilterData(), .toVaultFilterData(),
@ -289,6 +297,7 @@ class UserStateExtensionsTest {
isPremium = true, isPremium = true,
isLoggedIn = true, isLoggedIn = true,
isVaultUnlocked = true, isVaultUnlocked = true,
isBiometricsEnabled = false,
organizations = listOf( organizations = listOf(
Organization( Organization(
id = "organizationId-B", id = "organizationId-B",