Refactor vault unlock state to enum (#853)

This commit is contained in:
Shannon Draeker 2024-01-29 20:16:23 -07:00 committed by Álison Fernandes
parent d8ee29a0a4
commit a317174db7
14 changed files with 423 additions and 440 deletions

View file

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

View file

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

View file

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

View file

@ -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].

View file

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

View file

@ -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>,
)

View file

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

View file

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

View file

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

View file

@ -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",

View file

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

View file

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

View file

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