mirror of
https://github.com/bitwarden/android.git
synced 2025-03-15 18:58:59 +03:00
Refactor vault unlock state to enum (#853)
This commit is contained in:
parent
d8ee29a0a4
commit
a317174db7
14 changed files with 423 additions and 440 deletions
|
@ -144,7 +144,7 @@ class AuthRepositoryImpl(
|
|||
override val userStateFlow: StateFlow<UserState?> = combine(
|
||||
authDiskSource.userStateFlow,
|
||||
authDiskSource.userOrganizationsListFlow,
|
||||
vaultRepository.vaultStateFlow,
|
||||
vaultRepository.vaultUnlockDataStateFlow,
|
||||
mutableHasPendingAccountAdditionStateFlow,
|
||||
mutableHasPendingAccountDeletionStateFlow,
|
||||
) {
|
||||
|
@ -174,7 +174,7 @@ class AuthRepositoryImpl(
|
|||
initialValue = authDiskSource
|
||||
.userState
|
||||
?.toUserState(
|
||||
vaultState = vaultRepository.vaultStateFlow.value,
|
||||
vaultState = vaultRepository.vaultUnlockDataStateFlow.value,
|
||||
userOrganizationsList = authDiskSource.userOrganizationsList,
|
||||
hasPendingAccountAddition = mutableHasPendingAccountAdditionStateFlow.value,
|
||||
isBiometricsEnabledProvider = ::isBiometricsEnabled,
|
||||
|
|
|
@ -6,7 +6,8 @@ import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
|||
import com.x8bit.bitwarden.data.auth.repository.model.VaultUnlockType
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.toEnvironmentUrlsOrDefault
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultState
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.statusFor
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.toHexColorRepresentation
|
||||
|
||||
/**
|
||||
|
@ -44,7 +45,7 @@ fun UserStateJson.toUpdatedUserStateJson(
|
|||
* Converts the given [UserStateJson] to a [UserState] using the given [vaultState].
|
||||
*/
|
||||
fun UserStateJson.toUserState(
|
||||
vaultState: VaultState,
|
||||
vaultState: List<VaultUnlockData>,
|
||||
userOrganizationsList: List<UserOrganizations>,
|
||||
hasPendingAccountAddition: Boolean,
|
||||
isBiometricsEnabledProvider: (userId: String) -> Boolean,
|
||||
|
@ -69,7 +70,8 @@ fun UserStateJson.toUserState(
|
|||
.toEnvironmentUrlsOrDefault(),
|
||||
isPremium = accountJson.profile.hasPremium == true,
|
||||
isLoggedIn = accountJson.isLoggedIn,
|
||||
isVaultUnlocked = userId in vaultState.unlockedVaultUserIds,
|
||||
isVaultUnlocked = vaultState.statusFor(userId) ==
|
||||
VaultUnlockData.Status.UNLOCKED,
|
||||
organizations = userOrganizationsList
|
||||
.find { it.userId == userId }
|
||||
?.organizations
|
||||
|
|
|
@ -7,10 +7,12 @@ import com.x8bit.bitwarden.data.autofill.model.AutofillCipher
|
|||
import com.x8bit.bitwarden.data.platform.manager.ciphermatching.CipherMatchingManager
|
||||
import com.x8bit.bitwarden.data.platform.util.subtitle
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.statusFor
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
||||
/**
|
||||
* The default [AutofillCipherProvider] implementation. This service is used for getting currrent
|
||||
* The default [AutofillCipherProvider] implementation. This service is used for getting current
|
||||
* [AutofillCipher]s.
|
||||
*/
|
||||
class AutofillCipherProviderImpl(
|
||||
|
@ -25,7 +27,9 @@ class AutofillCipherProviderImpl(
|
|||
|
||||
// Wait for any unlocking actions to finish. This can be relevant on startup for Never lock
|
||||
// accounts.
|
||||
vaultRepository.vaultStateFlow.first { userId !in it.unlockingVaultUserIds }
|
||||
vaultRepository.vaultUnlockDataStateFlow.first {
|
||||
it.statusFor(userId) != VaultUnlockData.Status.UNLOCKING
|
||||
}
|
||||
|
||||
return !vaultRepository.isVaultUnlocked(userId = userId)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package com.x8bit.bitwarden.data.vault.manager
|
|||
|
||||
import com.bitwarden.core.InitUserCryptoMethod
|
||||
import com.bitwarden.crypto.Kdf
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultState
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
|
@ -11,9 +11,9 @@ import kotlinx.coroutines.flow.StateFlow
|
|||
*/
|
||||
interface VaultLockManager {
|
||||
/**
|
||||
* Flow that represents the current vault state.
|
||||
* Flow that represents the current vault lock state for each user.
|
||||
*/
|
||||
val vaultStateFlow: StateFlow<VaultState>
|
||||
val vaultUnlockDataStateFlow: StateFlow<List<VaultUnlockData>>
|
||||
|
||||
/**
|
||||
* Whether or not the vault is currently locked for the given [userId].
|
||||
|
|
|
@ -20,9 +20,11 @@ import com.x8bit.bitwarden.data.platform.util.asSuccess
|
|||
import com.x8bit.bitwarden.data.platform.util.flatMap
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.InitializeCryptoResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultState
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.statusFor
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toVaultUnlockResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.update
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
@ -68,16 +70,11 @@ class VaultLockManagerImpl(
|
|||
private val activeUserId: String? get() = authDiskSource.userState?.activeUserId
|
||||
private val userIds: Set<String> get() = authDiskSource.userState?.accounts?.keys.orEmpty()
|
||||
|
||||
private val mutableVaultStateStateFlow =
|
||||
MutableStateFlow(
|
||||
VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
),
|
||||
)
|
||||
private val mutableVaultUnlockDataStateFlow =
|
||||
MutableStateFlow<List<VaultUnlockData>>(emptyList())
|
||||
|
||||
override val vaultStateFlow: StateFlow<VaultState>
|
||||
get() = mutableVaultStateStateFlow.asStateFlow()
|
||||
override val vaultUnlockDataStateFlow: StateFlow<List<VaultUnlockData>>
|
||||
get() = mutableVaultUnlockDataStateFlow.asStateFlow()
|
||||
|
||||
init {
|
||||
observeAppForegroundChanges()
|
||||
|
@ -86,10 +83,10 @@ class VaultLockManagerImpl(
|
|||
}
|
||||
|
||||
override fun isVaultUnlocked(userId: String): Boolean =
|
||||
userId in mutableVaultStateStateFlow.value.unlockedVaultUserIds
|
||||
mutableVaultUnlockDataStateFlow.value.statusFor(userId) == VaultUnlockData.Status.UNLOCKED
|
||||
|
||||
override fun isVaultUnlocking(userId: String): Boolean =
|
||||
userId in mutableVaultStateStateFlow.value.unlockingVaultUserIds
|
||||
mutableVaultUnlockDataStateFlow.value.statusFor(userId) == VaultUnlockData.Status.UNLOCKING
|
||||
|
||||
override fun lockVault(userId: String) {
|
||||
setVaultToLocked(userId = userId)
|
||||
|
@ -205,10 +202,8 @@ class VaultLockManagerImpl(
|
|||
}
|
||||
|
||||
private fun setVaultToUnlocked(userId: String) {
|
||||
mutableVaultStateStateFlow.update {
|
||||
it.copy(
|
||||
unlockedVaultUserIds = it.unlockedVaultUserIds + userId,
|
||||
)
|
||||
mutableVaultUnlockDataStateFlow.update {
|
||||
it.update(userId, VaultUnlockData.Status.UNLOCKED)
|
||||
}
|
||||
// If we are unlocking an account with a timeout of Never, we should make sure to store the
|
||||
// auto-unlock key.
|
||||
|
@ -217,10 +212,8 @@ class VaultLockManagerImpl(
|
|||
|
||||
private fun setVaultToLocked(userId: String) {
|
||||
vaultSdkSource.clearCrypto(userId = userId)
|
||||
mutableVaultStateStateFlow.update {
|
||||
it.copy(
|
||||
unlockedVaultUserIds = it.unlockedVaultUserIds - userId,
|
||||
)
|
||||
mutableVaultUnlockDataStateFlow.update {
|
||||
it.update(userId, null)
|
||||
}
|
||||
authDiskSource.storeUserAutoUnlockKey(
|
||||
userId = userId,
|
||||
|
@ -229,18 +222,16 @@ class VaultLockManagerImpl(
|
|||
}
|
||||
|
||||
private fun setVaultToUnlocking(userId: String) {
|
||||
mutableVaultStateStateFlow.update {
|
||||
it.copy(
|
||||
unlockingVaultUserIds = it.unlockingVaultUserIds + userId,
|
||||
)
|
||||
mutableVaultUnlockDataStateFlow.update {
|
||||
it.update(userId, VaultUnlockData.Status.UNLOCKING)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setVaultToNotUnlocking(userId: String) {
|
||||
mutableVaultStateStateFlow.update {
|
||||
it.copy(
|
||||
unlockingVaultUserIds = it.unlockingVaultUserIds - userId,
|
||||
)
|
||||
val status = mutableVaultUnlockDataStateFlow.value.statusFor(userId)
|
||||
if (status != VaultUnlockData.Status.UNLOCKING) return
|
||||
mutableVaultUnlockDataStateFlow.update {
|
||||
it.update(userId, null)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
package com.x8bit.bitwarden.data.vault.repository.model
|
||||
|
||||
/**
|
||||
* General description of the vault across multiple users.
|
||||
*
|
||||
* @property unlockedVaultUserIds The user IDs for all users that currently have unlocked vaults.
|
||||
* @property unlockedVaultUserIds The user IDs for all users that are actively unlocking their
|
||||
* vaults.
|
||||
*/
|
||||
data class VaultState(
|
||||
val unlockedVaultUserIds: Set<String>,
|
||||
val unlockingVaultUserIds: Set<String>,
|
||||
)
|
|
@ -0,0 +1,21 @@
|
|||
package com.x8bit.bitwarden.data.vault.repository.model
|
||||
|
||||
/**
|
||||
* The vault state for a given user ID.
|
||||
*
|
||||
* @property userId The user ID.
|
||||
* @property status The lock status of the user's vault.
|
||||
*/
|
||||
data class VaultUnlockData(
|
||||
val userId: String,
|
||||
val status: Status,
|
||||
) {
|
||||
/**
|
||||
* The lock status of a user's vault.
|
||||
*/
|
||||
enum class Status {
|
||||
PENDING,
|
||||
UNLOCKED,
|
||||
UNLOCKING,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.x8bit.bitwarden.data.vault.repository.util
|
||||
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData
|
||||
|
||||
/**
|
||||
* Get the vault unlock status for a [userId] from a list of [VaultUnlockData].
|
||||
*/
|
||||
fun List<VaultUnlockData>.statusFor(userId: String): VaultUnlockData.Status? =
|
||||
firstOrNull { it.userId == userId }?.status
|
||||
|
||||
/**
|
||||
* Update the vault unlock status for a [userId] in a list of [VaultUnlockData].
|
||||
*/
|
||||
fun List<VaultUnlockData>.update(
|
||||
userId: String,
|
||||
status: VaultUnlockData.Status?,
|
||||
): List<VaultUnlockData> {
|
||||
val updatedList = filter {
|
||||
it.userId != userId
|
||||
}
|
||||
return if (status == null) {
|
||||
updatedList
|
||||
} else {
|
||||
updatedList
|
||||
.plus(
|
||||
VaultUnlockData(
|
||||
userId = userId,
|
||||
status = status,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
|
@ -73,7 +73,7 @@ import com.x8bit.bitwarden.data.platform.util.asSuccess
|
|||
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockOrganization
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultState
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
|
@ -108,7 +108,7 @@ class AuthRepositoryTest {
|
|||
private val organizationService: OrganizationService = mockk()
|
||||
private val mutableVaultStateFlow = MutableStateFlow(VAULT_STATE)
|
||||
private val vaultRepository: VaultRepository = mockk {
|
||||
every { vaultStateFlow } returns mutableVaultStateFlow
|
||||
every { vaultUnlockDataStateFlow } returns mutableVaultStateFlow
|
||||
every { deleteVaultData(any()) } just runs
|
||||
every { clearUnlockedData() } just runs
|
||||
}
|
||||
|
@ -295,10 +295,7 @@ class AuthRepositoryTest {
|
|||
repository.userStateFlow.value,
|
||||
)
|
||||
|
||||
val emptyVaultState = VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
)
|
||||
val emptyVaultState = emptyList<VaultUnlockData>()
|
||||
mutableVaultStateFlow.value = emptyVaultState
|
||||
assertEquals(
|
||||
MULTI_USER_STATE.toUserState(
|
||||
|
@ -2915,9 +2912,11 @@ class AuthRepositoryTest {
|
|||
organizations = ORGANIZATIONS.toOrganizations(),
|
||||
),
|
||||
)
|
||||
private val VAULT_STATE = VaultState(
|
||||
unlockedVaultUserIds = setOf(USER_ID_1),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
private val VAULT_STATE = listOf(
|
||||
VaultUnlockData(
|
||||
userId = USER_ID_1,
|
||||
status = VaultUnlockData.Status.UNLOCKED,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import com.x8bit.bitwarden.data.auth.repository.model.UserOrganizations
|
|||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.VaultUnlockType
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultState
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
|
@ -140,9 +140,11 @@ class UserStateJsonExtensionsTest {
|
|||
),
|
||||
)
|
||||
.toUserState(
|
||||
vaultState = VaultState(
|
||||
unlockedVaultUserIds = setOf("activeUserId"),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
vaultState = listOf(
|
||||
VaultUnlockData(
|
||||
userId = "activeUserId",
|
||||
status = VaultUnlockData.Status.UNLOCKED,
|
||||
),
|
||||
),
|
||||
userOrganizationsList = listOf(
|
||||
UserOrganizations(
|
||||
|
@ -212,10 +214,7 @@ class UserStateJsonExtensionsTest {
|
|||
),
|
||||
)
|
||||
.toUserState(
|
||||
vaultState = VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
),
|
||||
vaultState = emptyList(),
|
||||
userOrganizationsList = listOf(
|
||||
UserOrganizations(
|
||||
userId = "activeUserId",
|
||||
|
|
|
@ -12,7 +12,8 @@ import com.x8bit.bitwarden.data.platform.manager.ciphermatching.CipherMatchingMa
|
|||
import com.x8bit.bitwarden.data.platform.repository.model.DataState
|
||||
import com.x8bit.bitwarden.data.platform.util.subtitle
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultState
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.statusFor
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.every
|
||||
|
@ -57,20 +58,17 @@ class AutofillCipherProviderTest {
|
|||
every { activeUserId } returns ACTIVE_USER_ID
|
||||
}
|
||||
private val cipherMatchingManager: CipherMatchingManager = mockk()
|
||||
private val mutableVaultStateFlow = MutableStateFlow(
|
||||
VaultState(
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
),
|
||||
private val mutableVaultStateFlow = MutableStateFlow<List<VaultUnlockData>>(
|
||||
emptyList(),
|
||||
)
|
||||
private val mutableCiphersStateFlow = MutableStateFlow<DataState<List<CipherView>>>(
|
||||
DataState.Loading,
|
||||
)
|
||||
private val vaultRepository: VaultRepository = mockk {
|
||||
every { ciphersStateFlow } returns mutableCiphersStateFlow
|
||||
every { vaultStateFlow } returns mutableVaultStateFlow
|
||||
every { vaultUnlockDataStateFlow } returns mutableVaultStateFlow
|
||||
every { isVaultUnlocked(ACTIVE_USER_ID) } answers {
|
||||
ACTIVE_USER_ID in mutableVaultStateFlow.value.unlockedVaultUserIds
|
||||
mutableVaultStateFlow.value.statusFor(ACTIVE_USER_ID) == VaultUnlockData.Status.UNLOCKED
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,9 +109,11 @@ class AutofillCipherProviderTest {
|
|||
fun `isVaultLocked when there is an active user should wait for pending unlocking to finish and return the locked state for that user`() =
|
||||
runTest {
|
||||
every { authRepository.activeUserId } returns ACTIVE_USER_ID
|
||||
mutableVaultStateFlow.value = VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = setOf(ACTIVE_USER_ID),
|
||||
mutableVaultStateFlow.value = listOf(
|
||||
VaultUnlockData(
|
||||
userId = ACTIVE_USER_ID,
|
||||
status = VaultUnlockData.Status.UNLOCKING,
|
||||
),
|
||||
)
|
||||
|
||||
val result = async {
|
||||
|
@ -123,9 +123,11 @@ class AutofillCipherProviderTest {
|
|||
testScheduler.advanceUntilIdle()
|
||||
assertFalse(result.isCompleted)
|
||||
|
||||
mutableVaultStateFlow.value = VaultState(
|
||||
unlockedVaultUserIds = setOf(ACTIVE_USER_ID),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
mutableVaultStateFlow.value = listOf(
|
||||
VaultUnlockData(
|
||||
userId = ACTIVE_USER_ID,
|
||||
status = VaultUnlockData.Status.UNLOCKED,
|
||||
),
|
||||
)
|
||||
|
||||
testScheduler.advanceUntilIdle()
|
||||
|
@ -150,9 +152,11 @@ class AutofillCipherProviderTest {
|
|||
mutableCiphersStateFlow.value = DataState.Loaded(
|
||||
data = cipherViews,
|
||||
)
|
||||
mutableVaultStateFlow.value = VaultState(
|
||||
unlockedVaultUserIds = setOf(ACTIVE_USER_ID),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
mutableVaultStateFlow.value = listOf(
|
||||
VaultUnlockData(
|
||||
userId = ACTIVE_USER_ID,
|
||||
status = VaultUnlockData.Status.UNLOCKED,
|
||||
),
|
||||
)
|
||||
val expected = listOf(
|
||||
CARD_AUTOFILL_CIPHER,
|
||||
|
@ -167,10 +171,7 @@ class AutofillCipherProviderTest {
|
|||
|
||||
@Test
|
||||
fun `getCardAutofillCiphers when locked should return an empty list`() = runTest {
|
||||
mutableVaultStateFlow.value = VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
)
|
||||
mutableVaultStateFlow.value = emptyList()
|
||||
|
||||
// Test & Verify
|
||||
val actual = autofillCipherProvider.getCardAutofillCiphers()
|
||||
|
@ -203,9 +204,11 @@ class AutofillCipherProviderTest {
|
|||
mutableCiphersStateFlow.value = DataState.Loaded(
|
||||
data = cipherViews,
|
||||
)
|
||||
mutableVaultStateFlow.value = VaultState(
|
||||
unlockedVaultUserIds = setOf(ACTIVE_USER_ID),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
mutableVaultStateFlow.value = listOf(
|
||||
VaultUnlockData(
|
||||
userId = ACTIVE_USER_ID,
|
||||
status = VaultUnlockData.Status.UNLOCKED,
|
||||
),
|
||||
)
|
||||
val expected = listOf(
|
||||
LOGIN_AUTOFILL_CIPHER,
|
||||
|
@ -229,10 +232,7 @@ class AutofillCipherProviderTest {
|
|||
|
||||
@Test
|
||||
fun `getLoginAutofillCiphers when locked should return an empty list`() = runTest {
|
||||
mutableVaultStateFlow.value = VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
)
|
||||
mutableVaultStateFlow.value = emptyList()
|
||||
|
||||
// Test & Verify
|
||||
val actual = autofillCipherProvider.getLoginAutofillCiphers(
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -91,7 +91,7 @@ import com.x8bit.bitwarden.data.vault.repository.model.UpdateCipherResult
|
|||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateFolderResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateSendResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultData
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultState
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.createMockDomainsData
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toDomainsData
|
||||
|
@ -148,14 +148,11 @@ class VaultRepositoryTest {
|
|||
private val vaultSdkSource: VaultSdkSource = mockk {
|
||||
every { clearCrypto(userId = any()) } just runs
|
||||
}
|
||||
private val mutableVaultStateFlow = MutableStateFlow(
|
||||
VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
),
|
||||
private val mutableVaultStateFlow = MutableStateFlow<List<VaultUnlockData>>(
|
||||
emptyList(),
|
||||
)
|
||||
private val vaultLockManager: VaultLockManager = mockk {
|
||||
every { vaultStateFlow } returns mutableVaultStateFlow
|
||||
every { vaultUnlockDataStateFlow } returns mutableVaultStateFlow
|
||||
every { isVaultUnlocked(any()) } returns false
|
||||
every { isVaultUnlocking(any()) } returns false
|
||||
every { lockVault(any()) } just runs
|
||||
|
@ -700,22 +697,16 @@ class VaultRepositoryTest {
|
|||
runTest {
|
||||
fakeAuthDiskSource.userState = null
|
||||
assertEquals(
|
||||
VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
),
|
||||
vaultRepository.vaultStateFlow.value,
|
||||
emptyList<VaultUnlockData>(),
|
||||
vaultRepository.vaultUnlockDataStateFlow.value,
|
||||
)
|
||||
|
||||
val result = vaultRepository.unlockVaultWithBiometrics()
|
||||
|
||||
assertEquals(VaultUnlockResult.InvalidStateError, result)
|
||||
assertEquals(
|
||||
VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
),
|
||||
vaultRepository.vaultStateFlow.value,
|
||||
emptyList<VaultUnlockData>(),
|
||||
vaultRepository.vaultUnlockDataStateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -724,11 +715,8 @@ class VaultRepositoryTest {
|
|||
fun `unlockVaultWithBiometrics with missing biometrics key should return InvalidStateError`() =
|
||||
runTest {
|
||||
assertEquals(
|
||||
VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
),
|
||||
vaultRepository.vaultStateFlow.value,
|
||||
emptyList<VaultUnlockData>(),
|
||||
vaultRepository.vaultUnlockDataStateFlow.value,
|
||||
)
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
val userId = MOCK_USER_STATE.activeUserId
|
||||
|
@ -738,11 +726,8 @@ class VaultRepositoryTest {
|
|||
|
||||
assertEquals(VaultUnlockResult.InvalidStateError, result)
|
||||
assertEquals(
|
||||
VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
),
|
||||
vaultRepository.vaultStateFlow.value,
|
||||
emptyList<VaultUnlockData>(),
|
||||
vaultRepository.vaultUnlockDataStateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -864,11 +849,8 @@ class VaultRepositoryTest {
|
|||
runTest {
|
||||
fakeAuthDiskSource.userState = null
|
||||
assertEquals(
|
||||
VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
),
|
||||
vaultRepository.vaultStateFlow.value,
|
||||
emptyList<VaultUnlockData>(),
|
||||
vaultRepository.vaultUnlockDataStateFlow.value,
|
||||
)
|
||||
|
||||
val result = vaultRepository.unlockVaultWithMasterPassword(masterPassword = "")
|
||||
|
@ -878,11 +860,8 @@ class VaultRepositoryTest {
|
|||
result,
|
||||
)
|
||||
assertEquals(
|
||||
VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
),
|
||||
vaultRepository.vaultStateFlow.value,
|
||||
emptyList<VaultUnlockData>(),
|
||||
vaultRepository.vaultUnlockDataStateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -891,11 +870,8 @@ class VaultRepositoryTest {
|
|||
fun `unlockVaultWithMasterPassword with missing user key should return InvalidStateError`() =
|
||||
runTest {
|
||||
assertEquals(
|
||||
VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
),
|
||||
vaultRepository.vaultStateFlow.value,
|
||||
emptyList<VaultUnlockData>(),
|
||||
vaultRepository.vaultUnlockDataStateFlow.value,
|
||||
)
|
||||
|
||||
val result = vaultRepository.unlockVaultWithMasterPassword(masterPassword = "")
|
||||
|
@ -913,11 +889,8 @@ class VaultRepositoryTest {
|
|||
result,
|
||||
)
|
||||
assertEquals(
|
||||
VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
),
|
||||
vaultRepository.vaultStateFlow.value,
|
||||
emptyList<VaultUnlockData>(),
|
||||
vaultRepository.vaultUnlockDataStateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -926,11 +899,8 @@ class VaultRepositoryTest {
|
|||
fun `unlockVaultWithMasterPassword with missing private key should return InvalidStateError`() =
|
||||
runTest {
|
||||
assertEquals(
|
||||
VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
),
|
||||
vaultRepository.vaultStateFlow.value,
|
||||
emptyList<VaultUnlockData>(),
|
||||
vaultRepository.vaultUnlockDataStateFlow.value,
|
||||
)
|
||||
val result = vaultRepository.unlockVaultWithMasterPassword(masterPassword = "")
|
||||
fakeAuthDiskSource.storeUserKey(
|
||||
|
@ -948,11 +918,8 @@ class VaultRepositoryTest {
|
|||
)
|
||||
|
||||
assertEquals(
|
||||
VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
),
|
||||
vaultRepository.vaultStateFlow.value,
|
||||
emptyList<VaultUnlockData>(),
|
||||
vaultRepository.vaultUnlockDataStateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1102,11 +1069,8 @@ class VaultRepositoryTest {
|
|||
runTest {
|
||||
fakeAuthDiskSource.userState = null
|
||||
assertEquals(
|
||||
VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
),
|
||||
vaultRepository.vaultStateFlow.value,
|
||||
emptyList<VaultUnlockData>(),
|
||||
vaultRepository.vaultUnlockDataStateFlow.value,
|
||||
)
|
||||
|
||||
val result = vaultRepository.unlockVaultWithPin(pin = "1234")
|
||||
|
@ -1116,11 +1080,8 @@ class VaultRepositoryTest {
|
|||
result,
|
||||
)
|
||||
assertEquals(
|
||||
VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
),
|
||||
vaultRepository.vaultStateFlow.value,
|
||||
emptyList<VaultUnlockData>(),
|
||||
vaultRepository.vaultUnlockDataStateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1129,11 +1090,8 @@ class VaultRepositoryTest {
|
|||
fun `unlockVaultWithPin with missing pin-protected user key should return InvalidStateError`() =
|
||||
runTest {
|
||||
assertEquals(
|
||||
VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
),
|
||||
vaultRepository.vaultStateFlow.value,
|
||||
emptyList<VaultUnlockData>(),
|
||||
vaultRepository.vaultUnlockDataStateFlow.value,
|
||||
)
|
||||
|
||||
val result = vaultRepository.unlockVaultWithPin(pin = "1234")
|
||||
|
@ -1151,11 +1109,8 @@ class VaultRepositoryTest {
|
|||
result,
|
||||
)
|
||||
assertEquals(
|
||||
VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
),
|
||||
vaultRepository.vaultStateFlow.value,
|
||||
emptyList<VaultUnlockData>(),
|
||||
vaultRepository.vaultUnlockDataStateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1164,11 +1119,8 @@ class VaultRepositoryTest {
|
|||
fun `unlockVaultWithPin with missing private key should return InvalidStateError`() =
|
||||
runTest {
|
||||
assertEquals(
|
||||
VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
),
|
||||
vaultRepository.vaultStateFlow.value,
|
||||
emptyList<VaultUnlockData>(),
|
||||
vaultRepository.vaultUnlockDataStateFlow.value,
|
||||
)
|
||||
val result = vaultRepository.unlockVaultWithPin(pin = "1234")
|
||||
fakeAuthDiskSource.storePinProtectedUserKey(
|
||||
|
@ -1185,11 +1137,8 @@ class VaultRepositoryTest {
|
|||
result,
|
||||
)
|
||||
assertEquals(
|
||||
VaultState(
|
||||
unlockedVaultUserIds = emptySet(),
|
||||
unlockingVaultUserIds = emptySet(),
|
||||
),
|
||||
vaultRepository.vaultStateFlow.value,
|
||||
emptyList<VaultUnlockData>(),
|
||||
vaultRepository.vaultUnlockDataStateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
package com.x8bit.bitwarden.data.vault.repository.util
|
||||
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class VaultUnlockDataExtensionsTest {
|
||||
@Test
|
||||
fun `statusFor returns the correct status for a userId in the list`() {
|
||||
val list = listOf(
|
||||
VaultUnlockData(
|
||||
userId = USER_ID_1,
|
||||
status = VaultUnlockData.Status.UNLOCKING,
|
||||
),
|
||||
VaultUnlockData(
|
||||
userId = USER_ID_2,
|
||||
status = VaultUnlockData.Status.UNLOCKED,
|
||||
),
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
VaultUnlockData.Status.UNLOCKING,
|
||||
list.statusFor(USER_ID_1),
|
||||
)
|
||||
assertEquals(
|
||||
VaultUnlockData.Status.UNLOCKED,
|
||||
list.statusFor(USER_ID_2),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `update updates the status for a user id in the list`() {
|
||||
val list = listOf(
|
||||
VaultUnlockData(
|
||||
userId = USER_ID_1,
|
||||
status = VaultUnlockData.Status.UNLOCKING,
|
||||
),
|
||||
VaultUnlockData(
|
||||
userId = USER_ID_2,
|
||||
status = VaultUnlockData.Status.UNLOCKED,
|
||||
),
|
||||
)
|
||||
|
||||
val updatedList = list.update(
|
||||
userId = USER_ID_1,
|
||||
status = VaultUnlockData.Status.UNLOCKED,
|
||||
)
|
||||
assertEquals(
|
||||
VaultUnlockData.Status.UNLOCKED,
|
||||
updatedList.statusFor(USER_ID_1),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private const val USER_ID_1 = "userId_1"
|
||||
private const val USER_ID_2 = "userId_2"
|
Loading…
Add table
Reference in a new issue