BIT-1091: Initialize crypto for organizations (#370)

This commit is contained in:
Brian Yencho 2023-12-12 10:16:41 -06:00 committed by Álison Fernandes
parent 970e913373
commit 65b9005cbe
10 changed files with 661 additions and 81 deletions

View file

@ -179,9 +179,10 @@ class AuthRepositoryImpl constructor(
kdf = userStateJson.activeAccount.profile.toSdkParams(), kdf = userStateJson.activeAccount.profile.toSdkParams(),
userKey = loginResponse.key, userKey = loginResponse.key,
privateKey = loginResponse.privateKey, privateKey = loginResponse.privateKey,
// TODO use actual organization keys BIT-1091
organizationalKeys = emptyMap(),
masterPassword = password, masterPassword = password,
// We can separately unlock the vault for organization data after
// receiving the sync response.
organizationKeys = null,
) )
authDiskSource.userState = userStateJson authDiskSource.userState = userStateJson
authDiskSource.storeUserKey( authDiskSource.storeUserKey(

View file

@ -7,6 +7,7 @@ import com.bitwarden.core.Collection
import com.bitwarden.core.CollectionView import com.bitwarden.core.CollectionView
import com.bitwarden.core.Folder import com.bitwarden.core.Folder
import com.bitwarden.core.FolderView import com.bitwarden.core.FolderView
import com.bitwarden.core.InitOrgCryptoRequest
import com.bitwarden.core.InitUserCryptoRequest import com.bitwarden.core.InitUserCryptoRequest
import com.bitwarden.core.Send import com.bitwarden.core.Send
import com.bitwarden.core.SendView import com.bitwarden.core.SendView
@ -19,11 +20,21 @@ import com.x8bit.bitwarden.data.vault.datasource.sdk.model.InitializeCryptoResul
interface VaultSdkSource { interface VaultSdkSource {
/** /**
* Attempts to initialize cryptography functionality for the Bitwarden SDK * Attempts to initialize cryptography functionality for an individual user for the
* with a given [InitCryptoRequest]. * Bitwarden SDK with a given [InitUserCryptoRequest].
*/ */
suspend fun initializeCrypto(request: InitUserCryptoRequest): Result<InitializeCryptoResult> suspend fun initializeCrypto(request: InitUserCryptoRequest): Result<InitializeCryptoResult>
/**
* Attempts to initialize cryptography functionality for organization data associated with
* the current user for the Bitwarden SDK with a given [InitOrgCryptoRequest].
*
* This should only be called after a successful call to [initializeCrypto].
*/
suspend fun initializeOrganizationCrypto(
request: InitOrgCryptoRequest,
): Result<InitializeCryptoResult>
/** /**
* Encrypts a [CipherView] returning a [Cipher] wrapped in a [Result]. * Encrypts a [CipherView] returning a [Cipher] wrapped in a [Result].
*/ */

View file

@ -7,6 +7,7 @@ import com.bitwarden.core.Collection
import com.bitwarden.core.CollectionView import com.bitwarden.core.CollectionView
import com.bitwarden.core.Folder import com.bitwarden.core.Folder
import com.bitwarden.core.FolderView import com.bitwarden.core.FolderView
import com.bitwarden.core.InitOrgCryptoRequest
import com.bitwarden.core.InitUserCryptoRequest import com.bitwarden.core.InitUserCryptoRequest
import com.bitwarden.core.Send import com.bitwarden.core.Send
import com.bitwarden.core.SendView import com.bitwarden.core.SendView
@ -32,7 +33,20 @@ class VaultSdkSourceImpl(
clientCrypto.initializeUserCrypto(req = request) clientCrypto.initializeUserCrypto(req = request)
InitializeCryptoResult.Success InitializeCryptoResult.Success
} catch (exception: BitwardenException) { } catch (exception: BitwardenException) {
// The only truly expected error from the SDK is an incorrect password. // The only truly expected error from the SDK is an incorrect key/password.
InitializeCryptoResult.AuthenticationError
}
}
override suspend fun initializeOrganizationCrypto(
request: InitOrgCryptoRequest,
): Result<InitializeCryptoResult> =
runCatching {
try {
clientCrypto.initializeOrgCrypto(req = request)
InitializeCryptoResult.Success
} catch (exception: BitwardenException) {
// The only truly expected error from the SDK is for incorrect keys.
InitializeCryptoResult.AuthenticationError InitializeCryptoResult.AuthenticationError
} }
} }

View file

@ -11,7 +11,7 @@ sealed class InitializeCryptoResult {
data object Success : InitializeCryptoResult() data object Success : InitializeCryptoResult()
/** /**
* Incorrect password provided. * Incorrect password or key(s) provided.
*/ */
data object AuthenticationError : InitializeCryptoResult() data object AuthenticationError : InitializeCryptoResult()
} }

View file

@ -71,6 +71,9 @@ interface VaultRepository {
/** /**
* Attempt to unlock the vault with the specified user information. * Attempt to unlock the vault with the specified user information.
*
* Note that when [organizationKeys] is absent, no attempt will be made to unlock the vault
* for organization data.
*/ */
@Suppress("LongParameterList") @Suppress("LongParameterList")
suspend fun unlockVault( suspend fun unlockVault(
@ -80,7 +83,7 @@ interface VaultRepository {
kdf: Kdf, kdf: Kdf,
userKey: String, userKey: String,
privateKey: String, privateKey: String,
organizationalKeys: Map<String, String>, organizationKeys: Map<String, String>?,
): VaultUnlockResult ): VaultUnlockResult
/** /**

View file

@ -2,6 +2,7 @@ package com.x8bit.bitwarden.data.vault.repository
import com.bitwarden.core.CipherView import com.bitwarden.core.CipherView
import com.bitwarden.core.FolderView import com.bitwarden.core.FolderView
import com.bitwarden.core.InitOrgCryptoRequest
import com.bitwarden.core.InitUserCryptoMethod import com.bitwarden.core.InitUserCryptoMethod
import com.bitwarden.core.InitUserCryptoRequest import com.bitwarden.core.InitUserCryptoRequest
import com.bitwarden.core.Kdf import com.bitwarden.core.Kdf
@ -12,11 +13,13 @@ import com.x8bit.bitwarden.data.platform.datasource.network.util.isNoConnectionE
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
import com.x8bit.bitwarden.data.platform.repository.model.DataState import com.x8bit.bitwarden.data.platform.repository.model.DataState
import com.x8bit.bitwarden.data.platform.repository.util.map import com.x8bit.bitwarden.data.platform.repository.util.map
import com.x8bit.bitwarden.data.platform.util.asSuccess
import com.x8bit.bitwarden.data.platform.util.flatMap import com.x8bit.bitwarden.data.platform.util.flatMap
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
import com.x8bit.bitwarden.data.vault.datasource.network.service.CiphersService import com.x8bit.bitwarden.data.vault.datasource.network.service.CiphersService
import com.x8bit.bitwarden.data.vault.datasource.network.service.SyncService import com.x8bit.bitwarden.data.vault.datasource.network.service.SyncService
import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource 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.CreateCipherResult import com.x8bit.bitwarden.data.vault.repository.model.CreateCipherResult
import com.x8bit.bitwarden.data.vault.repository.model.SendData import com.x8bit.bitwarden.data.vault.repository.model.SendData
import com.x8bit.bitwarden.data.vault.repository.model.UpdateCipherResult import com.x8bit.bitwarden.data.vault.repository.model.UpdateCipherResult
@ -107,6 +110,7 @@ class VaultRepositoryImpl constructor(
syncResponse = syncResponse, syncResponse = syncResponse,
) )
unlockVaultForOrganizationsIfNecessary(syncResponse = syncResponse)
storeKeys(syncResponse = syncResponse) storeKeys(syncResponse = syncResponse)
decryptSyncResponseAndUpdateVaultDataState(syncResponse = syncResponse) decryptSyncResponseAndUpdateVaultDataState(syncResponse = syncResponse)
decryptSendsAndUpdateSendDataState(sendList = syncResponse.sends) decryptSendsAndUpdateSendDataState(sendList = syncResponse.sends)
@ -177,6 +181,8 @@ class VaultRepositoryImpl constructor(
?: return VaultUnlockResult.InvalidStateError ?: return VaultUnlockResult.InvalidStateError
val privateKey = authDiskSource.getPrivateKey(userId = userState.activeUserId) val privateKey = authDiskSource.getPrivateKey(userId = userState.activeUserId)
?: return VaultUnlockResult.InvalidStateError ?: return VaultUnlockResult.InvalidStateError
val organizationKeys = authDiskSource
.getOrganizationKeys(userId = userState.activeUserId)
return unlockVault( return unlockVault(
userId = userState.activeUserId, userId = userState.activeUserId,
masterPassword = masterPassword, masterPassword = masterPassword,
@ -184,8 +190,7 @@ class VaultRepositoryImpl constructor(
kdf = userState.activeAccount.profile.toSdkParams(), kdf = userState.activeAccount.profile.toSdkParams(),
userKey = userKey, userKey = userKey,
privateKey = privateKey, privateKey = privateKey,
// TODO use actual organization keys BIT-1091 organizationKeys = organizationKeys,
organizationalKeys = emptyMap(),
) )
.also { .also {
if (it is VaultUnlockResult.Success) { if (it is VaultUnlockResult.Success) {
@ -201,7 +206,7 @@ class VaultRepositoryImpl constructor(
kdf: Kdf, kdf: Kdf,
userKey: String, userKey: String,
privateKey: String, privateKey: String,
organizationalKeys: Map<String, String>, organizationKeys: Map<String, String>?,
): VaultUnlockResult = ): VaultUnlockResult =
flow { flow {
willSyncAfterUnlock = true willSyncAfterUnlock = true
@ -218,6 +223,20 @@ class VaultRepositoryImpl constructor(
), ),
), ),
) )
.flatMap { result ->
// Initialize the SDK for organizations if necessary
if (organizationKeys != null &&
result is InitializeCryptoResult.Success
) {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = organizationKeys,
),
)
} else {
result.asSuccess()
}
}
.fold( .fold(
onFailure = { VaultUnlockResult.GenericError }, onFailure = { VaultUnlockResult.GenericError },
onSuccess = { initializeCryptoResult -> onSuccess = { initializeCryptoResult ->
@ -320,6 +339,27 @@ class VaultRepositoryImpl constructor(
} }
} }
private suspend fun unlockVaultForOrganizationsIfNecessary(
syncResponse: SyncResponseJson,
) {
val profile = syncResponse.profile ?: return
val organizationKeys = profile.organizations
.orEmpty()
.filter { it.key != null }
.associate { it.id to requireNotNull(it.key) }
.takeUnless { it.isEmpty() }
?: return
// There shouldn't be issues when unlocking directly from the syncResponse so we can ignore
// the return type here.
vaultSdkSource
.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = organizationKeys,
),
)
}
private suspend fun decryptSendsAndUpdateSendDataState(sendList: List<SyncResponseJson.Send>?) { private suspend fun decryptSendsAndUpdateSendDataState(sendList: List<SyncResponseJson.Send>?) {
val newState = vaultSdkSource val newState = vaultSdkSource
.decryptSendList( .decryptSendList(

View file

@ -429,7 +429,7 @@ class AuthRepositoryTest {
kdf = ACCOUNT_1.profile.toSdkParams(), kdf = ACCOUNT_1.profile.toSdkParams(),
userKey = successResponse.key, userKey = successResponse.key,
privateKey = successResponse.privateKey, privateKey = successResponse.privateKey,
organizationalKeys = emptyMap(), organizationKeys = null,
masterPassword = PASSWORD, masterPassword = PASSWORD,
) )
} returns VaultUnlockResult.Success } returns VaultUnlockResult.Success
@ -465,7 +465,7 @@ class AuthRepositoryTest {
kdf = ACCOUNT_1.profile.toSdkParams(), kdf = ACCOUNT_1.profile.toSdkParams(),
userKey = successResponse.key, userKey = successResponse.key,
privateKey = successResponse.privateKey, privateKey = successResponse.privateKey,
organizationalKeys = emptyMap(), organizationKeys = null,
masterPassword = PASSWORD, masterPassword = PASSWORD,
) )
vaultRepository.sync() vaultRepository.sync()
@ -508,7 +508,7 @@ class AuthRepositoryTest {
kdf = ACCOUNT_1.profile.toSdkParams(), kdf = ACCOUNT_1.profile.toSdkParams(),
userKey = successResponse.key, userKey = successResponse.key,
privateKey = successResponse.privateKey, privateKey = successResponse.privateKey,
organizationalKeys = emptyMap(), organizationKeys = null,
masterPassword = PASSWORD, masterPassword = PASSWORD,
) )
} returns VaultUnlockResult.Success } returns VaultUnlockResult.Success
@ -546,7 +546,7 @@ class AuthRepositoryTest {
kdf = ACCOUNT_1.profile.toSdkParams(), kdf = ACCOUNT_1.profile.toSdkParams(),
userKey = successResponse.key, userKey = successResponse.key,
privateKey = successResponse.privateKey, privateKey = successResponse.privateKey,
organizationalKeys = emptyMap(), organizationKeys = null,
masterPassword = PASSWORD, masterPassword = PASSWORD,
) )
vaultRepository.sync() vaultRepository.sync()
@ -946,7 +946,7 @@ class AuthRepositoryTest {
kdf = ACCOUNT_1.profile.toSdkParams(), kdf = ACCOUNT_1.profile.toSdkParams(),
userKey = successResponse.key, userKey = successResponse.key,
privateKey = successResponse.privateKey, privateKey = successResponse.privateKey,
organizationalKeys = emptyMap(), organizationKeys = null,
masterPassword = PASSWORD, masterPassword = PASSWORD,
) )
} returns VaultUnlockResult.Success } returns VaultUnlockResult.Success
@ -1028,7 +1028,7 @@ class AuthRepositoryTest {
kdf = ACCOUNT_1.profile.toSdkParams(), kdf = ACCOUNT_1.profile.toSdkParams(),
userKey = successResponse.key, userKey = successResponse.key,
privateKey = successResponse.privateKey, privateKey = successResponse.privateKey,
organizationalKeys = emptyMap(), organizationKeys = null,
masterPassword = PASSWORD, masterPassword = PASSWORD,
) )
} returns VaultUnlockResult.Success } returns VaultUnlockResult.Success

View file

@ -77,6 +77,13 @@ fun createMockOrganization(number: Int): SyncResponseJson.Profile.Organization =
status = 1, status = 1,
) )
/**
* Create a mock set of organization keys with the given [number].
*/
fun createMockOrganizationKeys(number: Int): Map<String, String> =
createMockOrganization(number = number)
.let { mapOf(it.id to requireNotNull(it.key)) }
/** /**
* Create a mock [SyncResponseJson.Profile.Permissions]. * Create a mock [SyncResponseJson.Profile.Permissions].
*/ */

View file

@ -7,6 +7,7 @@ import com.bitwarden.core.Collection
import com.bitwarden.core.CollectionView import com.bitwarden.core.CollectionView
import com.bitwarden.core.Folder import com.bitwarden.core.Folder
import com.bitwarden.core.FolderView import com.bitwarden.core.FolderView
import com.bitwarden.core.InitOrgCryptoRequest
import com.bitwarden.core.InitUserCryptoRequest import com.bitwarden.core.InitUserCryptoRequest
import com.bitwarden.core.Send import com.bitwarden.core.Send
import com.bitwarden.core.SendView import com.bitwarden.core.SendView
@ -32,7 +33,7 @@ class VaultSdkSourceTest {
) )
@Test @Test
fun `initializeCrypto with sdk success should return InitializeCryptoResult Success`() = fun `initializeUserCrypto with sdk success should return InitializeCryptoResult Success`() =
runBlocking { runBlocking {
val mockInitCryptoRequest = mockk<InitUserCryptoRequest>() val mockInitCryptoRequest = mockk<InitUserCryptoRequest>()
coEvery { coEvery {
@ -101,6 +102,76 @@ class VaultSdkSourceTest {
} }
} }
@Test
fun `initializeOrgCrypto with sdk success should return InitializeCryptoResult Success`() =
runBlocking {
val mockInitCryptoRequest = mockk<InitOrgCryptoRequest>()
coEvery {
clientCrypto.initializeOrgCrypto(
req = mockInitCryptoRequest,
)
} returns Unit
val result = vaultSdkSource.initializeOrganizationCrypto(
request = mockInitCryptoRequest,
)
assertEquals(
InitializeCryptoResult.Success.asSuccess(),
result,
)
coVerify {
clientCrypto.initializeOrgCrypto(
req = mockInitCryptoRequest,
)
}
}
@Test
fun `initializeOrgCrypto with sdk failure should return failure`() = runBlocking {
val mockInitCryptoRequest = mockk<InitOrgCryptoRequest>()
val expectedException = IllegalStateException("mock")
coEvery {
clientCrypto.initializeOrgCrypto(
req = mockInitCryptoRequest,
)
} throws expectedException
val result = vaultSdkSource.initializeOrganizationCrypto(
request = mockInitCryptoRequest,
)
assertEquals(
expectedException.asFailure(),
result,
)
coVerify {
clientCrypto.initializeOrgCrypto(
req = mockInitCryptoRequest,
)
}
}
@Test
fun `initializeOrgCrypto with BitwardenException failure should return AuthenticationError`() =
runBlocking {
val mockInitCryptoRequest = mockk<InitOrgCryptoRequest>()
val expectedException = BitwardenException.E(message = "")
coEvery {
clientCrypto.initializeOrgCrypto(
req = mockInitCryptoRequest,
)
} throws expectedException
val result = vaultSdkSource.initializeOrganizationCrypto(
request = mockInitCryptoRequest,
)
assertEquals(
InitializeCryptoResult.AuthenticationError.asSuccess(),
result,
)
coVerify {
clientCrypto.initializeOrgCrypto(
req = mockInitCryptoRequest,
)
}
}
@Test @Test
fun `decryptCipher should call SDK and return a Result with correct data`() = runBlocking { fun `decryptCipher should call SDK and return a Result with correct data`() = runBlocking {
val mockCipher = mockk<CipherView>() val mockCipher = mockk<CipherView>()

View file

@ -3,6 +3,7 @@ package com.x8bit.bitwarden.data.vault.repository
import app.cash.turbine.test import app.cash.turbine.test
import com.bitwarden.core.CipherView import com.bitwarden.core.CipherView
import com.bitwarden.core.FolderView import com.bitwarden.core.FolderView
import com.bitwarden.core.InitOrgCryptoRequest
import com.bitwarden.core.InitUserCryptoMethod import com.bitwarden.core.InitUserCryptoMethod
import com.bitwarden.core.InitUserCryptoRequest import com.bitwarden.core.InitUserCryptoRequest
import com.bitwarden.core.Kdf import com.bitwarden.core.Kdf
@ -18,6 +19,7 @@ import com.x8bit.bitwarden.data.platform.util.asFailure
import com.x8bit.bitwarden.data.platform.util.asSuccess import com.x8bit.bitwarden.data.platform.util.asSuccess
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockCipher import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockCipher
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockCipherJsonRequest import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockCipherJsonRequest
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockOrganizationKeys
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockSyncResponse import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockSyncResponse
import com.x8bit.bitwarden.data.vault.datasource.network.service.CiphersService import com.x8bit.bitwarden.data.vault.datasource.network.service.CiphersService
import com.x8bit.bitwarden.data.vault.datasource.network.service.SyncService import com.x8bit.bitwarden.data.vault.datasource.network.service.SyncService
@ -65,12 +67,20 @@ class VaultRepositoryTest {
dispatcherManager = dispatcherManager, dispatcherManager = dispatcherManager,
) )
@Suppress("MaxLineLength")
@Test @Test
fun `sync with syncService Success should update AuthDiskSource and DataStateFlows`() = fun `sync with syncService Success should unlock the vault for orgs if necessary and update AuthDiskSource and DataStateFlows`() =
runTest { runTest {
coEvery { coEvery {
syncService.sync() syncService.sync()
} returns Result.success(createMockSyncResponse(number = 1)) } returns Result.success(createMockSyncResponse(number = 1))
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(1),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery { coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1))) vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1)))
} returns listOf(createMockCipherView(number = 1)).asSuccess() } returns listOf(createMockCipherView(number = 1)).asSuccess()
@ -127,6 +137,13 @@ class VaultRepositoryTest {
), ),
vaultRepository.sendDataStateFlow.value, vaultRepository.sendDataStateFlow.value,
) )
coVerify {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(1),
),
)
}
} }
@Test @Test
@ -135,6 +152,13 @@ class VaultRepositoryTest {
coEvery { coEvery {
syncService.sync() syncService.sync()
} returns Result.success(createMockSyncResponse(number = 1)) } returns Result.success(createMockSyncResponse(number = 1))
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(1),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery { coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1))) vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1)))
} returns listOf(createMockCipherView(number = 1)).asSuccess() } returns listOf(createMockCipherView(number = 1)).asSuccess()
@ -189,6 +213,13 @@ class VaultRepositoryTest {
coEvery { coEvery {
syncService.sync() syncService.sync()
} returns Result.success(createMockSyncResponse(number = 1)) } returns Result.success(createMockSyncResponse(number = 1))
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(1),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery { coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1))) vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1)))
} returns listOf(createMockCipherView(number = 1)).asSuccess() } returns listOf(createMockCipherView(number = 1)).asSuccess()
@ -241,6 +272,13 @@ class VaultRepositoryTest {
coEvery { coEvery {
syncService.sync() syncService.sync()
} returns Result.success(createMockSyncResponse(number = 1)) } returns Result.success(createMockSyncResponse(number = 1))
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(1),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery { coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1))) vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1)))
} returns mockException.asFailure() } returns mockException.asFailure()
@ -267,6 +305,13 @@ class VaultRepositoryTest {
coEvery { coEvery {
syncService.sync() syncService.sync()
} returns Result.success(createMockSyncResponse(number = 1)) } returns Result.success(createMockSyncResponse(number = 1))
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(1),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery { coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1))) vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1)))
} returns listOf(createMockCipherView(number = 1)).asSuccess() } returns listOf(createMockCipherView(number = 1)).asSuccess()
@ -293,6 +338,13 @@ class VaultRepositoryTest {
coEvery { coEvery {
syncService.sync() syncService.sync()
} returns Result.success(createMockSyncResponse(number = 1)) } returns Result.success(createMockSyncResponse(number = 1))
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(1),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery { coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1))) vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1)))
} returns listOf(createMockCipherView(number = 1)).asSuccess() } returns listOf(createMockCipherView(number = 1)).asSuccess()
@ -369,6 +421,13 @@ class VaultRepositoryTest {
coEvery { coEvery {
syncService.sync() syncService.sync()
} returns Result.success(createMockSyncResponse(number = 1)) } returns Result.success(createMockSyncResponse(number = 1))
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(1),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery { coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1))) vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1)))
} returns listOf(createMockCipherView(number = 1)).asSuccess() } returns listOf(createMockCipherView(number = 1)).asSuccess()
@ -429,6 +488,13 @@ class VaultRepositoryTest {
Result.success(createMockSyncResponse(number = 1)), Result.success(createMockSyncResponse(number = 1)),
UnknownHostException().asFailure(), UnknownHostException().asFailure(),
) )
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(1),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery { coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1))) vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1)))
} returns listOf(createMockCipherView(number = 1)).asSuccess() } returns listOf(createMockCipherView(number = 1)).asSuccess()
@ -529,6 +595,13 @@ class VaultRepositoryTest {
coEvery { coEvery {
syncService.sync() syncService.sync()
} returns Result.success(createMockSyncResponse(number = 1)) } returns Result.success(createMockSyncResponse(number = 1))
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(1),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery { coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1))) vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1)))
} returns listOf(createMockCipherView(number = 1)).asSuccess() } returns listOf(createMockCipherView(number = 1)).asSuccess()
@ -546,6 +619,10 @@ class VaultRepositoryTest {
userId = "mockId-1", userId = "mockId-1",
userKey = "mockKey-1", userKey = "mockKey-1",
) )
fakeAuthDiskSource.storeOrganizationKeys(
userId = "mockId-1",
organizationKeys = createMockOrganizationKeys(number = 1),
)
fakeAuthDiskSource.userState = MOCK_USER_STATE fakeAuthDiskSource.userState = MOCK_USER_STATE
coEvery { coEvery {
vaultSdkSource.initializeCrypto( vaultSdkSource.initializeCrypto(
@ -590,6 +667,13 @@ class VaultRepositoryTest {
coEvery { coEvery {
syncService.sync() syncService.sync()
} returns Result.success(createMockSyncResponse(number = 1)) } returns Result.success(createMockSyncResponse(number = 1))
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(1),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery { coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1))) vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1)))
} returns listOf(createMockCipherView(number = 1)).asSuccess() } returns listOf(createMockCipherView(number = 1)).asSuccess()
@ -681,8 +765,9 @@ class VaultRepositoryTest {
coVerify(exactly = 0) { syncService.sync() } coVerify(exactly = 0) { syncService.sync() }
} }
@Suppress("MaxLineLength")
@Test @Test
fun `unlockVaultAndSyncForCurrentUser with unlockVault failure should return GenericError`() = fun `unlockVaultAndSyncForCurrentUser with unlockVault failure for users should return GenericError`() =
runTest { runTest {
coEvery { coEvery {
syncService.sync() syncService.sync()
@ -740,7 +825,77 @@ class VaultRepositoryTest {
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `unlockVaultAndSyncForCurrentUser with unlockVault AuthenticationError should return AuthenticationError`() = fun `unlockVaultAndSyncForCurrentUser with unlockVault failure for orgs should return GenericError`() =
runTest {
coEvery {
syncService.sync()
} returns Result.success(createMockSyncResponse(number = 1))
coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1)))
} returns mockk()
coEvery {
vaultSdkSource.decryptFolderList(listOf(createMockSdkFolder(1)))
} returns mockk()
fakeAuthDiskSource.storePrivateKey(
userId = "mockId-1",
privateKey = "mockPrivateKey-1",
)
fakeAuthDiskSource.storeUserKey(
userId = "mockId-1",
userKey = "mockKey-1",
)
fakeAuthDiskSource.storeOrganizationKeys(
userId = "mockId-1",
organizationKeys = createMockOrganizationKeys(number = 1),
)
fakeAuthDiskSource.userState = MOCK_USER_STATE
coEvery {
vaultSdkSource.initializeCrypto(
request = InitUserCryptoRequest(
kdfParams = Kdf.Pbkdf2(iterations = DEFAULT_PBKDF2_ITERATIONS.toUInt()),
email = "email",
privateKey = "mockPrivateKey-1",
method = InitUserCryptoMethod.Password(
password = "mockPassword-1",
userKey = "mockKey-1",
),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(1),
),
)
} returns IllegalStateException().asFailure()
assertEquals(
VaultState(
unlockedVaultUserIds = emptySet(),
),
vaultRepository.vaultStateFlow.value,
)
val result = vaultRepository.unlockVaultAndSyncForCurrentUser(
masterPassword = "mockPassword-1",
)
assertEquals(
VaultUnlockResult.GenericError,
result,
)
assertEquals(
VaultState(
unlockedVaultUserIds = emptySet(),
),
vaultRepository.vaultStateFlow.value,
)
}
@Suppress("MaxLineLength")
@Test
fun `unlockVaultAndSyncForCurrentUser with unlockVault AuthenticationError for users should return AuthenticationError`() =
runTest { runTest {
coEvery { syncService.sync() } returns Result.success(createMockSyncResponse(number = 1)) coEvery { syncService.sync() } returns Result.success(createMockSyncResponse(number = 1))
coEvery { coEvery {
@ -791,6 +946,70 @@ class VaultRepositoryTest {
) )
} }
@Suppress("MaxLineLength")
@Test
fun `unlockVaultAndSyncForCurrentUser with unlockVault AuthenticationError for orgs should return AuthenticationError`() =
runTest {
coEvery { syncService.sync() } returns Result.success(createMockSyncResponse(number = 1))
coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1)))
} returns mockk()
coEvery {
vaultSdkSource.decryptFolderList(listOf(createMockSdkFolder(1)))
} returns mockk()
fakeAuthDiskSource.storePrivateKey(
userId = "mockId-1",
privateKey = "mockPrivateKey-1",
)
fakeAuthDiskSource.storeUserKey(
userId = "mockId-1",
userKey = "mockKey-1",
)
fakeAuthDiskSource.storeOrganizationKeys(
userId = "mockId-1",
organizationKeys = createMockOrganizationKeys(number = 1),
)
fakeAuthDiskSource.userState = MOCK_USER_STATE
coEvery {
vaultSdkSource.initializeCrypto(
request = InitUserCryptoRequest(
kdfParams = Kdf.Pbkdf2(iterations = DEFAULT_PBKDF2_ITERATIONS.toUInt()),
email = "email",
privateKey = "mockPrivateKey-1",
method = InitUserCryptoMethod.Password(
password = "",
userKey = "mockKey-1",
),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(1),
),
)
} returns InitializeCryptoResult.AuthenticationError.asSuccess()
assertEquals(
VaultState(
unlockedVaultUserIds = emptySet(),
),
vaultRepository.vaultStateFlow.value,
)
val result = vaultRepository.unlockVaultAndSyncForCurrentUser(masterPassword = "")
assertEquals(
VaultUnlockResult.AuthenticationError,
result,
)
assertEquals(
VaultState(
unlockedVaultUserIds = emptySet(),
),
vaultRepository.vaultStateFlow.value,
)
}
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `unlockVaultAndSyncForCurrentUser with missing user state should return InvalidStateError `() = fun `unlockVaultAndSyncForCurrentUser with missing user state should return InvalidStateError `() =
@ -890,7 +1109,7 @@ class VaultRepositoryTest {
val masterPassword = "drowssap" val masterPassword = "drowssap"
val userKey = "12345" val userKey = "12345"
val privateKey = "54321" val privateKey = "54321"
val organizationalKeys = emptyMap<String, String>() val organizationKeys = mapOf("orgId1" to "orgKey1")
coEvery { coEvery {
vaultSdkSource.initializeCrypto( vaultSdkSource.initializeCrypto(
request = InitUserCryptoRequest( request = InitUserCryptoRequest(
@ -904,6 +1123,11 @@ class VaultRepositoryTest {
), ),
) )
} returns InitializeCryptoResult.Success.asSuccess() } returns InitializeCryptoResult.Success.asSuccess()
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(organizationKeys = organizationKeys),
)
} returns InitializeCryptoResult.Success.asSuccess()
assertEquals( assertEquals(
VaultState( VaultState(
unlockedVaultUserIds = emptySet(), unlockedVaultUserIds = emptySet(),
@ -918,7 +1142,7 @@ class VaultRepositoryTest {
email = email, email = email,
userKey = userKey, userKey = userKey,
privateKey = privateKey, privateKey = privateKey,
organizationalKeys = organizationalKeys, organizationKeys = organizationKeys,
) )
assertEquals(VaultUnlockResult.Success, result) assertEquals(VaultUnlockResult.Success, result)
@ -941,11 +1165,16 @@ class VaultRepositoryTest {
), ),
) )
} }
coVerify(exactly = 1) {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(organizationKeys = organizationKeys),
)
}
} }
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `unlockVault with initializeCrypto authentication failure should return AuthenticationError`() = fun `unlockVault with initializeCrypto authentication failure for users should return AuthenticationError`() =
runTest { runTest {
val userId = "userId" val userId = "userId"
val kdf = MOCK_PROFILE.toSdkParams() val kdf = MOCK_PROFILE.toSdkParams()
@ -953,7 +1182,7 @@ class VaultRepositoryTest {
val masterPassword = "drowssap" val masterPassword = "drowssap"
val userKey = "12345" val userKey = "12345"
val privateKey = "54321" val privateKey = "54321"
val organizationalKeys = emptyMap<String, String>() val organizationKeys = mapOf("orgId1" to "orgKey1")
coEvery { coEvery {
vaultSdkSource.initializeCrypto( vaultSdkSource.initializeCrypto(
request = InitUserCryptoRequest( request = InitUserCryptoRequest(
@ -967,6 +1196,7 @@ class VaultRepositoryTest {
), ),
) )
} returns InitializeCryptoResult.AuthenticationError.asSuccess() } returns InitializeCryptoResult.AuthenticationError.asSuccess()
assertEquals( assertEquals(
VaultState( VaultState(
unlockedVaultUserIds = emptySet(), unlockedVaultUserIds = emptySet(),
@ -981,7 +1211,7 @@ class VaultRepositoryTest {
email = email, email = email,
userKey = userKey, userKey = userKey,
privateKey = privateKey, privateKey = privateKey,
organizationalKeys = organizationalKeys, organizationKeys = organizationKeys,
) )
assertEquals(VaultUnlockResult.AuthenticationError, result) assertEquals(VaultUnlockResult.AuthenticationError, result)
@ -1006,66 +1236,213 @@ class VaultRepositoryTest {
} }
} }
@Suppress("MaxLineLength")
@Test @Test
fun `unlockVault with initializeCrypto failure should return GenericError`() = runTest { fun `unlockVault with initializeCrypto authentication failure for orgs should return AuthenticationError`() =
val userId = "userId" runTest {
val kdf = MOCK_PROFILE.toSdkParams() val userId = "userId"
val email = MOCK_PROFILE.email val kdf = MOCK_PROFILE.toSdkParams()
val masterPassword = "drowssap" val email = MOCK_PROFILE.email
val userKey = "12345" val masterPassword = "drowssap"
val privateKey = "54321" val userKey = "12345"
val organizationalKeys = emptyMap<String, String>() val privateKey = "54321"
coEvery { val organizationKeys = mapOf("orgId1" to "orgKey1")
vaultSdkSource.initializeCrypto( coEvery {
request = InitUserCryptoRequest( vaultSdkSource.initializeCrypto(
kdfParams = kdf, request = InitUserCryptoRequest(
email = email, kdfParams = kdf,
privateKey = privateKey, email = email,
method = InitUserCryptoMethod.Password( privateKey = privateKey,
password = masterPassword, method = InitUserCryptoMethod.Password(
userKey = userKey, password = masterPassword,
userKey = userKey,
),
), ),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(organizationKeys = organizationKeys),
)
} returns InitializeCryptoResult.AuthenticationError.asSuccess()
assertEquals(
VaultState(
unlockedVaultUserIds = emptySet(),
), ),
vaultRepository.vaultStateFlow.value,
) )
} returns Throwable("Fail").asFailure()
assertEquals(
VaultState(
unlockedVaultUserIds = emptySet(),
),
vaultRepository.vaultStateFlow.value,
)
val result = vaultRepository.unlockVault( val result = vaultRepository.unlockVault(
userId = userId, userId = userId,
masterPassword = masterPassword, masterPassword = masterPassword,
kdf = kdf, kdf = kdf,
email = email, email = email,
userKey = userKey, userKey = userKey,
privateKey = privateKey, privateKey = privateKey,
organizationalKeys = organizationalKeys, organizationKeys = organizationKeys,
) )
assertEquals(VaultUnlockResult.GenericError, result) assertEquals(VaultUnlockResult.AuthenticationError, result)
assertEquals( assertEquals(
VaultState( VaultState(
unlockedVaultUserIds = emptySet(), unlockedVaultUserIds = emptySet(),
), ),
vaultRepository.vaultStateFlow.value, vaultRepository.vaultStateFlow.value,
) )
coVerify(exactly = 1) { coVerify(exactly = 1) {
vaultSdkSource.initializeCrypto( vaultSdkSource.initializeCrypto(
request = InitUserCryptoRequest( request = InitUserCryptoRequest(
kdfParams = kdf, kdfParams = kdf,
email = email, email = email,
privateKey = privateKey, privateKey = privateKey,
method = InitUserCryptoMethod.Password( method = InitUserCryptoMethod.Password(
password = masterPassword, password = masterPassword,
userKey = userKey, userKey = userKey,
),
), ),
), )
) }
coVerify(exactly = 1) {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(organizationKeys = organizationKeys),
)
}
}
@Test
fun `unlockVault with initializeCrypto failure for users should return GenericError`() =
runTest {
val userId = "userId"
val kdf = MOCK_PROFILE.toSdkParams()
val email = MOCK_PROFILE.email
val masterPassword = "drowssap"
val userKey = "12345"
val privateKey = "54321"
val organizationKeys = mapOf("orgId1" to "orgKey1")
coEvery {
vaultSdkSource.initializeCrypto(
request = InitUserCryptoRequest(
kdfParams = kdf,
email = email,
privateKey = privateKey,
method = InitUserCryptoMethod.Password(
password = masterPassword,
userKey = userKey,
),
),
)
} returns Throwable("Fail").asFailure()
assertEquals(
VaultState(
unlockedVaultUserIds = emptySet(),
),
vaultRepository.vaultStateFlow.value,
)
val result = vaultRepository.unlockVault(
userId = userId,
masterPassword = masterPassword,
kdf = kdf,
email = email,
userKey = userKey,
privateKey = privateKey,
organizationKeys = organizationKeys,
)
assertEquals(VaultUnlockResult.GenericError, result)
assertEquals(
VaultState(
unlockedVaultUserIds = emptySet(),
),
vaultRepository.vaultStateFlow.value,
)
coVerify(exactly = 1) {
vaultSdkSource.initializeCrypto(
request = InitUserCryptoRequest(
kdfParams = kdf,
email = email,
privateKey = privateKey,
method = InitUserCryptoMethod.Password(
password = masterPassword,
userKey = userKey,
),
),
)
}
}
@Test
fun `unlockVault with initializeCrypto failure for orgs should return GenericError`() =
runTest {
val userId = "userId"
val kdf = MOCK_PROFILE.toSdkParams()
val email = MOCK_PROFILE.email
val masterPassword = "drowssap"
val userKey = "12345"
val privateKey = "54321"
val organizationKeys = mapOf("orgId1" to "orgKey1")
coEvery {
vaultSdkSource.initializeCrypto(
request = InitUserCryptoRequest(
kdfParams = kdf,
email = email,
privateKey = privateKey,
method = InitUserCryptoMethod.Password(
password = masterPassword,
userKey = userKey,
),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(organizationKeys = organizationKeys),
)
} returns Throwable("Fail").asFailure()
assertEquals(
VaultState(
unlockedVaultUserIds = emptySet(),
),
vaultRepository.vaultStateFlow.value,
)
val result = vaultRepository.unlockVault(
userId = userId,
masterPassword = masterPassword,
kdf = kdf,
email = email,
userKey = userKey,
privateKey = privateKey,
organizationKeys = organizationKeys,
)
assertEquals(VaultUnlockResult.GenericError, result)
assertEquals(
VaultState(
unlockedVaultUserIds = emptySet(),
),
vaultRepository.vaultStateFlow.value,
)
coVerify(exactly = 1) {
vaultSdkSource.initializeCrypto(
request = InitUserCryptoRequest(
kdfParams = kdf,
email = email,
privateKey = privateKey,
method = InitUserCryptoMethod.Password(
password = masterPassword,
userKey = userKey,
),
),
)
}
coVerify(exactly = 1) {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(organizationKeys = organizationKeys),
)
}
} }
}
@Test @Test
fun `unlockVault with initializeCrypto awaiting should block calls to sync`() = runTest { fun `unlockVault with initializeCrypto awaiting should block calls to sync`() = runTest {
@ -1075,7 +1452,7 @@ class VaultRepositoryTest {
val masterPassword = "drowssap" val masterPassword = "drowssap"
val userKey = "12345" val userKey = "12345"
val privateKey = "54321" val privateKey = "54321"
val organizationalKeys = emptyMap<String, String>() val organizationKeys = null
coEvery { coEvery {
vaultSdkSource.initializeCrypto( vaultSdkSource.initializeCrypto(
request = InitUserCryptoRequest( request = InitUserCryptoRequest(
@ -1099,7 +1476,7 @@ class VaultRepositoryTest {
email = email, email = email,
userKey = userKey, userKey = userKey,
privateKey = privateKey, privateKey = privateKey,
organizationalKeys = organizationalKeys, organizationKeys = organizationKeys,
) )
} }
// Does nothing because we are blocking // Does nothing because we are blocking
@ -1128,6 +1505,13 @@ class VaultRepositoryTest {
coEvery { coEvery {
syncService.sync() syncService.sync()
} returns Result.success(createMockSyncResponse(number = 1)) } returns Result.success(createMockSyncResponse(number = 1))
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(1),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery { coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1))) vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1)))
} returns listOf(createMockCipherView(number = 1)).asSuccess() } returns listOf(createMockCipherView(number = 1)).asSuccess()
@ -1170,6 +1554,13 @@ class VaultRepositoryTest {
coEvery { coEvery {
syncService.sync() syncService.sync()
} returns Result.success(createMockSyncResponse(number = 1)) } returns Result.success(createMockSyncResponse(number = 1))
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(1),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery { coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1))) vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1)))
} returns listOf(createMockCipherView(number = 1)).asSuccess() } returns listOf(createMockCipherView(number = 1)).asSuccess()
@ -1213,6 +1604,13 @@ class VaultRepositoryTest {
coEvery { coEvery {
syncService.sync() syncService.sync()
} returns Result.success(createMockSyncResponse(itemId)) } returns Result.success(createMockSyncResponse(itemId))
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(itemId),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery { coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(itemId))) vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(itemId)))
} returns listOf(item).asSuccess() } returns listOf(item).asSuccess()
@ -1287,6 +1685,13 @@ class VaultRepositoryTest {
coEvery { coEvery {
syncService.sync() syncService.sync()
} returns Result.success(createMockSyncResponse(1)) } returns Result.success(createMockSyncResponse(1))
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(1),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery { coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1))) vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1)))
} returns listOf(createMockCipherView(1)).asSuccess() } returns listOf(createMockCipherView(1)).asSuccess()
@ -1319,6 +1724,13 @@ class VaultRepositoryTest {
coEvery { coEvery {
syncService.sync() syncService.sync()
} returns Result.success(createMockSyncResponse(folderId)) } returns Result.success(createMockSyncResponse(folderId))
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(folderId),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery { coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(folderId))) vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(folderId)))
} returns listOf(createMockCipherView(folderId)).asSuccess() } returns listOf(createMockCipherView(folderId)).asSuccess()
@ -1393,6 +1805,13 @@ class VaultRepositoryTest {
coEvery { coEvery {
syncService.sync() syncService.sync()
} returns Result.success(createMockSyncResponse(1)) } returns Result.success(createMockSyncResponse(1))
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(1),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery { coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1))) vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1)))
} returns listOf(createMockCipherView(1)).asSuccess() } returns listOf(createMockCipherView(1)).asSuccess()
@ -1471,6 +1890,13 @@ class VaultRepositoryTest {
coEvery { coEvery {
syncService.sync() syncService.sync()
} returns Result.success(createMockSyncResponse(1)) } returns Result.success(createMockSyncResponse(1))
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(1),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery { coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1))) vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1)))
} returns listOf(createMockCipherView(1)).asSuccess() } returns listOf(createMockCipherView(1)).asSuccess()
@ -1548,6 +1974,13 @@ class VaultRepositoryTest {
coEvery { coEvery {
syncService.sync() syncService.sync()
} returns Result.success(createMockSyncResponse(1)) } returns Result.success(createMockSyncResponse(1))
coEvery {
vaultSdkSource.initializeOrganizationCrypto(
request = InitOrgCryptoRequest(
organizationKeys = createMockOrganizationKeys(1),
),
)
} returns InitializeCryptoResult.Success.asSuccess()
coEvery { coEvery {
vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1))) vaultSdkSource.decryptCipherList(listOf(createMockSdkCipher(1)))
} returns listOf(createMockCipherView(1)).asSuccess() } returns listOf(createMockCipherView(1)).asSuccess()
@ -1577,7 +2010,7 @@ class VaultRepositoryTest {
val masterPassword = "drowssap" val masterPassword = "drowssap"
val userKey = "12345" val userKey = "12345"
val privateKey = "54321" val privateKey = "54321"
val organizationalKeys = emptyMap<String, String>() val organizationKeys = null
coEvery { coEvery {
vaultSdkSource.initializeCrypto( vaultSdkSource.initializeCrypto(
request = InitUserCryptoRequest( request = InitUserCryptoRequest(
@ -1599,7 +2032,7 @@ class VaultRepositoryTest {
email = email, email = email,
userKey = userKey, userKey = userKey,
privateKey = privateKey, privateKey = privateKey,
organizationalKeys = organizationalKeys, organizationKeys = organizationKeys,
) )
assertEquals(VaultUnlockResult.Success, result) assertEquals(VaultUnlockResult.Success, result)