mirror of
https://github.com/bitwarden/android.git
synced 2026-10-22 02:53:19 -05:00
Move BiometricsEncryptionManager into the AuthRepository (#6249)
This commit is contained in:
1 parent
2eb8ad4221
commit
cd27fe339d
17 files changed
+87
-182
No files matched your search
@@ -38,6 +38,7 @@ import com.x8bit.bitwarden.data.auth.repository.util.SsoCallbackResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.WebAuthResult
|
||||
import com.x8bit.bitwarden.data.auth.util.YubiKeyResult
|
||||
import com.x8bit.bitwarden.data.platform.datasource.network.authenticator.AuthenticatorProvider
|
||||
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@@ -48,6 +49,7 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
interface AuthRepository :
|
||||
AuthenticatorProvider,
|
||||
AuthRequestManager,
|
||||
BiometricsEncryptionManager,
|
||||
KdfManager,
|
||||
UserStateManager {
|
||||
/**
|
||||
|
||||
@@ -102,6 +102,7 @@ import com.x8bit.bitwarden.data.auth.util.YubiKeyResult
|
||||
import com.x8bit.bitwarden.data.auth.util.toSdkParams
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.error.NoActiveUserException
|
||||
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.LogsManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.PushManager
|
||||
@@ -157,6 +158,7 @@ class AuthRepositoryImpl(
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val vaultRepository: VaultRepository,
|
||||
private val authRequestManager: AuthRequestManager,
|
||||
private val biometricsEncryptionManager: BiometricsEncryptionManager,
|
||||
private val keyConnectorManager: KeyConnectorManager,
|
||||
private val trustedDeviceManager: TrustedDeviceManager,
|
||||
private val userLogoutManager: UserLogoutManager,
|
||||
@@ -168,6 +170,7 @@ class AuthRepositoryImpl(
|
||||
dispatcherManager: DispatcherManager,
|
||||
) : AuthRepository,
|
||||
AuthRequestManager by authRequestManager,
|
||||
BiometricsEncryptionManager by biometricsEncryptionManager,
|
||||
KdfManager by kdfManager,
|
||||
UserStateManager by userStateManager {
|
||||
/**
|
||||
|
||||
+3
@@ -19,6 +19,7 @@ import com.x8bit.bitwarden.data.auth.manager.UserStateManagerImpl
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepositoryImpl
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.LogsManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
@@ -60,6 +61,7 @@ object AuthRepositoryModule {
|
||||
environmentRepository: EnvironmentRepository,
|
||||
settingsRepository: SettingsRepository,
|
||||
vaultRepository: VaultRepository,
|
||||
biometricsEncryptionManager: BiometricsEncryptionManager,
|
||||
keyConnectorManager: KeyConnectorManager,
|
||||
authRequestManager: AuthRequestManager,
|
||||
trustedDeviceManager: TrustedDeviceManager,
|
||||
@@ -85,6 +87,7 @@ object AuthRepositoryModule {
|
||||
environmentRepository = environmentRepository,
|
||||
settingsRepository = settingsRepository,
|
||||
vaultRepository = vaultRepository,
|
||||
biometricsEncryptionManager = biometricsEncryptionManager,
|
||||
keyConnectorManager = keyConnectorManager,
|
||||
authRequestManager = authRequestManager,
|
||||
trustedDeviceManager = trustedDeviceManager,
|
||||
|
||||
+4
-5
@@ -11,10 +11,10 @@ import com.bitwarden.fido.Fido2CredentialAutofillView
|
||||
import com.bitwarden.ui.platform.resource.BitwardenDrawable
|
||||
import com.bitwarden.ui.platform.resource.BitwardenString
|
||||
import com.bitwarden.vault.CipherListView
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.autofill.util.login
|
||||
import com.x8bit.bitwarden.data.credentials.manager.CredentialManagerPendingIntentManager
|
||||
import com.x8bit.bitwarden.data.credentials.util.setBiometricPromptDataIfSupported
|
||||
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
|
||||
|
||||
/**
|
||||
* Primary implementation of [CredentialEntryBuilder].
|
||||
@@ -22,7 +22,7 @@ import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
|
||||
class CredentialEntryBuilderImpl(
|
||||
private val context: Context,
|
||||
private val pendingIntentManager: CredentialManagerPendingIntentManager,
|
||||
private val biometricsEncryptionManager: BiometricsEncryptionManager,
|
||||
private val authRepository: AuthRepository,
|
||||
) : CredentialEntryBuilder {
|
||||
|
||||
override fun buildPublicKeyCredentialEntries(
|
||||
@@ -82,7 +82,7 @@ class CredentialEntryBuilderImpl(
|
||||
.also { builder ->
|
||||
if (!isUserVerified) {
|
||||
builder.setBiometricPromptDataIfSupported(
|
||||
cipher = biometricsEncryptionManager.getOrCreateCipher(userId),
|
||||
cipher = authRepository.getOrCreateCipher(userId),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -113,8 +113,7 @@ class CredentialEntryBuilderImpl(
|
||||
.apply {
|
||||
if (!isUserVerified) {
|
||||
setBiometricPromptDataIfSupported(
|
||||
cipher = biometricsEncryptionManager
|
||||
.getOrCreateCipher(userId),
|
||||
cipher = authRepository.getOrCreateCipher(userId),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-5
@@ -25,7 +25,6 @@ import com.x8bit.bitwarden.data.credentials.repository.PrivilegedAppRepositoryIm
|
||||
import com.x8bit.bitwarden.data.credentials.sanitizer.PasskeyAttestationOptionsSanitizer
|
||||
import com.x8bit.bitwarden.data.credentials.sanitizer.PasskeyAttestationOptionsSanitizerImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.AssetManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.ciphermatching.CipherMatchingManager
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
@@ -54,7 +53,6 @@ object CredentialProviderModule {
|
||||
bitwardenCredentialManager: BitwardenCredentialManager,
|
||||
dispatcherManager: DispatcherManager,
|
||||
pendingIntentManager: CredentialManagerPendingIntentManager,
|
||||
biometricsEncryptionManager: BiometricsEncryptionManager,
|
||||
clock: Clock,
|
||||
): CredentialProviderProcessor =
|
||||
CredentialProviderProcessorImpl(
|
||||
@@ -63,7 +61,6 @@ object CredentialProviderModule {
|
||||
bitwardenCredentialManager = bitwardenCredentialManager,
|
||||
pendingIntentManager = pendingIntentManager,
|
||||
clock = clock,
|
||||
biometricsEncryptionManager = biometricsEncryptionManager,
|
||||
dispatcherManager = dispatcherManager,
|
||||
)
|
||||
|
||||
@@ -108,11 +105,11 @@ object CredentialProviderModule {
|
||||
fun provideCredentialEntryBuilder(
|
||||
@ApplicationContext context: Context,
|
||||
pendingIntentManager: CredentialManagerPendingIntentManager,
|
||||
biometricsEncryptionManager: BiometricsEncryptionManager,
|
||||
authRepository: AuthRepository,
|
||||
): CredentialEntryBuilder = CredentialEntryBuilderImpl(
|
||||
context = context,
|
||||
pendingIntentManager = pendingIntentManager,
|
||||
biometricsEncryptionManager = biometricsEncryptionManager,
|
||||
authRepository = authRepository,
|
||||
)
|
||||
|
||||
@Provides
|
||||
|
||||
+2
-4
@@ -34,7 +34,6 @@ import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||
import com.x8bit.bitwarden.data.credentials.manager.BitwardenCredentialManager
|
||||
import com.x8bit.bitwarden.data.credentials.manager.CredentialManagerPendingIntentManager
|
||||
import com.x8bit.bitwarden.data.credentials.model.GetCredentialsRequest
|
||||
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
@@ -53,7 +52,6 @@ class CredentialProviderProcessorImpl(
|
||||
private val bitwardenCredentialManager: BitwardenCredentialManager,
|
||||
private val pendingIntentManager: CredentialManagerPendingIntentManager,
|
||||
private val clock: Clock,
|
||||
private val biometricsEncryptionManager: BiometricsEncryptionManager,
|
||||
dispatcherManager: DispatcherManager,
|
||||
) : CredentialProviderProcessor {
|
||||
|
||||
@@ -203,7 +201,7 @@ class CredentialProviderProcessorImpl(
|
||||
.setAutoSelectAllowed(true)
|
||||
|
||||
if (isVaultUnlocked) {
|
||||
biometricsEncryptionManager
|
||||
authRepository
|
||||
.getOrCreateCipher(userId)
|
||||
?.let { entryBuilder.setBiometricPromptDataIfSupported(cipher = it) }
|
||||
}
|
||||
@@ -251,7 +249,7 @@ class CredentialProviderProcessorImpl(
|
||||
.setAutoSelectAllowed(true)
|
||||
|
||||
if (isVaultUnlocked) {
|
||||
biometricsEncryptionManager
|
||||
authRepository
|
||||
.getOrCreateCipher(userId)
|
||||
?.let { entryBuilder.setBiometricPromptDataIfSupported(cipher = it) }
|
||||
}
|
||||
|
||||
-1
@@ -32,7 +32,6 @@ interface BiometricsEncryptionManager {
|
||||
*/
|
||||
fun isBiometricIntegrityValid(
|
||||
userId: String,
|
||||
cipher: Cipher?,
|
||||
): Boolean
|
||||
|
||||
/**
|
||||
|
||||
+6
-4
@@ -90,8 +90,8 @@ class BiometricsEncryptionManagerImpl(
|
||||
return cipher?.takeIf { isCipherInitialized }
|
||||
}
|
||||
|
||||
override fun isBiometricIntegrityValid(userId: String, cipher: Cipher?): Boolean =
|
||||
isSystemBiometricIntegrityValid(userId, cipher) && isAccountBiometricIntegrityValid(userId)
|
||||
override fun isBiometricIntegrityValid(userId: String): Boolean =
|
||||
isSystemBiometricIntegrityValid(userId) && isAccountBiometricIntegrityValid(userId)
|
||||
|
||||
override fun isAccountBiometricIntegrityValid(userId: String): Boolean {
|
||||
val systemBioIntegrityState = settingsDiskSource
|
||||
@@ -203,11 +203,13 @@ class BiometricsEncryptionManagerImpl(
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the keystore key and decrypts it using the user-provided [cipher].
|
||||
* Validates the keystore key and decrypts it, if decryption is successful `true` is returned,
|
||||
* `false` otherwise.
|
||||
*/
|
||||
private fun isSystemBiometricIntegrityValid(userId: String, cipher: Cipher?): Boolean {
|
||||
private fun isSystemBiometricIntegrityValid(userId: String): Boolean {
|
||||
// Attempt to get the user scoped key. If that fails, we check to see if a legacy key
|
||||
// is available.
|
||||
val cipher = getOrCreateCipher(userId = userId)
|
||||
val secretKey = getSecretKeyOrNull(userId = userId) ?: getSecretKeyOrNull(userId = null)
|
||||
return if (cipher != null && secretKey != null) {
|
||||
cipher.initializeCipher(userId = userId, secretKey = secretKey)
|
||||
|
||||
+3
-9
@@ -10,7 +10,6 @@ import com.bitwarden.ui.util.asText
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.OnboardingStatus
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.autofill.manager.browser.BrowserThirdPartyAutofillEnabledManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.BiometricsKeyResult
|
||||
@@ -33,17 +32,12 @@ class SetupUnlockViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val authRepository: AuthRepository,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val biometricsEncryptionManager: BiometricsEncryptionManager,
|
||||
private val firstTimeActionManager: FirstTimeActionManager,
|
||||
private val browserThirdPartyAutofillEnabledManager: BrowserThirdPartyAutofillEnabledManager,
|
||||
) : BaseViewModel<SetupUnlockState, SetupUnlockEvent, SetupUnlockAction>(
|
||||
// We load the state from the savedStateHandle for testing purposes.
|
||||
initialState = savedStateHandle[KEY_STATE] ?: run {
|
||||
val userId = requireNotNull(authRepository.userStateFlow.value).activeUserId
|
||||
val isBiometricsValid = biometricsEncryptionManager.isBiometricIntegrityValid(
|
||||
userId = userId,
|
||||
cipher = biometricsEncryptionManager.getOrCreateCipher(userId = userId),
|
||||
)
|
||||
// whether or not the user has completed the initial setup prior to this.
|
||||
val isInitialSetup = savedStateHandle.toSetupUnlockArgs().isInitialSetup
|
||||
SetupUnlockState(
|
||||
@@ -55,7 +49,7 @@ class SetupUnlockViewModel @Inject constructor(
|
||||
?.hasMasterPassword != false,
|
||||
isUnlockWithPinEnabled = settingsRepository.isUnlockWithPinEnabled,
|
||||
isUnlockWithBiometricsEnabled = settingsRepository.isUnlockWithBiometricsEnabled &&
|
||||
isBiometricsValid,
|
||||
authRepository.isBiometricIntegrityValid(userId = userId),
|
||||
dialogState = null,
|
||||
isInitialSetup = isInitialSetup,
|
||||
)
|
||||
@@ -100,7 +94,7 @@ class SetupUnlockViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun handleEnableBiometricsClick() {
|
||||
biometricsEncryptionManager
|
||||
authRepository
|
||||
.createCipherOrNull(userId = state.userId)
|
||||
?.let {
|
||||
sendEvent(
|
||||
@@ -134,7 +128,7 @@ class SetupUnlockViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun handleUnlockWithBiometricToggleDisabled() {
|
||||
biometricsEncryptionManager.clearBiometrics(userId = state.userId)
|
||||
authRepository.clearBiometrics(userId = state.userId)
|
||||
mutableStateFlow.update { it.copy(isUnlockWithBiometricsEnabled = false) }
|
||||
}
|
||||
|
||||
|
||||
+6
-17
@@ -21,7 +21,6 @@ import com.x8bit.bitwarden.data.credentials.model.CreateCredentialRequest
|
||||
import com.x8bit.bitwarden.data.credentials.model.Fido2CredentialAssertionRequest
|
||||
import com.x8bit.bitwarden.data.credentials.model.GetCredentialsRequest
|
||||
import com.x8bit.bitwarden.data.platform.manager.AppResumeManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
||||
import com.x8bit.bitwarden.data.platform.manager.util.toCreateCredentialRequestOrNull
|
||||
@@ -55,7 +54,6 @@ private const val KEY_STATE = "state"
|
||||
class VaultUnlockViewModel @Inject constructor(
|
||||
private val authRepository: AuthRepository,
|
||||
private val vaultRepo: VaultRepository,
|
||||
private val biometricsEncryptionManager: BiometricsEncryptionManager,
|
||||
private val specialCircumstanceManager: SpecialCircumstanceManager,
|
||||
private val bitwardenCredentialManager: BitwardenCredentialManager,
|
||||
private val appResumeManager: AppResumeManager,
|
||||
@@ -68,10 +66,6 @@ class VaultUnlockViewModel @Inject constructor(
|
||||
val activeAccount = userState.activeAccount
|
||||
val accountSummaries = userState.toAccountSummaries()
|
||||
val activeAccountSummary = userState.toActiveAccountSummary()
|
||||
val isBiometricsValid = biometricsEncryptionManager.isBiometricIntegrityValid(
|
||||
userId = userState.activeUserId,
|
||||
cipher = biometricsEncryptionManager.getOrCreateCipher(userState.activeUserId),
|
||||
)
|
||||
val vaultUnlockType = activeAccount.vaultUnlockType
|
||||
val hasNoMasterPassword = !activeAccount.hasMasterPassword
|
||||
if (!activeAccount.hasManualUnlockMechanism) {
|
||||
@@ -82,7 +76,6 @@ class VaultUnlockViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
val specialCircumstance = specialCircumstanceManager.specialCircumstance
|
||||
|
||||
val showAccountMenu =
|
||||
savedStateHandle.toVaultUnlockArgs().unlockType == UnlockType.STANDARD &&
|
||||
(specialCircumstance !is SpecialCircumstance.ProviderGetCredentials &&
|
||||
@@ -97,7 +90,7 @@ class VaultUnlockViewModel @Inject constructor(
|
||||
environmentUrl = activeAccount.environment.label,
|
||||
input = "",
|
||||
isBiometricEnabled = activeAccount.isBiometricsEnabled,
|
||||
isBiometricsValid = isBiometricsValid,
|
||||
isBiometricsValid = authRepository.isBiometricIntegrityValid(userState.activeUserId),
|
||||
showAccountMenu = showAccountMenu,
|
||||
showBiometricInvalidatedMessage = false,
|
||||
vaultUnlockType = vaultUnlockType,
|
||||
@@ -233,7 +226,7 @@ class VaultUnlockViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun handleBiometricsUnlockClick() {
|
||||
val cipher = biometricsEncryptionManager.getOrCreateCipher(state.userId)
|
||||
val cipher = authRepository.getOrCreateCipher(state.userId)
|
||||
if (cipher != null) {
|
||||
sendEvent(
|
||||
event = VaultUnlockEvent.PromptForBiometrics(
|
||||
@@ -244,7 +237,7 @@ class VaultUnlockViewModel @Inject constructor(
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
isBiometricsValid = false,
|
||||
showBiometricInvalidatedMessage = !biometricsEncryptionManager
|
||||
showBiometricInvalidatedMessage = !authRepository
|
||||
.isAccountBiometricIntegrityValid(state.userId),
|
||||
)
|
||||
}
|
||||
@@ -351,7 +344,7 @@ class VaultUnlockViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
is VaultUnlockResult.BiometricDecodingError -> {
|
||||
biometricsEncryptionManager.clearBiometrics(userId = state.userId)
|
||||
authRepository.clearBiometrics(userId = state.userId)
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
isBiometricsValid = false,
|
||||
@@ -433,13 +426,9 @@ class VaultUnlockViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun promptForBiometricsIfAvailable() {
|
||||
val cipher = biometricsEncryptionManager.getOrCreateCipher(state.userId)
|
||||
val cipher = authRepository.getOrCreateCipher(state.userId)
|
||||
if (state.showBiometricLogin && cipher != null && !state.isFromLockFlow) {
|
||||
sendEvent(
|
||||
VaultUnlockEvent.PromptForBiometrics(
|
||||
cipher = cipher,
|
||||
),
|
||||
)
|
||||
sendEvent(VaultUnlockEvent.PromptForBiometrics(cipher = cipher))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-15
@@ -18,7 +18,6 @@ import com.x8bit.bitwarden.data.auth.repository.model.LogoutReason
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.PolicyInformation
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserFingerprintResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.policyInformation
|
||||
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||
@@ -51,28 +50,20 @@ class AccountSecurityViewModel @Inject constructor(
|
||||
private val vaultRepository: VaultRepository,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val environmentRepository: EnvironmentRepository,
|
||||
private val biometricsEncryptionManager: BiometricsEncryptionManager,
|
||||
private val firstTimeActionManager: FirstTimeActionManager,
|
||||
policyManager: PolicyManager,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : BaseViewModel<AccountSecurityState, AccountSecurityEvent, AccountSecurityAction>(
|
||||
initialState = savedStateHandle[KEY_STATE] ?: run {
|
||||
val userId = requireNotNull(authRepository.userStateFlow.value).activeUserId
|
||||
val isBiometricsValid = biometricsEncryptionManager.isBiometricIntegrityValid(
|
||||
userId = userId,
|
||||
cipher = biometricsEncryptionManager.getOrCreateCipher(userId),
|
||||
)
|
||||
val userState = requireNotNull(authRepository.userStateFlow.value)
|
||||
val userId = userState.activeUserId
|
||||
AccountSecurityState(
|
||||
dialog = null,
|
||||
fingerprintPhrase = "".asText(), // This will be filled in dynamically
|
||||
isAuthenticatorSyncChecked = settingsRepository.isAuthenticatorSyncEnabled,
|
||||
isUnlockWithBiometricsEnabled = settingsRepository.isUnlockWithBiometricsEnabled &&
|
||||
isBiometricsValid,
|
||||
isUnlockWithPasswordEnabled = authRepository
|
||||
.userStateFlow
|
||||
.value
|
||||
?.activeAccount
|
||||
?.hasMasterPassword != false,
|
||||
authRepository.isBiometricIntegrityValid(userId = userId),
|
||||
isUnlockWithPasswordEnabled = userState.activeAccount.hasMasterPassword,
|
||||
isUnlockWithPinEnabled = settingsRepository.isUnlockWithPinEnabled,
|
||||
shouldShowEnableAuthenticatorSync = isBuildVersionAtLeast(Build.VERSION_CODES.S),
|
||||
userId = userId,
|
||||
@@ -230,7 +221,7 @@ class AccountSecurityViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun handleEnableBiometricsClick() {
|
||||
biometricsEncryptionManager
|
||||
authRepository
|
||||
.createCipherOrNull(userId = state.userId)
|
||||
?.let {
|
||||
sendEvent(
|
||||
@@ -319,7 +310,7 @@ class AccountSecurityViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun handleUnlockWithBiometricToggleDisabled() {
|
||||
biometricsEncryptionManager.clearBiometrics(userId = state.userId)
|
||||
authRepository.clearBiometrics(userId = state.userId)
|
||||
mutableStateFlow.update { it.copy(isUnlockWithBiometricsEnabled = false) }
|
||||
validateVaultTimeoutAction()
|
||||
}
|
||||
|
||||
@@ -280,6 +280,7 @@ class AuthRepositoryTest {
|
||||
updateKdfToMinimumsIfNeeded(password = any())
|
||||
} returns UpdateKdfMinimumsResult.Success
|
||||
}
|
||||
|
||||
private val repository: AuthRepository = AuthRepositoryImpl(
|
||||
clock = FIXED_CLOCK,
|
||||
accountsService = accountsService,
|
||||
@@ -296,6 +297,7 @@ class AuthRepositoryTest {
|
||||
settingsRepository = settingsRepository,
|
||||
vaultRepository = vaultRepository,
|
||||
authRequestManager = authRequestManager,
|
||||
biometricsEncryptionManager = mockk(),
|
||||
keyConnectorManager = keyConnectorManager,
|
||||
trustedDeviceManager = trustedDeviceManager,
|
||||
userLogoutManager = userLogoutManager,
|
||||
|
||||
+8
-18
@@ -12,8 +12,8 @@ import com.bitwarden.core.util.isBuildVersionAtLeast
|
||||
import com.bitwarden.fido.Fido2CredentialAutofillView
|
||||
import com.bitwarden.vault.CipherListView
|
||||
import com.bitwarden.vault.CipherListViewType
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.credentials.manager.CredentialManagerPendingIntentManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
|
||||
import com.x8bit.bitwarden.data.util.mockBuilder
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherListView
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockFido2CredentialAutofillView
|
||||
@@ -53,13 +53,13 @@ class CredentialEntryBuilderTest {
|
||||
)
|
||||
} returns mockGetPasswordCredentialIntent
|
||||
}
|
||||
private val mockBiometricsEncryptionManager = mockk<BiometricsEncryptionManager>()
|
||||
private val mockAuthRepository = mockk<AuthRepository>()
|
||||
private val mockBeginGetPublicKeyOption = mockk<BeginGetPublicKeyCredentialOption>()
|
||||
private val mockBeginGetPasswordOption = mockk<BeginGetPasswordOption>()
|
||||
private val credentialEntryBuilder = CredentialEntryBuilderImpl(
|
||||
context = mockContext,
|
||||
pendingIntentManager = mockPendingIntentManager,
|
||||
biometricsEncryptionManager = mockBiometricsEncryptionManager,
|
||||
authRepository = mockAuthRepository,
|
||||
)
|
||||
private val mockPublicKeyCredentialEntry = mockk<PublicKeyCredentialEntry>(relaxed = true)
|
||||
private val mockPasswordCredentialEntry = mockk<PasswordCredentialEntry>(relaxed = true)
|
||||
@@ -136,9 +136,7 @@ class CredentialEntryBuilderTest {
|
||||
createMockFido2CredentialAutofillView(number = 1),
|
||||
)
|
||||
|
||||
every {
|
||||
mockBiometricsEncryptionManager.getOrCreateCipher("userId")
|
||||
} returns null
|
||||
every { mockAuthRepository.getOrCreateCipher("userId") } returns null
|
||||
|
||||
val result = credentialEntryBuilder
|
||||
.buildPublicKeyCredentialEntries(
|
||||
@@ -172,9 +170,7 @@ class CredentialEntryBuilderTest {
|
||||
|
||||
// Verify biometric prompt data is not set when buildVersion is at least 35
|
||||
// and cipher is null.
|
||||
every {
|
||||
mockBiometricsEncryptionManager.getOrCreateCipher("userId")
|
||||
} returns null
|
||||
every { mockAuthRepository.getOrCreateCipher("userId") } returns null
|
||||
every { isBuildVersionAtLeast(any()) } returns true
|
||||
|
||||
credentialEntryBuilder
|
||||
@@ -216,9 +212,7 @@ class CredentialEntryBuilderTest {
|
||||
}
|
||||
|
||||
// Verify biometric prompt data is not set when user is verified
|
||||
every {
|
||||
mockBiometricsEncryptionManager.getOrCreateCipher(any())
|
||||
} returns mockk(relaxed = true)
|
||||
every { mockAuthRepository.getOrCreateCipher(any()) } returns mockk(relaxed = true)
|
||||
credentialEntryBuilder
|
||||
.buildPublicKeyCredentialEntries(
|
||||
userId = "userId",
|
||||
@@ -305,9 +299,7 @@ class CredentialEntryBuilderTest {
|
||||
),
|
||||
),
|
||||
)
|
||||
every {
|
||||
mockBiometricsEncryptionManager.getOrCreateCipher("userId")
|
||||
} returns null
|
||||
every { mockAuthRepository.getOrCreateCipher("userId") } returns null
|
||||
|
||||
val result = credentialEntryBuilder
|
||||
.buildPasswordCredentialEntries(
|
||||
@@ -347,9 +339,7 @@ class CredentialEntryBuilderTest {
|
||||
),
|
||||
)
|
||||
|
||||
every {
|
||||
mockBiometricsEncryptionManager.getOrCreateCipher(any())
|
||||
} returns mockk(relaxed = true)
|
||||
every { mockAuthRepository.getOrCreateCipher(any()) } returns mockk(relaxed = true)
|
||||
every { isBuildVersionAtLeast(any()) } returns true
|
||||
|
||||
// Verify biometric prompt data is set when buildVersion is >= 35, cipher is
|
||||
|
||||
+8
-21
@@ -32,7 +32,6 @@ import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.VaultUnlockType
|
||||
import com.x8bit.bitwarden.data.credentials.manager.BitwardenCredentialManager
|
||||
import com.x8bit.bitwarden.data.credentials.manager.CredentialManagerPendingIntentManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.every
|
||||
@@ -71,7 +70,6 @@ class CredentialProviderProcessorTest {
|
||||
}
|
||||
private val pendingIntentManager: CredentialManagerPendingIntentManager = mockk()
|
||||
private val dispatcherManager: DispatcherManager = FakeDispatcherManager()
|
||||
private val biometricsEncryptionManager: BiometricsEncryptionManager = mockk()
|
||||
private val cancellationSignal: CancellationSignal = mockk()
|
||||
|
||||
private val clock = FIXED_CLOCK
|
||||
@@ -84,7 +82,6 @@ class CredentialProviderProcessorTest {
|
||||
bitwardenCredentialManager = bitwardenCredentialManager,
|
||||
pendingIntentManager = pendingIntentManager,
|
||||
clock = clock,
|
||||
biometricsEncryptionManager = biometricsEncryptionManager,
|
||||
dispatcherManager = dispatcherManager,
|
||||
)
|
||||
|
||||
@@ -167,9 +164,7 @@ class CredentialProviderProcessorTest {
|
||||
userId = any(),
|
||||
)
|
||||
} returns mockIntent
|
||||
every {
|
||||
biometricsEncryptionManager.getOrCreateCipher(userId = any())
|
||||
} returns mockk<Cipher>()
|
||||
every { authRepository.getOrCreateCipher(userId = any()) } returns mockk<Cipher>()
|
||||
every { cancellationSignal.setOnCancelListener(any()) } just runs
|
||||
every { callback.onResult(capture(captureSlot)) } just runs
|
||||
|
||||
@@ -208,9 +203,7 @@ class CredentialProviderProcessorTest {
|
||||
userId = any(),
|
||||
)
|
||||
} returns mockIntent
|
||||
every {
|
||||
biometricsEncryptionManager.getOrCreateCipher(any())
|
||||
} returns mockk<Cipher>()
|
||||
every { authRepository.getOrCreateCipher(any()) } returns mockk<Cipher>()
|
||||
every { isBuildVersionAtLeast(Build.VERSION_CODES.VANILLA_ICE_CREAM) } returns true
|
||||
|
||||
credentialProviderProcessor.processCreateCredentialRequest(
|
||||
@@ -249,7 +242,7 @@ class CredentialProviderProcessorTest {
|
||||
) { "Expected all entries to have BIOMETRIC_STRONG authenticators." }
|
||||
|
||||
// Verify entries have no biometric prompt data when cipher is null
|
||||
every { biometricsEncryptionManager.getOrCreateCipher(any()) } returns null
|
||||
every { authRepository.getOrCreateCipher(any()) } returns null
|
||||
credentialProviderProcessor.processCreateCredentialRequest(
|
||||
request = request,
|
||||
cancellationSignal = cancellationSignal,
|
||||
@@ -279,9 +272,7 @@ class CredentialProviderProcessorTest {
|
||||
userId = any(),
|
||||
)
|
||||
} returns mockIntent
|
||||
every {
|
||||
biometricsEncryptionManager.getOrCreateCipher(userId = any())
|
||||
} returns mockk<Cipher>()
|
||||
every { authRepository.getOrCreateCipher(userId = any()) } returns mockk<Cipher>()
|
||||
every { cancellationSignal.setOnCancelListener(any()) } just runs
|
||||
every { callback.onResult(capture(captureSlot)) } just runs
|
||||
every { isBuildVersionAtLeast(Build.VERSION_CODES.VANILLA_ICE_CREAM) } returns false
|
||||
@@ -332,7 +323,7 @@ class CredentialProviderProcessorTest {
|
||||
)
|
||||
|
||||
verify(exactly = 1) { callback.onResult(any()) }
|
||||
verify(exactly = 0) { biometricsEncryptionManager.getOrCreateCipher(any()) }
|
||||
verify(exactly = 0) { authRepository.getOrCreateCipher(any()) }
|
||||
|
||||
// Verify entries have no biometric prompt data when vault is locked
|
||||
assertTrue(captureSlot.captured.createEntries.all { it.biometricPromptData == null }) {
|
||||
@@ -416,9 +407,7 @@ class CredentialProviderProcessorTest {
|
||||
userId = any(),
|
||||
)
|
||||
} returns mockIntent
|
||||
every {
|
||||
biometricsEncryptionManager.getOrCreateCipher(userId = any())
|
||||
} returns mockk<Cipher>()
|
||||
every { authRepository.getOrCreateCipher(userId = any()) } returns mockk<Cipher>()
|
||||
every { cancellationSignal.setOnCancelListener(any()) } just runs
|
||||
every { request.candidateQueryData } returns candidateQueryData
|
||||
every {
|
||||
@@ -464,9 +453,7 @@ class CredentialProviderProcessorTest {
|
||||
userId = any(),
|
||||
)
|
||||
} returns mockIntent
|
||||
every {
|
||||
biometricsEncryptionManager.getOrCreateCipher(any())
|
||||
} returns mockk<Cipher>()
|
||||
every { authRepository.getOrCreateCipher(any()) } returns mockk<Cipher>()
|
||||
every { isBuildVersionAtLeast(Build.VERSION_CODES.VANILLA_ICE_CREAM) } returns true
|
||||
|
||||
credentialProviderProcessor.processCreateCredentialRequest(
|
||||
@@ -505,7 +492,7 @@ class CredentialProviderProcessorTest {
|
||||
) { "Expected all entries to have BIOMETRIC_STRONG authenticators." }
|
||||
|
||||
// Verify entries have no biometric prompt data when cipher is null
|
||||
every { biometricsEncryptionManager.getOrCreateCipher(any()) } returns null
|
||||
every { authRepository.getOrCreateCipher(any()) } returns null
|
||||
credentialProviderProcessor.processCreateCredentialRequest(
|
||||
request = request,
|
||||
cancellationSignal = cancellationSignal,
|
||||
|
||||
+9
-20
@@ -10,7 +10,6 @@ import com.x8bit.bitwarden.data.auth.datasource.disk.model.OnboardingStatus
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||
import com.x8bit.bitwarden.data.autofill.manager.browser.BrowserThirdPartyAutofillEnabledManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
@@ -40,6 +39,8 @@ class SetupUnlockViewModelTest : BaseViewModelTest() {
|
||||
private val authRepository: AuthRepository = mockk {
|
||||
every { userStateFlow } returns mutableUserStateFlow
|
||||
every { setOnboardingStatus(status = any()) } just runs
|
||||
every { isBiometricIntegrityValid(userId = DEFAULT_USER_ID) } returns false
|
||||
every { createCipherOrNull(DEFAULT_USER_ID) } returns CIPHER
|
||||
}
|
||||
|
||||
private val mutableAutofillEnabledStateFlow = MutableStateFlow(false)
|
||||
@@ -53,13 +54,6 @@ class SetupUnlockViewModelTest : BaseViewModelTest() {
|
||||
every { firstTimeStateFlow } returns mutableFirstTimeStateFlow
|
||||
every { storeShowUnlockSettingBadge(any()) } just runs
|
||||
}
|
||||
private val biometricsEncryptionManager: BiometricsEncryptionManager = mockk {
|
||||
every { getOrCreateCipher(userId = DEFAULT_USER_ID) } returns CIPHER
|
||||
every {
|
||||
isBiometricIntegrityValid(userId = DEFAULT_USER_ID, cipher = CIPHER)
|
||||
} returns false
|
||||
every { createCipherOrNull(DEFAULT_USER_ID) } returns CIPHER
|
||||
}
|
||||
private val thirdPartyAutofillEnabledManager: BrowserThirdPartyAutofillEnabledManager = mockk {
|
||||
every {
|
||||
browserThirdPartyAutofillStatus
|
||||
@@ -180,7 +174,7 @@ class SetupUnlockViewModelTest : BaseViewModelTest() {
|
||||
fun `on UnlockWithBiometricToggleDisabled should call clearBiometricsKey and update the state`() {
|
||||
val initialState = DEFAULT_STATE.copy(isUnlockWithBiometricsEnabled = true)
|
||||
every { settingsRepository.isUnlockWithBiometricsEnabled } returns true
|
||||
every { biometricsEncryptionManager.clearBiometrics(userId = DEFAULT_USER_ID) } just runs
|
||||
every { authRepository.clearBiometrics(userId = DEFAULT_USER_ID) } just runs
|
||||
val viewModel = createViewModel(initialState)
|
||||
assertEquals(initialState, viewModel.stateFlow.value)
|
||||
|
||||
@@ -191,7 +185,7 @@ class SetupUnlockViewModelTest : BaseViewModelTest() {
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
biometricsEncryptionManager.clearBiometrics(userId = DEFAULT_USER_ID)
|
||||
authRepository.clearBiometrics(userId = DEFAULT_USER_ID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,25 +334,21 @@ class SetupUnlockViewModelTest : BaseViewModelTest() {
|
||||
runTest {
|
||||
val viewModel = createViewModel()
|
||||
|
||||
viewModel.trySendAction(SetupUnlockAction.EnableBiometricsClick)
|
||||
|
||||
verify {
|
||||
biometricsEncryptionManager.getOrCreateCipher(DEFAULT_USER_ID)
|
||||
}
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(SetupUnlockAction.EnableBiometricsClick)
|
||||
assertEquals(
|
||||
SetupUnlockEvent.ShowBiometricsPrompt(CIPHER),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
verify {
|
||||
authRepository.createCipherOrNull(DEFAULT_USER_ID)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `EnableBiometricsClick actin should show error dialog when cipher is null`() {
|
||||
every {
|
||||
biometricsEncryptionManager.createCipherOrNull(DEFAULT_USER_ID)
|
||||
} returns null
|
||||
every { authRepository.createCipherOrNull(DEFAULT_USER_ID) } returns null
|
||||
val viewModel = createViewModel()
|
||||
|
||||
viewModel.trySendAction(SetupUnlockAction.EnableBiometricsClick)
|
||||
@@ -411,7 +401,6 @@ class SetupUnlockViewModelTest : BaseViewModelTest() {
|
||||
},
|
||||
authRepository = authRepository,
|
||||
settingsRepository = settingsRepository,
|
||||
biometricsEncryptionManager = biometricsEncryptionManager,
|
||||
firstTimeActionManager = firstTimeActionManager,
|
||||
browserThirdPartyAutofillEnabledManager = thirdPartyAutofillEnabledManager,
|
||||
)
|
||||
|
||||
+14
-30
@@ -18,7 +18,6 @@ import com.x8bit.bitwarden.data.credentials.manager.BitwardenCredentialManager
|
||||
import com.x8bit.bitwarden.data.credentials.model.createMockFido2CredentialAssertionRequest
|
||||
import com.x8bit.bitwarden.data.credentials.model.createMockGetCredentialsRequest
|
||||
import com.x8bit.bitwarden.data.platform.manager.AppResumeManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
||||
@@ -60,25 +59,12 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
|
||||
every { logout(reason = any()) } just runs
|
||||
every { logout(userId = any(), reason = any()) } just runs
|
||||
every { switchAccount(any()) } returns SwitchAccountResult.AccountSwitched
|
||||
every { getOrCreateCipher(USER_ID) } returns CIPHER
|
||||
every { isBiometricIntegrityValid(userId = DEFAULT_USER_STATE.activeUserId) } returns true
|
||||
}
|
||||
private val vaultRepository: VaultRepository = mockk(relaxed = true) {
|
||||
every { lockVault(any(), any()) } just runs
|
||||
}
|
||||
private val encryptionManager: BiometricsEncryptionManager = mockk {
|
||||
every { getOrCreateCipher(USER_ID) } returns CIPHER
|
||||
every {
|
||||
isBiometricIntegrityValid(
|
||||
userId = DEFAULT_USER_STATE.activeUserId,
|
||||
cipher = CIPHER,
|
||||
)
|
||||
} returns true
|
||||
every {
|
||||
isBiometricIntegrityValid(
|
||||
userId = DEFAULT_USER_STATE.activeUserId,
|
||||
cipher = null,
|
||||
)
|
||||
} returns false
|
||||
}
|
||||
private val bitwardenCredentialManager: BitwardenCredentialManager = mockk {
|
||||
every { isUserVerified } returns true
|
||||
every { isUserVerified = any() } just runs
|
||||
@@ -124,7 +110,7 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
|
||||
fun `initial state should be correct when not set`() {
|
||||
val viewModel = createViewModel()
|
||||
assertEquals(DEFAULT_STATE, viewModel.stateFlow.value)
|
||||
verify { encryptionManager.getOrCreateCipher(USER_ID) }
|
||||
verify { authRepository.getOrCreateCipher(USER_ID) }
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -506,7 +492,7 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
|
||||
viewModel.trySendAction(VaultUnlockAction.BiometricsUnlockClick)
|
||||
assertEquals(VaultUnlockEvent.PromptForBiometrics(CIPHER), awaitItem())
|
||||
}
|
||||
verify { encryptionManager.getOrCreateCipher(USER_ID) }
|
||||
verify { authRepository.getOrCreateCipher(USER_ID) }
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -533,8 +519,8 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
|
||||
fun `on BiometricsUnlockClick should disable isBiometricsValid and show message when cipher is null and integrity check returns false`() {
|
||||
val initialState = DEFAULT_STATE.copy(isBiometricsValid = true)
|
||||
val viewModel = createViewModel(state = initialState)
|
||||
every { encryptionManager.getOrCreateCipher(USER_ID) } returns null
|
||||
every { encryptionManager.isAccountBiometricIntegrityValid(USER_ID) } returns false
|
||||
every { authRepository.getOrCreateCipher(USER_ID) } returns null
|
||||
every { authRepository.isAccountBiometricIntegrityValid(USER_ID) } returns false
|
||||
|
||||
viewModel.trySendAction(VaultUnlockAction.BiometricsUnlockClick)
|
||||
assertEquals(
|
||||
@@ -544,7 +530,7 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
verify { encryptionManager.getOrCreateCipher(USER_ID) }
|
||||
verify { authRepository.getOrCreateCipher(USER_ID) }
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@@ -552,8 +538,8 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
|
||||
fun `on BiometricsUnlockClick should disable isBiometricsValid and not show message when cipher is null and integrity check returns true`() {
|
||||
val initialState = DEFAULT_STATE.copy(isBiometricsValid = true)
|
||||
val viewModel = createViewModel(state = initialState)
|
||||
every { encryptionManager.getOrCreateCipher(USER_ID) } returns null
|
||||
every { encryptionManager.isAccountBiometricIntegrityValid(USER_ID) } returns true
|
||||
every { authRepository.getOrCreateCipher(USER_ID) } returns null
|
||||
every { authRepository.isAccountBiometricIntegrityValid(USER_ID) } returns true
|
||||
|
||||
viewModel.trySendAction(VaultUnlockAction.BiometricsUnlockClick)
|
||||
assertEquals(
|
||||
@@ -563,7 +549,7 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
verify { encryptionManager.getOrCreateCipher(USER_ID) }
|
||||
verify { authRepository.getOrCreateCipher(USER_ID) }
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -718,7 +704,7 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
// The initial state causes this to be called as well as the change.
|
||||
verify(exactly = 2) {
|
||||
encryptionManager.getOrCreateCipher(USER_ID)
|
||||
authRepository.getOrCreateCipher(USER_ID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -745,7 +731,7 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
// Only the call for the initial state should be called.
|
||||
verify(exactly = 1) {
|
||||
encryptionManager.getOrCreateCipher(USER_ID)
|
||||
authRepository.getOrCreateCipher(USER_ID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1168,7 +1154,7 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
|
||||
coEvery {
|
||||
vaultRepository.unlockVaultWithBiometrics(cipher = CIPHER)
|
||||
} returns VaultUnlockResult.BiometricDecodingError(error = Throwable("Fail"))
|
||||
every { encryptionManager.clearBiometrics(userId = USER_ID) } just runs
|
||||
every { authRepository.clearBiometrics(userId = USER_ID) } just runs
|
||||
|
||||
viewModel.trySendAction(VaultUnlockAction.BiometricsUnlockSuccess(CIPHER))
|
||||
|
||||
@@ -1183,7 +1169,7 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
coVerify(exactly = 1) {
|
||||
encryptionManager.clearBiometrics(userId = USER_ID)
|
||||
authRepository.clearBiometrics(userId = USER_ID)
|
||||
vaultRepository.unlockVaultWithBiometrics(cipher = CIPHER)
|
||||
}
|
||||
}
|
||||
@@ -1341,7 +1327,6 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
|
||||
state: VaultUnlockState? = null,
|
||||
unlockType: UnlockType = UnlockType.STANDARD,
|
||||
vaultRepo: VaultRepository = vaultRepository,
|
||||
biometricsEncryptionManager: BiometricsEncryptionManager = encryptionManager,
|
||||
lockManager: VaultLockManager = vaultLockManager,
|
||||
): VaultUnlockViewModel = VaultUnlockViewModel(
|
||||
savedStateHandle = SavedStateHandle().apply {
|
||||
@@ -1350,7 +1335,6 @@ class VaultUnlockViewModelTest : BaseViewModelTest() {
|
||||
},
|
||||
authRepository = authRepository,
|
||||
vaultRepo = vaultRepo,
|
||||
biometricsEncryptionManager = biometricsEncryptionManager,
|
||||
bitwardenCredentialManager = bitwardenCredentialManager,
|
||||
specialCircumstanceManager = specialCircumstanceManager,
|
||||
appResumeManager = appResumeManager,
|
||||
|
||||
+9
-33
@@ -21,7 +21,6 @@ import com.x8bit.bitwarden.data.auth.repository.model.PolicyInformation
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserFingerprintResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||
import com.x8bit.bitwarden.data.platform.error.NoActiveUserException
|
||||
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState
|
||||
@@ -62,6 +61,8 @@ class AccountSecurityViewModelTest : BaseViewModelTest() {
|
||||
private val mutableUserStateFlow = MutableStateFlow<UserState?>(DEFAULT_USER_STATE)
|
||||
private val authRepository: AuthRepository = mockk(relaxed = true) {
|
||||
every { userStateFlow } returns mutableUserStateFlow
|
||||
every { createCipherOrNull(DEFAULT_USER_STATE.activeUserId) } returns CIPHER
|
||||
every { isBiometricIntegrityValid(userId = DEFAULT_USER_STATE.activeUserId) } returns true
|
||||
}
|
||||
private val vaultRepository: VaultRepository = mockk(relaxed = true)
|
||||
private val mutableBiometricsUnlockEnabledFlow = bufferedMutableSharedFlow<Boolean>()
|
||||
@@ -84,16 +85,6 @@ class AccountSecurityViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
private val mutableActivePolicyFlow = bufferedMutableSharedFlow<List<Policy>>()
|
||||
private val mutableRemovePinPolicyFlow = bufferedMutableSharedFlow<List<Policy>>()
|
||||
private val biometricsEncryptionManager: BiometricsEncryptionManager = mockk {
|
||||
every { createCipherOrNull(DEFAULT_USER_STATE.activeUserId) } returns CIPHER
|
||||
every { getOrCreateCipher(DEFAULT_USER_STATE.activeUserId) } returns CIPHER
|
||||
every {
|
||||
isBiometricIntegrityValid(
|
||||
userId = DEFAULT_USER_STATE.activeUserId,
|
||||
cipher = CIPHER,
|
||||
)
|
||||
} returns true
|
||||
}
|
||||
private val policyManager: PolicyManager = mockk {
|
||||
every {
|
||||
getActivePoliciesFlow(type = PolicyTypeJson.MAXIMUM_VAULT_TIMEOUT)
|
||||
@@ -123,16 +114,9 @@ class AccountSecurityViewModelTest : BaseViewModelTest() {
|
||||
@Test
|
||||
fun `initial state should be correct when saved state is not set`() {
|
||||
val viewModel = createViewModel(initialState = null)
|
||||
assertEquals(
|
||||
DEFAULT_STATE,
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
assertEquals(DEFAULT_STATE, viewModel.stateFlow.value)
|
||||
verify {
|
||||
biometricsEncryptionManager.getOrCreateCipher(DEFAULT_USER_STATE.activeUserId)
|
||||
biometricsEncryptionManager.isBiometricIntegrityValid(
|
||||
userId = DEFAULT_USER_STATE.activeUserId,
|
||||
cipher = CIPHER,
|
||||
)
|
||||
settingsRepository.isUnlockWithBiometricsEnabled
|
||||
}
|
||||
coVerify { settingsRepository.getUserFingerprint() }
|
||||
}
|
||||
@@ -510,9 +494,7 @@ class AccountSecurityViewModelTest : BaseViewModelTest() {
|
||||
|
||||
@Test
|
||||
fun `on EnableBiometricsClick should show Error dialog when cipher is null`() {
|
||||
every {
|
||||
biometricsEncryptionManager.createCipherOrNull(DEFAULT_USER_STATE.activeUserId)
|
||||
} returns null
|
||||
every { authRepository.createCipherOrNull(DEFAULT_USER_STATE.activeUserId) } returns null
|
||||
val viewModel = createViewModel()
|
||||
|
||||
viewModel.trySendAction(AccountSecurityAction.EnableBiometricsClick)
|
||||
@@ -534,9 +516,7 @@ class AccountSecurityViewModelTest : BaseViewModelTest() {
|
||||
runTest {
|
||||
val initialState = DEFAULT_STATE.copy(isUnlockWithBiometricsEnabled = true)
|
||||
every { settingsRepository.isUnlockWithBiometricsEnabled } returns true
|
||||
every {
|
||||
biometricsEncryptionManager.clearBiometrics(userId = DEFAULT_USER_ID)
|
||||
} just runs
|
||||
every { authRepository.clearBiometrics(userId = DEFAULT_USER_ID) } just runs
|
||||
val viewModel = createViewModel(initialState)
|
||||
assertEquals(initialState, viewModel.stateFlow.value)
|
||||
|
||||
@@ -547,7 +527,7 @@ class AccountSecurityViewModelTest : BaseViewModelTest() {
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
biometricsEncryptionManager.clearBiometrics(userId = DEFAULT_USER_ID)
|
||||
authRepository.clearBiometrics(userId = DEFAULT_USER_ID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -560,9 +540,7 @@ class AccountSecurityViewModelTest : BaseViewModelTest() {
|
||||
isUnlockWithBiometricsEnabled = true,
|
||||
)
|
||||
every { settingsRepository.isUnlockWithBiometricsEnabled } returns true
|
||||
every {
|
||||
biometricsEncryptionManager.clearBiometrics(userId = DEFAULT_USER_ID)
|
||||
} just runs
|
||||
every { authRepository.clearBiometrics(userId = DEFAULT_USER_ID) } just runs
|
||||
every { settingsRepository.vaultTimeoutAction = VaultTimeoutAction.LOGOUT } just runs
|
||||
val viewModel = createViewModel(initialState)
|
||||
assertEquals(initialState, viewModel.stateFlow.value)
|
||||
@@ -577,7 +555,7 @@ class AccountSecurityViewModelTest : BaseViewModelTest() {
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
biometricsEncryptionManager.clearBiometrics(userId = DEFAULT_USER_ID)
|
||||
authRepository.clearBiometrics(userId = DEFAULT_USER_ID)
|
||||
settingsRepository.vaultTimeoutAction = VaultTimeoutAction.LOGOUT
|
||||
}
|
||||
}
|
||||
@@ -903,14 +881,12 @@ class AccountSecurityViewModelTest : BaseViewModelTest() {
|
||||
vaultRepository: VaultRepository = this.vaultRepository,
|
||||
environmentRepository: EnvironmentRepository = this.fakeEnvironmentRepository,
|
||||
settingsRepository: SettingsRepository = this.settingsRepository,
|
||||
biometricsEncryptionManager: BiometricsEncryptionManager = this.biometricsEncryptionManager,
|
||||
policyManager: PolicyManager = this.policyManager,
|
||||
): AccountSecurityViewModel = AccountSecurityViewModel(
|
||||
authRepository = authRepository,
|
||||
vaultRepository = vaultRepository,
|
||||
settingsRepository = settingsRepository,
|
||||
environmentRepository = environmentRepository,
|
||||
biometricsEncryptionManager = biometricsEncryptionManager,
|
||||
policyManager = policyManager,
|
||||
savedStateHandle = SavedStateHandle().apply {
|
||||
set("state", initialState)
|
||||
|
||||
Reference in new issue
Block a user