[PM-21782] Pass encryptedFor to cipher functions (#5297)

This commit is contained in:
Patrick Honkonen authored and GitHub committed 2025-06-03 16:34:46 +00:00
1 parent 0934d47159
commit 0892e0ff1f
20 files changed
+372 -137

No files matched your search

@@ -22,6 +22,7 @@ import com.bitwarden.vault.CipherListView
import com.bitwarden.vault.CipherView
import com.bitwarden.vault.Collection
import com.bitwarden.vault.CollectionView
import com.bitwarden.vault.EncryptionContext
import com.bitwarden.vault.Folder
import com.bitwarden.vault.FolderView
import com.bitwarden.vault.PasswordHistory
@@ -187,7 +188,7 @@ interface VaultSdkSource {
suspend fun encryptCipher(
userId: String,
cipherView: CipherView,
): Result<Cipher>
): Result<EncryptionContext>
/**
* Decrypts a [Cipher] for the user with the given [userId], returning a [CipherView] wrapped
@@ -349,13 +350,13 @@ interface VaultSdkSource {
): Result<List<FolderView>>
/**
* Decrypts a [cipher] [attachment] file found at [encryptedFilePath] saving it at
* Decrypts a [cipher] [attachmentView] file found at [encryptedFilePath] saving it at
* [decryptedFilePath] for the user with the given [userId]
*/
suspend fun decryptFile(
userId: String,
cipher: Cipher,
attachment: Attachment,
attachmentView: AttachmentView,
encryptedFilePath: String,
decryptedFilePath: String,
): Result<Unit>
@@ -25,6 +25,7 @@ import com.bitwarden.vault.CipherListView
import com.bitwarden.vault.CipherView
import com.bitwarden.vault.Collection
import com.bitwarden.vault.CollectionView
import com.bitwarden.vault.EncryptionContext
import com.bitwarden.vault.Folder
import com.bitwarden.vault.FolderView
import com.bitwarden.vault.PasswordHistory
@@ -269,7 +270,7 @@ class VaultSdkSourceImpl(
override suspend fun encryptCipher(
userId: String,
cipherView: CipherView,
): Result<Cipher> =
): Result<EncryptionContext> =
runCatchingWithLogs {
getClient(userId = userId)
.vault()
@@ -389,7 +390,7 @@ class VaultSdkSourceImpl(
override suspend fun decryptFile(
userId: String,
cipher: Cipher,
attachment: Attachment,
attachmentView: AttachmentView,
encryptedFilePath: String,
decryptedFilePath: String,
): Result<Unit> =
@@ -399,7 +400,7 @@ class VaultSdkSourceImpl(
.attachments()
.decryptFile(
cipher = cipher,
attachment = attachment,
attachment = attachmentView,
encryptedFilePath = encryptedFilePath,
decryptedFilePath = decryptedFilePath,
)
@@ -3,9 +3,9 @@ package com.x8bit.bitwarden.data.vault.datasource.sdk.model
import com.bitwarden.annotation.OmitFromCoverage
import com.bitwarden.fido.Fido2CredentialAutofillView
import com.bitwarden.sdk.Fido2CredentialStore
import com.bitwarden.vault.Cipher
import com.bitwarden.vault.CipherListView
import com.bitwarden.vault.CipherView
import com.bitwarden.vault.EncryptionContext
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
import com.x8bit.bitwarden.data.autofill.util.isActiveWithFido2Credentials
import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource
@@ -91,11 +91,12 @@ class Fido2CredentialStoreImpl(
/**
* Save the provided [cred] to the users vault.
*/
override suspend fun saveCredential(cred: Cipher) {
val userId = getActiveUserIdOrThrow()
override suspend fun saveCredential(cred: EncryptionContext) {
vaultSdkSource
.decryptCipher(userId, cred)
.decryptCipher(
userId = cred.encryptedFor,
cipher = cred.cipher,
)
.map { decryptedCipherView ->
decryptedCipherView.id
?.let { vaultRepository.updateCipher(it, decryptedCipherView) }
@@ -12,8 +12,8 @@ import com.bitwarden.network.model.UpdateCipherCollectionsJsonRequest
import com.bitwarden.network.model.UpdateCipherResponseJson
import com.bitwarden.network.service.CiphersService
import com.bitwarden.vault.AttachmentView
import com.bitwarden.vault.Cipher
import com.bitwarden.vault.CipherView
import com.bitwarden.vault.EncryptionContext
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
import com.x8bit.bitwarden.data.platform.error.NoActiveUserException
import com.x8bit.bitwarden.data.platform.manager.ReviewPromptManager
@@ -80,10 +80,10 @@ class CipherManagerImpl(
userId = userId,
cipherView = cipherView,
)
.flatMap { cipher ->
.flatMap {
ciphersService.createCipherInOrganization(
body = CreateCipherInOrganizationJsonRequest(
cipher = cipher.toEncryptedNetworkCipher(),
cipher = it.toEncryptedNetworkCipher(),
collectionIds = collectionIds,
),
)
@@ -123,10 +123,15 @@ class CipherManagerImpl(
?: return DeleteCipherResult.Error(error = NoActiveUserException())
return cipherView
.encryptCipherAndCheckForMigration(userId = userId, cipherId = cipherId)
.flatMap { cipher ->
.flatMap { encryptionContext ->
ciphersService
.softDeleteCipher(cipherId = cipherId)
.flatMap { vaultSdkSource.decryptCipher(userId = userId, cipher = cipher) }
.flatMap {
vaultSdkSource.decryptCipher(
userId = userId,
cipher = encryptionContext.cipher,
)
}
}
.flatMap {
vaultSdkSource.encryptCipher(
@@ -165,7 +170,7 @@ class CipherManagerImpl(
cipherId: String,
attachmentId: String,
cipherView: CipherView,
): Result<Cipher> {
): Result<EncryptionContext> {
val userId = activeUserId ?: return NoActiveUserException().asFailure()
return ciphersService
.deleteCipherAttachment(
@@ -181,10 +186,10 @@ class CipherManagerImpl(
)
.encryptCipherAndCheckForMigration(userId = userId, cipherId = cipherId)
}
.onSuccess { cipher ->
.onSuccess { encryptionContext ->
vaultDiskSource.saveCipher(
userId = userId,
cipher = cipher.toEncryptedNetworkCipherResponse(),
cipher = encryptionContext.toEncryptedNetworkCipherResponse(),
)
}
}
@@ -220,10 +225,10 @@ class CipherManagerImpl(
userId = userId,
cipherView = cipherView,
)
.flatMap { cipher ->
.flatMap {
ciphersService.updateCipher(
cipherId = cipherId,
body = cipher.toEncryptedNetworkCipher(),
body = it.toEncryptedNetworkCipher(),
)
}
.map { response ->
@@ -263,11 +268,11 @@ class CipherManagerImpl(
)
}
.flatMap { vaultSdkSource.encryptCipher(userId = userId, cipherView = it) }
.flatMap { cipher ->
.flatMap {
ciphersService.shareCipher(
cipherId = cipherId,
body = ShareCipherJsonRequest(
cipher = cipher.toEncryptedNetworkCipher(),
cipher = it.toEncryptedNetworkCipher(),
collectionIds = collectionIds,
),
)
@@ -301,10 +306,10 @@ class CipherManagerImpl(
cipherView = cipherView.copy(collectionIds = collectionIds),
)
}
.onSuccess { cipher ->
.onSuccess { encryptionContext ->
vaultDiskSource.saveCipher(
userId = userId,
cipher = cipher.toEncryptedNetworkCipherResponse(),
cipher = encryptionContext.toEncryptedNetworkCipherResponse(),
)
}
.fold(
@@ -362,14 +367,14 @@ class CipherManagerImpl(
userId = userId,
cipherId = requireNotNull(cipherView.id),
)
.flatMap { cipher ->
.flatMap { encryptionContext ->
fileManager
.writeUriToCache(fileUri = fileUri)
.flatMap { cacheFile ->
vaultSdkSource
.encryptAttachment(
userId = userId,
cipher = cipher,
cipher = encryptionContext.cipher,
attachmentView = attachmentView,
decryptedFilePath = cacheFile.absolutePath,
encryptedFilePath = "${cacheFile.absolutePath}.enc",
@@ -447,10 +452,10 @@ class CipherManagerImpl(
cipherId = requireNotNull(cipherView.id),
)
.fold(
onSuccess = { it },
onSuccess = { it.cipher },
onFailure = { return it.asFailure() },
)
val attachment = cipher.attachments?.find { it.id == attachmentId }
val attachmentView = cipherView.attachments?.find { it.id == attachmentId }
?: return IllegalStateException("No attachment to download").asFailure()
val attachmentData = ciphersService
@@ -479,7 +484,7 @@ class CipherManagerImpl(
.decryptFile(
userId = userId,
cipher = cipher,
attachment = attachment,
attachmentView = attachmentView,
encryptedFilePath = encryptedFile.path,
decryptedFilePath = decryptedFile.path,
)
@@ -494,17 +499,17 @@ class CipherManagerImpl(
private suspend fun CipherView.encryptCipherAndCheckForMigration(
userId: String,
cipherId: String,
): Result<Cipher> =
): Result<EncryptionContext> =
vaultSdkSource
.encryptCipher(userId = userId, cipherView = this)
.flatMap {
.flatMap { encryptionContext ->
// We only migrate the cipher if the original cipher did not have a key and the
// new cipher does. This means the SDK created the key and migration is required.
if (it.key != null && this.key == null) {
if (encryptionContext.cipher.key != null && this.key == null) {
ciphersService
.updateCipher(
cipherId = cipherId,
body = it.toEncryptedNetworkCipher(),
body = encryptionContext.toEncryptedNetworkCipher(),
)
.flatMap { response ->
when (response) {
@@ -520,12 +525,14 @@ class CipherManagerImpl(
userId = userId,
cipher = response.cipher,
)
response.cipher.toEncryptedSdkCipher().asSuccess()
encryptionContext
.copy(cipher = response.cipher.toEncryptedSdkCipher())
.asSuccess()
}
}
}
} else {
it.asSuccess()
encryptionContext.asSuccess()
}
}
@@ -541,7 +548,7 @@ class CipherManagerImpl(
?: return IllegalStateException("CipherView must have an ID").asFailure()
var migratedCipherView = cipherView
.encryptCipherAndCheckForMigration(userId = userId, cipherId = cipherViewId)
.flatMap { vaultSdkSource.decryptCipher(userId = userId, cipher = it) }
.flatMap { vaultSdkSource.decryptCipher(userId = userId, cipher = it.cipher) }
.getOrElse { return it.asFailure() }
attachmentViewsToMigrate
@@ -574,7 +581,12 @@ class CipherManagerImpl(
cipherId = cipherViewId,
)
}
.flatMap { vaultSdkSource.decryptCipher(userId = userId, cipher = it) }
.flatMap {
vaultSdkSource.decryptCipher(
userId = userId,
cipher = it.cipher,
)
}
.onSuccess { migratedCipherView = it }
}
?: IllegalStateException("AttachmentView must have an ID").asFailure()
@@ -181,6 +181,7 @@ class VaultLockManagerImpl(
email = email,
privateKey = privateKey,
method = initUserCryptoMethod,
userId = userId,
),
)
.flatMap { result ->
@@ -20,6 +20,7 @@ import com.bitwarden.vault.CipherPermissions
import com.bitwarden.vault.CipherRepromptType
import com.bitwarden.vault.CipherType
import com.bitwarden.vault.CipherView
import com.bitwarden.vault.EncryptionContext
import com.bitwarden.vault.Fido2Credential
import com.bitwarden.vault.Field
import com.bitwarden.vault.FieldType
@@ -37,8 +38,12 @@ import java.time.ZonedDateTime
/**
* Converts a Bitwarden SDK [Cipher] object to a corresponding
* [SyncResponseJson.Cipher] object.
*
* @param encryptedFor The ID of the user who this cipher is encrypted by.
*/
fun Cipher.toEncryptedNetworkCipher(): CipherJsonRequest =
fun Cipher.toEncryptedNetworkCipher(
encryptedFor: String,
): CipherJsonRequest =
CipherJsonRequest(
notes = notes,
attachments = attachments
@@ -59,13 +64,18 @@ fun Cipher.toEncryptedNetworkCipher(): CipherJsonRequest =
card = card?.toEncryptedNetworkCard(),
key = key,
sshKey = sshKey?.toEncryptedNetworkSshKey(),
encryptedFor = encryptedFor,
)
/**
* Converts a Bitwarden SDK [Cipher] object to a corresponding
* [SyncResponseJson.Cipher] object.
*
* @param encryptedFor The ID of the user who this cipher is encrypted by.
*/
fun Cipher.toEncryptedNetworkCipherResponse(): SyncResponseJson.Cipher =
fun Cipher.toEncryptedNetworkCipherResponse(
encryptedFor: String,
): SyncResponseJson.Cipher =
SyncResponseJson.Cipher(
notes = notes,
reprompt = reprompt.toNetworkRepromptType(),
@@ -92,6 +102,7 @@ fun Cipher.toEncryptedNetworkCipherResponse(): SyncResponseJson.Cipher =
id = id.orEmpty(),
shouldViewPassword = viewPassword,
key = key,
encryptedFor = encryptedFor,
)
/**
@@ -626,3 +637,17 @@ fun List<CipherListView>.sortAlphabetically(): List<CipherListView> {
},
)
}
/**
* Converts a Bitwarden SDK [EncryptionContext] object to a corresponding [CipherJsonRequest]
* object.
*/
fun EncryptionContext.toEncryptedNetworkCipher(): CipherJsonRequest =
cipher.toEncryptedNetworkCipher(encryptedFor = encryptedFor)
/**
* Converts a Bitwarden SDK [EncryptionContext] object to a corresponding [SyncResponseJson.Cipher]
* object.
*/
fun EncryptionContext.toEncryptedNetworkCipherResponse(): SyncResponseJson.Cipher =
cipher.toEncryptedNetworkCipherResponse(encryptedFor = encryptedFor)
@@ -419,7 +419,8 @@ private const val CIPHER_JSON = """
"publicKey": "mockPublicKey-1",
"privateKey": "mockPrivateKey-1",
"keyFingerprint": "mockKeyFingerprint-1"
}
},
"encryptedFor": "mockEncryptedFor-1"
}
"""
@@ -20,15 +20,15 @@ import com.bitwarden.fido.PublicKeyCredentialAuthenticatorAttestationResponse
import com.bitwarden.fido.UnverifiedAssetLink
import com.bitwarden.sdk.AuthClient
import com.bitwarden.sdk.BitwardenException
import com.bitwarden.sdk.CiphersClient
import com.bitwarden.sdk.Client
import com.bitwarden.sdk.ClientCiphers
import com.bitwarden.sdk.ClientFido2
import com.bitwarden.sdk.ClientFido2Authenticator
import com.bitwarden.sdk.ClientFido2Client
import com.bitwarden.sdk.ClientPasswordHistory
import com.bitwarden.sdk.CryptoClient
import com.bitwarden.sdk.ExporterClient
import com.bitwarden.sdk.Fido2CredentialStore
import com.bitwarden.sdk.PasswordHistoryClient
import com.bitwarden.sdk.PlatformClient
import com.bitwarden.sdk.SendClient
import com.bitwarden.sdk.VaultClient
@@ -41,6 +41,7 @@ import com.bitwarden.vault.CipherListView
import com.bitwarden.vault.CipherView
import com.bitwarden.vault.Collection
import com.bitwarden.vault.CollectionView
import com.bitwarden.vault.EncryptionContext
import com.bitwarden.vault.Folder
import com.bitwarden.vault.FolderView
import com.bitwarden.vault.PasswordHistory
@@ -83,12 +84,12 @@ class VaultSdkSourceTest {
private val clientPlatform = mockk<PlatformClient> {
every { fido2() } returns clientFido2
}
private val clientPasswordHistory = mockk<ClientPasswordHistory>()
private val passwordHistoryClient = mockk<PasswordHistoryClient>()
private val clientSends = mockk<SendClient>()
private val clientCiphers = mockk<ClientCiphers>()
private val ciphersClient = mockk<CiphersClient>()
private val clientVault = mockk<VaultClient> {
every { ciphers() } returns clientCiphers
every { passwordHistory() } returns clientPasswordHistory
every { ciphers() } returns ciphersClient
every { passwordHistory() } returns passwordHistoryClient
}
private val clientExporters = mockk<ExporterClient> {
coEvery { exportVault(any(), any(), any()) }
@@ -615,8 +616,10 @@ class VaultSdkSourceTest {
fun `decryptCipher should call SDK and return a Result with correct data`() = runBlocking {
val userId = "userId"
val mockCipher = mockk<CipherView>()
val expectedResult = mockk<Cipher>()
coEvery { clientCiphers.encrypt(cipherView = mockCipher) } returns expectedResult
val expectedResult = mockk<EncryptionContext> {
every { cipher } returns createMockSdkCipher(number = 1)
}
coEvery { ciphersClient.encrypt(cipherView = mockCipher) } returns expectedResult
val result = vaultSdkSource.encryptCipher(
userId = userId,
cipherView = mockCipher,
@@ -626,7 +629,7 @@ class VaultSdkSourceTest {
result,
)
coVerify {
clientCiphers.encrypt(cipherView = mockCipher)
ciphersClient.encrypt(cipherView = mockCipher)
sdkClientManager.getOrCreateClient(userId = userId)
}
}
@@ -636,7 +639,7 @@ class VaultSdkSourceTest {
val userId = "userId"
val mockCipher = mockk<Cipher>()
val expectedResult = mockk<CipherView>()
coEvery { clientCiphers.decrypt(cipher = mockCipher) } returns expectedResult
coEvery { ciphersClient.decrypt(cipher = mockCipher) } returns expectedResult
val result = vaultSdkSource.decryptCipher(
userId = userId,
cipher = mockCipher,
@@ -646,7 +649,7 @@ class VaultSdkSourceTest {
result,
)
coVerify {
clientCiphers.decrypt(cipher = mockCipher)
ciphersClient.decrypt(cipher = mockCipher)
sdkClientManager.getOrCreateClient(userId = userId)
}
}
@@ -657,7 +660,7 @@ class VaultSdkSourceTest {
val userId = "userId"
val mockCiphers = mockk<List<Cipher>>()
val expectedResult = mockk<List<CipherListView>>()
coEvery { clientCiphers.decryptList(ciphers = mockCiphers) } returns expectedResult
coEvery { ciphersClient.decryptList(ciphers = mockCiphers) } returns expectedResult
val result = vaultSdkSource.decryptCipherListCollection(
userId = userId,
cipherList = mockCiphers,
@@ -667,7 +670,7 @@ class VaultSdkSourceTest {
result,
)
coVerify {
clientCiphers.decryptList(ciphers = mockCiphers)
ciphersClient.decryptList(ciphers = mockCiphers)
sdkClientManager.getOrCreateClient(userId = userId)
}
}
@@ -679,8 +682,8 @@ class VaultSdkSourceTest {
val mockCipher2 = mockk<Cipher>()
val cipherView1 = mockk<CipherView>()
val cipherView2 = mockk<CipherView>()
coEvery { clientCiphers.decrypt(cipher = mockCipher1) } returns cipherView1
coEvery { clientCiphers.decrypt(cipher = mockCipher2) } returns cipherView2
coEvery { ciphersClient.decrypt(cipher = mockCipher1) } returns cipherView1
coEvery { ciphersClient.decrypt(cipher = mockCipher2) } returns cipherView2
val result = vaultSdkSource.decryptCipherList(
userId = userId,
cipherList = listOf(mockCipher1, mockCipher2),
@@ -690,8 +693,8 @@ class VaultSdkSourceTest {
result,
)
coVerify(exactly = 1) {
clientCiphers.decrypt(cipher = mockCipher1)
clientCiphers.decrypt(cipher = mockCipher2)
ciphersClient.decrypt(cipher = mockCipher1)
ciphersClient.decrypt(cipher = mockCipher2)
// It's important that we only fetch the client once
sdkClientManager.getOrCreateClient(userId = userId)
client.vault()
@@ -936,12 +939,12 @@ class VaultSdkSourceTest {
fun `File decrypt should call SDK and return a Result with correct data`() = runBlocking {
val userId = "userId"
val mockCipher = mockk<Cipher>()
val mockAttachment = mockk<Attachment>()
val mockAttachmentView = mockk<AttachmentView>()
val expectedResult = Unit
coEvery {
clientVault.attachments().decryptFile(
cipher = mockCipher,
attachment = mockAttachment,
attachment = mockAttachmentView,
encryptedFilePath = "encrypted_path",
decryptedFilePath = "decrypted_path",
)
@@ -949,7 +952,7 @@ class VaultSdkSourceTest {
val result = vaultSdkSource.decryptFile(
userId = userId,
cipher = mockCipher,
attachment = mockAttachment,
attachmentView = mockAttachmentView,
encryptedFilePath = "encrypted_path",
decryptedFilePath = "decrypted_path",
)
@@ -960,7 +963,7 @@ class VaultSdkSourceTest {
coVerify {
clientVault.attachments().decryptFile(
cipher = mockCipher,
attachment = mockAttachment,
attachment = mockAttachmentView,
encryptedFilePath = "encrypted_path",
decryptedFilePath = "decrypted_path",
)
@@ -975,7 +978,7 @@ class VaultSdkSourceTest {
val mockPasswordHistoryView = mockk<PasswordHistoryView>()
val expectedResult = mockk<PasswordHistory>()
coEvery {
clientPasswordHistory.encrypt(
passwordHistoryClient.encrypt(
passwordHistory = mockPasswordHistoryView,
)
} returns expectedResult
@@ -987,7 +990,7 @@ class VaultSdkSourceTest {
assertEquals(expectedResult.asSuccess(), result)
coVerify {
clientPasswordHistory.encrypt(
passwordHistoryClient.encrypt(
passwordHistory = mockPasswordHistoryView,
)
}
@@ -1001,7 +1004,7 @@ class VaultSdkSourceTest {
val mockPasswordHistoryList = mockk<List<PasswordHistory>>()
val expectedResult = mockk<List<PasswordHistoryView>>()
coEvery {
clientPasswordHistory.decryptList(
passwordHistoryClient.decryptList(
list = mockPasswordHistoryList,
)
} returns expectedResult
@@ -1013,7 +1016,7 @@ class VaultSdkSourceTest {
assertEquals(expectedResult.asSuccess(), result)
coVerify {
clientPasswordHistory.decryptList(
passwordHistoryClient.decryptList(
list = mockPasswordHistoryList,
)
}
@@ -1051,7 +1054,7 @@ class VaultSdkSourceTest {
val mockCipher = mockk<CipherView>()
val expectedResult = mockk<CipherView>()
coEvery {
clientCiphers.moveToOrganization(cipher = mockCipher, organizationId = organizationId)
ciphersClient.moveToOrganization(cipher = mockCipher, organizationId = organizationId)
} returns expectedResult
val result = vaultSdkSource.moveToOrganization(
@@ -56,6 +56,7 @@ fun createMockCipherView(
clock = clock,
fido2Credentials = fido2Credentials,
),
attachments: List<AttachmentView> = listOf(createMockAttachmentView(number = number)),
): CipherView =
CipherView(
id = "mockId-$number",
@@ -74,7 +75,7 @@ fun createMockCipherView(
null
},
revisionDate = clock.instant(),
attachments = listOf(createMockAttachmentView(number = number)),
attachments = attachments,
card = createMockCardView(number = number).takeIf { cipherType == CipherType.CARD },
fields = listOf(createMockFieldView(number = number)),
identity = createMockIdentityView(number = number).takeIf {
@@ -0,0 +1,29 @@
package com.x8bit.bitwarden.data.vault.datasource.sdk.model
import com.bitwarden.vault.Cipher
import com.bitwarden.vault.EncryptionContext
import java.time.Clock
import java.time.Instant
import java.time.ZoneOffset
import java.time.ZonedDateTime
/**
* Default date time used for [ZonedDateTime] properties of mock objects.
*/
private const val DEFAULT_TIMESTAMP = "2023-10-27T12:00:00Z"
private val FIXED_CLOCK: Clock = Clock.fixed(
Instant.parse(DEFAULT_TIMESTAMP),
ZoneOffset.UTC,
)
/**
* Create a mock [EncryptionContext] with a given [number].
*/
fun createMockEncryptionContext(
number: Int,
cipher: Cipher = createMockSdkCipher(number, FIXED_CLOCK),
): EncryptionContext =
EncryptionContext(
encryptedFor = "mockEncryptedFor-$number",
cipher = cipher,
)
@@ -19,6 +19,7 @@ import com.bitwarden.network.service.CiphersService
import com.bitwarden.vault.Attachment
import com.bitwarden.vault.AttachmentView
import com.bitwarden.vault.Cipher
import com.bitwarden.vault.EncryptionContext
import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountJson
import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountTokensJson
import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson
@@ -29,6 +30,7 @@ import com.x8bit.bitwarden.data.vault.datasource.disk.VaultDiskSource
import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockAttachmentView
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockEncryptionContext
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockSdkAttachment
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockSdkCipher
import com.x8bit.bitwarden.data.vault.manager.model.DownloadResult
@@ -156,7 +158,10 @@ class CipherManagerTest {
userId = userId,
cipherView = mockCipherView,
)
} returns createMockSdkCipher(number = 1, clock = clock).asSuccess()
} returns createMockEncryptionContext(
number = 1,
cipher = createMockSdkCipher(number = 1, clock = clock),
).asSuccess()
coEvery {
ciphersService.createCipher(
body = createMockCipherJsonRequest(
@@ -183,7 +188,10 @@ class CipherManagerTest {
userId = userId,
cipherView = mockCipherView,
)
} returns createMockSdkCipher(number = 1, clock = clock).asSuccess()
} returns createMockEncryptionContext(
number = 1,
cipher = createMockSdkCipher(number = 1, clock = clock),
).asSuccess()
val mockCipher = createMockCipher(number = 1)
coEvery {
ciphersService.createCipher(
@@ -250,7 +258,10 @@ class CipherManagerTest {
userId = userId,
cipherView = mockCipherView,
)
} returns createMockSdkCipher(number = 1, clock = clock).asSuccess()
} returns createMockEncryptionContext(
number = 1,
cipher = createMockSdkCipher(number = 1, clock = clock),
).asSuccess()
coEvery {
ciphersService.createCipherInOrganization(
body = CreateCipherInOrganizationJsonRequest(
@@ -283,7 +294,10 @@ class CipherManagerTest {
userId = userId,
cipherView = mockCipherView,
)
} returns createMockSdkCipher(number = 1, clock = clock).asSuccess()
} returns createMockEncryptionContext(
number = 1,
cipher = createMockSdkCipher(number = 1, clock = clock),
).asSuccess()
val mockCipher = createMockCipher(number = 1)
coEvery {
ciphersService.createCipherInOrganization(
@@ -364,7 +378,10 @@ class CipherManagerTest {
userId = userId,
cipherView = mockCipherView,
)
} returns createMockSdkCipher(number = 1, clock = clock).asSuccess()
} returns createMockEncryptionContext(
number = 1,
cipher = createMockSdkCipher(number = 1, clock = clock),
).asSuccess()
coEvery {
ciphersService.updateCipher(
cipherId = cipherId,
@@ -396,7 +413,10 @@ class CipherManagerTest {
userId = userId,
cipherView = mockCipherView,
)
} returns createMockSdkCipher(number = 1, clock = clock).asSuccess()
} returns createMockEncryptionContext(
number = 1,
cipher = createMockSdkCipher(number = 1, clock = clock),
).asSuccess()
coEvery {
ciphersService.updateCipher(
cipherId = cipherId,
@@ -439,7 +459,10 @@ class CipherManagerTest {
userId = userId,
cipherView = mockCipherView,
)
} returns createMockSdkCipher(number = 1, clock = clock).asSuccess()
} returns createMockEncryptionContext(
number = 1,
cipher = createMockSdkCipher(number = 1, clock = clock),
).asSuccess()
val mockCipher = createMockCipher(number = 1)
coEvery {
ciphersService.updateCipher(
@@ -529,11 +552,11 @@ class CipherManagerTest {
val userId = MOCK_USER_STATE.activeUserId
val cipherId = "mockId-1"
val cipherView = createMockCipherView(number = 1)
val cipher = createMockSdkCipher(number = 1)
val encryptionContext = createMockEncryptionContext(number = 1)
val error = Throwable("Fail")
coEvery {
vaultSdkSource.encryptCipher(userId = userId, cipherView = cipherView)
} returns cipher.asSuccess()
} returns encryptionContext.asSuccess()
coEvery {
ciphersService.softDeleteCipher(cipherId = cipherId)
} returns error.asFailure()
@@ -553,26 +576,32 @@ class CipherManagerTest {
val fixedInstant = Instant.parse("2023-10-27T12:00:00Z")
val userId = "mockId-1"
val cipherId = "mockId-1"
val cipher = createMockSdkCipher(number = 1, clock = clock)
val encryptionContext = createMockEncryptionContext(
number = 1,
cipher = createMockSdkCipher(number = 1, clock = clock),
)
val cipherView = createMockCipherView(number = 1)
coEvery {
vaultSdkSource.encryptCipher(userId = userId, cipherView = cipherView)
} returns cipher.asSuccess()
} returns encryptionContext.asSuccess()
coEvery {
vaultSdkSource.encryptCipher(
userId = userId,
cipherView = cipherView.copy(deletedDate = fixedInstant),
)
} returns cipher.asSuccess()
} returns encryptionContext.asSuccess()
coEvery {
vaultSdkSource.decryptCipher(userId = userId, cipher = cipher)
vaultSdkSource.decryptCipher(
userId = userId,
cipher = encryptionContext.cipher,
)
} returns cipherView.asSuccess()
fakeAuthDiskSource.userState = MOCK_USER_STATE
coEvery { ciphersService.softDeleteCipher(cipherId = cipherId) } returns Unit.asSuccess()
coEvery {
vaultDiskSource.saveCipher(
userId = userId,
cipher = cipher.toEncryptedNetworkCipherResponse(),
cipher = encryptionContext.toEncryptedNetworkCipherResponse(),
)
} just runs
@@ -591,16 +620,19 @@ class CipherManagerTest {
val fixedInstant = Instant.parse("2023-10-27T12:00:00Z")
val userId = "mockId-1"
val cipherId = "mockId-1"
val cipher = createMockSdkCipher(number = 1, clock = clock)
val encryptionContext = createMockEncryptionContext(
number = 1,
cipher = createMockSdkCipher(number = 1, clock = clock),
)
val cipherView = createMockCipherView(number = 1).copy(key = null)
val networkCipher = createMockCipher(number = 1).copy(key = null)
coEvery {
vaultSdkSource.encryptCipher(userId = userId, cipherView = cipherView)
} returns cipher.asSuccess()
} returns encryptionContext.asSuccess()
coEvery {
ciphersService.updateCipher(
cipherId = cipherId,
body = cipher.toEncryptedNetworkCipher(),
body = encryptionContext.toEncryptedNetworkCipher(),
)
} returns UpdateCipherResponseJson.Success(networkCipher).asSuccess()
coEvery {
@@ -617,16 +649,16 @@ class CipherManagerTest {
userId = userId,
cipherView = cipherView.copy(deletedDate = fixedInstant),
)
} returns cipher.asSuccess()
} returns encryptionContext.asSuccess()
coEvery {
vaultSdkSource.decryptCipher(userId = userId, cipher = cipher)
vaultSdkSource.decryptCipher(userId = userId, cipher = encryptionContext.cipher)
} returns cipherView.asSuccess()
fakeAuthDiskSource.userState = MOCK_USER_STATE
coEvery { ciphersService.softDeleteCipher(cipherId = cipherId) } returns Unit.asSuccess()
coEvery {
vaultDiskSource.saveCipher(
userId = userId,
cipher = cipher.toEncryptedNetworkCipherResponse(),
cipher = encryptionContext.toEncryptedNetworkCipherResponse(),
)
} just runs
@@ -639,7 +671,7 @@ class CipherManagerTest {
coVerify(exactly = 1) {
ciphersService.updateCipher(
cipherId = cipherId,
body = cipher.toEncryptedNetworkCipher(),
body = encryptionContext.toEncryptedNetworkCipher(),
)
vaultDiskSource.saveCipher(userId = userId, cipher = networkCipher)
}
@@ -692,7 +724,11 @@ class CipherManagerTest {
runTest {
mockkStatic(Cipher::toEncryptedNetworkCipherResponse)
every {
createMockSdkCipher(number = 1, clock = clock).toEncryptedNetworkCipherResponse()
createMockEncryptionContext(
number = 1,
cipher = createMockSdkCipher(number = 1, clock = clock),
)
.toEncryptedNetworkCipherResponse()
} returns createMockCipher(number = 1)
val fixedInstant = Instant.parse("2021-01-01T00:00:00Z")
val userId = "mockId-1"
@@ -703,7 +739,10 @@ class CipherManagerTest {
userId = userId,
cipherView = createMockCipherView(number = 1).copy(attachments = emptyList()),
)
} returns createMockSdkCipher(number = 1, clock = clock).asSuccess()
} returns createMockEncryptionContext(
number = 1,
cipher = createMockSdkCipher(number = 1, clock = clock),
).asSuccess()
fakeAuthDiskSource.userState = MOCK_USER_STATE
coEvery {
ciphersService.deleteCipherAttachment(
@@ -820,7 +859,10 @@ class CipherManagerTest {
} returns mockCipherView.asSuccess()
coEvery {
vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView)
} returns createMockSdkCipher(number = 1, clock = clock).asSuccess()
} returns createMockEncryptionContext(
number = 1,
cipher = createMockSdkCipher(number = 1, clock = clock),
).asSuccess()
coEvery {
ciphersService.shareCipher(
cipherId = "mockId-1",
@@ -864,6 +906,10 @@ class CipherManagerTest {
val mockCipher = createMockSdkCipher(number = 1).copy(
attachments = listOf(mockAttachment),
)
val mockEncryptionContext = createMockEncryptionContext(
number = 1,
cipher = mockCipher,
)
val attachment = createMockAttachment(number = 1)
val encryptedFile = File("path/to/encrypted/file")
val decryptedFile = File("path/to/encrypted/file_decrypted")
@@ -874,7 +920,7 @@ class CipherManagerTest {
// Handle mocks for migration
coEvery {
vaultSdkSource.encryptCipher(userId = userId, cipherView = initialCipherView)
} returns mockCipher.asSuccess()
} returns mockEncryptionContext.asSuccess()
coEvery {
vaultSdkSource.decryptCipher(userId = userId, cipher = mockCipher)
} returns initialCipherView.asSuccess()
@@ -888,7 +934,7 @@ class CipherManagerTest {
vaultSdkSource.decryptFile(
userId = userId,
cipher = mockCipher,
attachment = mockAttachment,
attachmentView = mockAttachmentView,
encryptedFilePath = encryptedFile.path,
decryptedFilePath = decryptedFile.path,
)
@@ -950,11 +996,11 @@ class CipherManagerTest {
userId = userId,
cipherView = mockCipherView.copy(attachments = emptyList()),
)
} returns mockCipher.asSuccess()
} returns mockEncryptionContext.asSuccess()
coEvery {
vaultDiskSource.saveCipher(
userId = userId,
cipher = mockCipher.toEncryptedNetworkCipherResponse(),
cipher = mockCipher.toEncryptedNetworkCipherResponse("mockEncryptedFor-1"),
)
} just runs
// Done with mocks for migration
@@ -968,7 +1014,10 @@ class CipherManagerTest {
} returns mockCipherView.asSuccess()
coEvery {
vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView)
} returns createMockSdkCipher(number = 1, clock = clock).asSuccess()
} returns createMockEncryptionContext(
number = 1,
cipher = createMockSdkCipher(number = 1, clock = clock),
).asSuccess()
coEvery {
ciphersService.shareCipher(
cipherId = "mockId-1",
@@ -1015,7 +1064,10 @@ class CipherManagerTest {
} returns mockCipherView.asSuccess()
coEvery {
vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView)
} returns createMockSdkCipher(number = 1, clock = clock).asSuccess()
} returns createMockEncryptionContext(
number = 1,
cipher = createMockSdkCipher(number = 1, clock = clock),
).asSuccess()
val error = Throwable("Fail")
coEvery {
ciphersService.shareCipher(
@@ -1102,7 +1154,10 @@ class CipherManagerTest {
userId = userId,
cipherView = createMockCipherView(number = 1),
)
} returns createMockSdkCipher(number = 1, clock = clock).asSuccess()
} returns createMockEncryptionContext(
number = 1,
cipher = createMockSdkCipher(number = 1, clock = clock),
).asSuccess()
coEvery {
ciphersService.updateCipherCollections(
cipherId = "mockId-1",
@@ -1135,7 +1190,10 @@ class CipherManagerTest {
userId = userId,
cipherView = createMockCipherView(number = 1),
)
} returns createMockSdkCipher(number = 1, clock = clock).asSuccess()
} returns createMockEncryptionContext(
number = 1,
cipher = createMockSdkCipher(number = 1, clock = clock),
).asSuccess()
val error = Throwable("Fail")
coEvery {
ciphersService.updateCipherCollections(
@@ -1251,6 +1309,7 @@ class CipherManagerTest {
val mockUri = setupMockUri(url = "www.test.com")
val mockCipherView = createMockCipherView(number = 1)
val mockCipher = createMockSdkCipher(number = 1, clock = clock)
val mockEncryptionContext = createMockEncryptionContext(number = 1, cipher = mockCipher)
val mockFile = File.createTempFile("mockFile", "temp")
val mockFileName = "mockFileName-1"
val mockFileSize = "1"
@@ -1263,7 +1322,7 @@ class CipherManagerTest {
val error = Throwable("Fail")
coEvery {
vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView)
} returns mockCipher.asSuccess()
} returns mockEncryptionContext.asSuccess()
coEvery {
fileManager.writeUriToCache(fileUri = mockUri)
} returns mockFile.asSuccess()
@@ -1298,12 +1357,13 @@ class CipherManagerTest {
val mockUri = setupMockUri(url = "www.test.com")
val mockCipherView = createMockCipherView(number = 1)
val mockCipher = createMockSdkCipher(number = 1, clock = clock)
val mockEncryptionContext = createMockEncryptionContext(number = 1, cipher = mockCipher)
val mockFileName = "mockFileName-1"
val mockFileSize = "1"
val error = Throwable("Fail")
coEvery {
vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView)
} returns mockCipher.asSuccess()
} returns mockEncryptionContext.asSuccess()
coEvery {
fileManager.writeUriToCache(fileUri = mockUri)
} returns error.asFailure()
@@ -1329,6 +1389,7 @@ class CipherManagerTest {
val mockUri = setupMockUri(url = "www.test.com")
val mockCipherView = createMockCipherView(number = 1)
val mockCipher = createMockSdkCipher(number = 1, clock = clock)
val mockEncryptionContext = createMockEncryptionContext(number = 1, cipher = mockCipher)
val mockFileName = "mockFileName-1"
val mockFileSize = "1"
val mockAttachmentView = createMockAttachmentView(number = 1).copy(
@@ -1342,7 +1403,7 @@ class CipherManagerTest {
val error = Throwable("Fail")
coEvery {
vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView)
} returns mockCipher.asSuccess()
} returns mockEncryptionContext.asSuccess()
coEvery {
fileManager.writeUriToCache(fileUri = mockUri)
} returns mockFile.asSuccess()
@@ -1387,6 +1448,7 @@ class CipherManagerTest {
val mockUri = setupMockUri(url = "www.test.com")
val mockCipherView = createMockCipherView(number = 1)
val mockCipher = createMockSdkCipher(number = 1, clock = clock)
val mockEncryptionContext = createMockEncryptionContext(number = 1, cipher = mockCipher)
val mockFileName = "mockFileName-1"
val mockFileSize = "1"
val mockAttachmentView = createMockAttachmentView(number = 1).copy(
@@ -1401,7 +1463,7 @@ class CipherManagerTest {
val error = Throwable("Fail")
coEvery {
vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView)
} returns mockCipher.asSuccess()
} returns mockEncryptionContext.asSuccess()
coEvery {
fileManager.writeUriToCache(fileUri = mockUri)
} returns mockFile.asSuccess()
@@ -1452,6 +1514,7 @@ class CipherManagerTest {
val mockUri = setupMockUri(url = "www.test.com")
val mockCipherView = createMockCipherView(number = 1)
val mockCipher = createMockSdkCipher(number = 1, clock = clock)
val mockEncryptionContext = createMockEncryptionContext(number = 1, cipher = mockCipher)
val mockFileName = "mockFileName-1"
val mockFileSize = "1"
val mockAttachmentView = createMockAttachmentView(number = 1).copy(
@@ -1470,7 +1533,7 @@ class CipherManagerTest {
val error = Throwable("Fail")
coEvery {
vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView)
} returns mockCipher.asSuccess()
} returns mockEncryptionContext.asSuccess()
coEvery {
fileManager.writeUriToCache(fileUri = mockUri)
} returns mockFile.asSuccess()
@@ -1530,6 +1593,7 @@ class CipherManagerTest {
val mockUri = setupMockUri(url = "www.test.com")
val mockCipherView = createMockCipherView(number = 1)
val mockCipher = createMockSdkCipher(number = 1, clock = clock)
val mockEncryptionContext = createMockEncryptionContext(number = 1, cipher = mockCipher)
val mockFileName = "mockFileName-1"
val mockFileSize = "1"
val mockAttachmentView = createMockAttachmentView(number = 1).copy(
@@ -1547,7 +1611,7 @@ class CipherManagerTest {
)
coEvery {
vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView)
} returns mockCipher.asSuccess()
} returns mockEncryptionContext.asSuccess()
coEvery {
fileManager.writeUriToCache(fileUri = mockUri)
} returns mockFile.asSuccess()
@@ -1605,6 +1669,7 @@ class CipherManagerTest {
val mockUri = setupMockUri(url = "www.test.com")
val mockCipherView = createMockCipherView(number = 1)
val mockCipher = createMockSdkCipher(number = 1, clock = clock)
val mockEncryptionContext = createMockEncryptionContext(number = 1, cipher = mockCipher)
val mockFileName = "mockFileName-1"
val mockFileSize = "1"
val mockAttachmentView = createMockAttachmentView(number = 1).copy(
@@ -1622,7 +1687,7 @@ class CipherManagerTest {
)
coEvery {
vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView)
} returns mockCipher.asSuccess()
} returns mockEncryptionContext.asSuccess()
coEvery {
fileManager.writeUriToCache(fileUri = mockUri)
} returns mockFile.asSuccess()
@@ -1682,6 +1747,7 @@ class CipherManagerTest {
val mockUri = setupMockUri(url = "www.test.com")
val mockCipherView = createMockCipherView(number = 1)
val mockCipher = createMockSdkCipher(number = 1, clock = clock)
val mockEncryptionContext = createMockEncryptionContext(number = 1, cipher = mockCipher)
val mockFileName = "mockFileName-1"
val mockFileSize = "1"
val mockAttachmentView = createMockAttachmentView(number = 1).copy(
@@ -1695,7 +1761,7 @@ class CipherManagerTest {
val mockAttachmentJsonResponse = createMockAttachmentResponse(number = 1)
coEvery {
vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView)
} returns mockCipher.asSuccess()
} returns mockEncryptionContext.asSuccess()
coEvery {
fileManager.writeUriToCache(fileUri = mockUri)
} returns mockFile.asSuccess()
@@ -1743,18 +1809,22 @@ class CipherManagerTest {
fakeAuthDiskSource.userState = MOCK_USER_STATE
val attachmentId = "mockId-1"
val cipher = mockk<Cipher> {
val mockCipher = mockk<Cipher> {
every { key } returns "key"
every { attachments } returns emptyList()
every { id } returns "mockId-1"
}
val cipherView = createMockCipherView(number = 1)
val mockEncryptionContext = mockk<EncryptionContext> {
every { encryptedFor } returns "mockEncryptedFor-1"
every { cipher } returns mockCipher
}
val cipherView = createMockCipherView(number = 1, attachments = emptyList())
coEvery {
vaultSdkSource.encryptCipher(
userId = MOCK_USER_STATE.activeUserId,
cipherView = cipherView,
)
} returns cipher.asSuccess()
} returns mockEncryptionContext.asSuccess()
assertEquals(
DownloadAttachmentResult.Failure(IllegalStateException()),
@@ -1784,18 +1854,22 @@ class CipherManagerTest {
val attachment = mockk<Attachment> {
every { id } returns attachmentId
}
val cipher = mockk<Cipher> {
val mockCipher = mockk<Cipher> {
every { key } returns "key"
every { attachments } returns listOf(attachment)
every { id } returns "mockId-1"
}
val mockEncryptionContext = mockk<EncryptionContext> {
every { encryptedFor } returns "mockEncryptedFor-1"
every { cipher } returns mockCipher
}
val cipherView = createMockCipherView(number = 1)
coEvery {
vaultSdkSource.encryptCipher(
userId = MOCK_USER_STATE.activeUserId,
cipherView = cipherView,
)
} returns cipher.asSuccess()
} returns mockEncryptionContext.asSuccess()
val error = Throwable()
coEvery {
@@ -1830,18 +1904,22 @@ class CipherManagerTest {
val attachment = mockk<Attachment> {
every { id } returns attachmentId
}
val cipher = mockk<Cipher> {
val mockCipher = mockk<Cipher> {
every { key } returns "key"
every { attachments } returns listOf(attachment)
every { id } returns "mockId-1"
}
val mockEncryptionContext = mockk<EncryptionContext> {
every { encryptedFor } returns "mockEncryptedFor-1"
every { cipher } returns mockCipher
}
val cipherView = createMockCipherView(number = 1)
coEvery {
vaultSdkSource.encryptCipher(
userId = MOCK_USER_STATE.activeUserId,
cipherView = cipherView,
)
} returns cipher.asSuccess()
} returns mockEncryptionContext.asSuccess()
val response = mockk<SyncResponseJson.Cipher.Attachment> {
every { url } returns null
@@ -1878,11 +1956,15 @@ class CipherManagerTest {
val attachment = mockk<Attachment> {
every { id } returns attachmentId
}
val cipher = mockk<Cipher> {
val mockCipher = mockk<Cipher> {
every { key } returns "key"
every { attachments } returns listOf(attachment)
every { id } returns "mockId-1"
}
val mockEncryptionContext = mockk<EncryptionContext> {
every { encryptedFor } returns "mockEncryptedFor-1"
every { cipher } returns mockCipher
}
val cipherView = createMockCipherView(number = 1)
coEvery {
@@ -1890,7 +1972,7 @@ class CipherManagerTest {
userId = MOCK_USER_STATE.activeUserId,
cipherView = cipherView,
)
} returns cipher.asSuccess()
} returns mockEncryptionContext.asSuccess()
val response = mockk<SyncResponseJson.Cipher.Attachment> {
every { url } returns "https://bitwarden.com"
@@ -1932,18 +2014,23 @@ class CipherManagerTest {
val attachment = mockk<Attachment> {
every { id } returns attachmentId
}
val cipher = mockk<Cipher> {
val mockCipher = mockk<Cipher> {
every { key } returns "key"
every { attachments } returns listOf(attachment)
every { id } returns "mockId-1"
}
val cipherView = createMockCipherView(number = 1)
val mockEncryptionContext = mockk<EncryptionContext> {
every { encryptedFor } returns "mockEncryptedFor-1"
every { cipher } returns mockCipher
}
val attachmentView = createMockAttachmentView(number = 1)
val cipherView = createMockCipherView(number = 1, attachments = listOf(attachmentView))
coEvery {
vaultSdkSource.encryptCipher(
userId = MOCK_USER_STATE.activeUserId,
cipherView = cipherView,
)
} returns cipher.asSuccess()
} returns mockEncryptionContext.asSuccess()
val response = mockk<SyncResponseJson.Cipher.Attachment> {
every { url } returns "https://bitwarden.com"
@@ -1963,8 +2050,8 @@ class CipherManagerTest {
coEvery {
vaultSdkSource.decryptFile(
userId = MOCK_USER_STATE.activeUserId,
cipher = cipher,
attachment = attachment,
cipher = mockCipher,
attachmentView = attachmentView,
encryptedFilePath = "path/to/encrypted/file",
decryptedFilePath = "path/to/encrypted/file_decrypted",
)
@@ -1990,8 +2077,8 @@ class CipherManagerTest {
fileManager.downloadFileToCache("https://bitwarden.com")
vaultSdkSource.decryptFile(
userId = MOCK_USER_STATE.activeUserId,
cipher = cipher,
attachment = attachment,
cipher = mockCipher,
attachmentView = attachmentView,
encryptedFilePath = "path/to/encrypted/file",
decryptedFilePath = "path/to/encrypted/file_decrypted",
)
@@ -2008,18 +2095,25 @@ class CipherManagerTest {
val attachment = mockk<Attachment> {
every { id } returns attachmentId
}
val cipher = mockk<Cipher> {
val mockCipher = mockk<Cipher> {
every { key } returns "key"
every { attachments } returns listOf(attachment)
every { id } returns "mockId-1"
}
val cipherView = createMockCipherView(number = 1)
val mockEncryptionContext = mockk<EncryptionContext> {
every { encryptedFor } returns "mockEncryptedFor-1"
every { cipher } returns mockCipher
}
val attachmentView = mockk<AttachmentView> {
every { id } returns attachmentId
}
val cipherView = createMockCipherView(number = 1, attachments = listOf(attachmentView))
coEvery {
vaultSdkSource.encryptCipher(
userId = MOCK_USER_STATE.activeUserId,
cipherView = cipherView,
)
} returns cipher.asSuccess()
} returns mockEncryptionContext.asSuccess()
val response = mockk<SyncResponseJson.Cipher.Attachment> {
every { url } returns "https://bitwarden.com"
@@ -2039,8 +2133,8 @@ class CipherManagerTest {
coEvery {
vaultSdkSource.decryptFile(
userId = MOCK_USER_STATE.activeUserId,
cipher = cipher,
attachment = attachment,
cipher = mockCipher,
attachmentView = attachmentView,
encryptedFilePath = "path/to/encrypted/file",
decryptedFilePath = "path/to/encrypted/file_decrypted",
)
@@ -2068,8 +2162,8 @@ class CipherManagerTest {
fileManager.downloadFileToCache(url = "https://bitwarden.com")
vaultSdkSource.decryptFile(
userId = MOCK_USER_STATE.activeUserId,
cipher = cipher,
attachment = attachment,
cipher = mockCipher,
attachmentView = attachmentView,
encryptedFilePath = "path/to/encrypted/file",
decryptedFilePath = "path/to/encrypted/file_decrypted",
)
@@ -741,6 +741,7 @@ class VaultLockManagerTest {
vaultSdkSource.initializeCrypto(
userId = USER_ID,
request = InitUserCryptoRequest(
userId = USER_ID,
kdfParams = MOCK_PROFILE.toSdkParams(),
email = MOCK_PROFILE.email,
privateKey = privateKey,
@@ -764,6 +765,7 @@ class VaultLockManagerTest {
vaultSdkSource.initializeCrypto(
userId = USER_ID,
request = InitUserCryptoRequest(
userId = USER_ID,
kdfParams = MOCK_PROFILE.toSdkParams(),
email = MOCK_PROFILE.email,
privateKey = privateKey,
@@ -894,6 +896,7 @@ class VaultLockManagerTest {
vaultSdkSource.initializeCrypto(
userId = USER_ID,
request = InitUserCryptoRequest(
userId = USER_ID,
kdfParams = kdf,
email = email,
privateKey = privateKey,
@@ -958,6 +961,7 @@ class VaultLockManagerTest {
vaultSdkSource.initializeCrypto(
userId = USER_ID,
request = InitUserCryptoRequest(
userId = USER_ID,
kdfParams = kdf,
email = email,
privateKey = privateKey,
@@ -990,6 +994,7 @@ class VaultLockManagerTest {
vaultSdkSource.initializeCrypto(
userId = USER_ID,
request = InitUserCryptoRequest(
userId = USER_ID,
kdfParams = kdf,
email = email,
privateKey = privateKey,
@@ -1065,6 +1070,7 @@ class VaultLockManagerTest {
vaultSdkSource.initializeCrypto(
userId = USER_ID,
request = InitUserCryptoRequest(
userId = USER_ID,
kdfParams = kdf,
email = email,
privateKey = privateKey,
@@ -1098,6 +1104,7 @@ class VaultLockManagerTest {
vaultSdkSource.initializeCrypto(
userId = USER_ID,
request = InitUserCryptoRequest(
userId = USER_ID,
kdfParams = kdf,
email = email,
privateKey = privateKey,
@@ -1143,6 +1150,7 @@ class VaultLockManagerTest {
vaultSdkSource.initializeCrypto(
userId = USER_ID,
request = InitUserCryptoRequest(
userId = USER_ID,
kdfParams = kdf,
email = email,
privateKey = privateKey,
@@ -1169,6 +1177,7 @@ class VaultLockManagerTest {
vaultSdkSource.initializeCrypto(
userId = USER_ID,
request = InitUserCryptoRequest(
userId = USER_ID,
kdfParams = kdf,
email = email,
privateKey = privateKey,
@@ -1221,6 +1230,7 @@ class VaultLockManagerTest {
vaultSdkSource.initializeCrypto(
userId = USER_ID,
request = InitUserCryptoRequest(
userId = USER_ID,
kdfParams = kdf,
email = email,
privateKey = privateKey,
@@ -1254,6 +1264,7 @@ class VaultLockManagerTest {
vaultSdkSource.initializeCrypto(
userId = USER_ID,
request = InitUserCryptoRequest(
userId = USER_ID,
kdfParams = kdf,
email = email,
privateKey = privateKey,
@@ -1298,6 +1309,7 @@ class VaultLockManagerTest {
vaultSdkSource.initializeCrypto(
userId = USER_ID,
request = InitUserCryptoRequest(
userId = USER_ID,
kdfParams = kdf,
email = email,
privateKey = privateKey,
@@ -1324,6 +1336,7 @@ class VaultLockManagerTest {
vaultSdkSource.initializeCrypto(
userId = USER_ID,
request = InitUserCryptoRequest(
userId = USER_ID,
kdfParams = kdf,
email = email,
privateKey = privateKey,
@@ -1375,6 +1388,7 @@ class VaultLockManagerTest {
vaultSdkSource.initializeCrypto(
userId = USER_ID,
request = InitUserCryptoRequest(
userId = USER_ID,
kdfParams = kdf,
email = email,
privateKey = privateKey,
@@ -1407,6 +1421,7 @@ class VaultLockManagerTest {
vaultSdkSource.initializeCrypto(
userId = USER_ID,
request = InitUserCryptoRequest(
userId = USER_ID,
kdfParams = kdf,
email = email,
privateKey = privateKey,
@@ -1465,6 +1480,7 @@ class VaultLockManagerTest {
vaultSdkSource.initializeCrypto(
userId = USER_ID,
request = InitUserCryptoRequest(
userId = USER_ID,
kdfParams = kdf,
email = email,
privateKey = privateKey,
@@ -1589,6 +1605,7 @@ class VaultLockManagerTest {
vaultSdkSource.initializeCrypto(
userId = userId,
request = InitUserCryptoRequest(
userId = userId,
kdfParams = kdf,
email = email,
privateKey = privateKey,
@@ -1634,6 +1651,7 @@ class VaultLockManagerTest {
vaultSdkSource.initializeCrypto(
userId = userId,
request = InitUserCryptoRequest(
userId = userId,
kdfParams = kdf,
email = email,
privateKey = privateKey,
@@ -1668,6 +1686,7 @@ class VaultLockManagerTest {
vaultSdkSource.initializeCrypto(
userId = userId,
request = InitUserCryptoRequest(
userId = userId,
kdfParams = kdf,
email = email,
privateKey = privateKey,
@@ -21,6 +21,7 @@ import com.bitwarden.vault.CipherType
import com.bitwarden.vault.FieldType
import com.bitwarden.vault.UriMatchType
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockEncryptionContext
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockSdkAttachment
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockSdkCard
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockSdkCipher
@@ -53,7 +54,9 @@ class VaultSdkCipherExtensionsTest {
fun `toEncryptedNetworkCipherResponse should convert an Sdk Cipher to a cipher`() {
val sdkCipher = createMockSdkCipher(number = 1, clock = FIXED_CLOCK)
val result = sdkCipher.toEncryptedNetworkCipherResponse()
val result = sdkCipher.toEncryptedNetworkCipherResponse(
encryptedFor = "mockEncryptedFor-1",
)
assertEquals(
createMockCipher(
@@ -67,7 +70,9 @@ class VaultSdkCipherExtensionsTest {
@Test
fun `toEncryptedNetworkCipher should convert an Sdk Cipher to a Network Cipher`() {
val sdkCipher = createMockSdkCipher(number = 1, clock = FIXED_CLOCK)
val syncCipher = sdkCipher.toEncryptedNetworkCipher()
val syncCipher = sdkCipher.toEncryptedNetworkCipher(
encryptedFor = "mockEncryptedFor-1",
)
assertEquals(
createMockCipherJsonRequest(
number = 1,
@@ -343,4 +348,30 @@ class VaultSdkCipherExtensionsTest {
list.sortAlphabetically(),
)
}
@Suppress("MaxLineLength")
@Test
fun `EncryptionContext toEncryptedNetworkCipher should convert an EncryptionContext to a Network Cipher`() {
val encryptionContext = createMockEncryptionContext(number = 1)
assertEquals(
createMockCipherJsonRequest(
number = 1,
login = createMockLogin(number = 1, uri = null),
),
encryptionContext.toEncryptedNetworkCipher(),
)
}
@Suppress("MaxLineLength")
@Test
fun `EncryptionContext toEncryptedNetworkCipherResponse should convert an EncryptionContext to a cipher`() {
val encryptionContext = createMockEncryptionContext(number = 1)
assertEquals(
createMockCipher(
number = 1,
login = createMockLogin(number = 1, uri = null),
),
encryptionContext.toEncryptedNetworkCipherResponse(),
)
}
}
+1 -1
View File
@@ -25,7 +25,7 @@ androidxSplash = "1.1.0-rc01"
androidXAppCompat = "1.7.0"
androdixAutofill = "1.1.0"
androidxWork = "2.10.1"
bitwardenSdk = "1.0.0-20250418.073303-151"
bitwardenSdk = "1.0.0-20250602.132903-199"
crashlytics = "3.0.3"
detekt = "1.23.8"
firebaseBom = "33.14.0"
@@ -23,6 +23,7 @@ import java.time.ZonedDateTime
* @property isFavorite If the cipher is a favorite.
* @property card The card of the cipher.
* @property key The key of the cipher (nullable).
* @property encryptedFor ID of the user who the cipher is encrypted by.
*/
@Serializable
data class CipherJsonRequest(
@@ -77,4 +78,7 @@ data class CipherJsonRequest(
@SerialName("key")
val key: String?,
@SerialName("encryptedFor")
val encryptedFor: String?,
)
@@ -438,6 +438,8 @@ data class SyncResponseJson(
* @property shouldViewPassword If the password can be viewed for the cipher.
* @property isFavorite If the cipher is a favorite.
* @property card The card of the cipher.
* @property key The key of the cipher (nullable).
* @property encryptedFor ID of the user who the cipher is encrypted by.
*/
@Serializable
data class Cipher(
@@ -518,6 +520,9 @@ data class SyncResponseJson(
@SerialName("key")
val key: String?,
@SerialName("encryptedFor")
val encryptedFor: String?,
) {
/**
* Represents an attachment in the vault response.
@@ -467,7 +467,8 @@ private const val CREATE_ATTACHMENT_SUCCESS_JSON = """
"publicKey": "mockPublicKey-1",
"privateKey": "mockPrivateKey-1",
"keyFingerprint": "mockKeyFingerprint-1"
}
},
"encryptedFor": "mockEncryptedFor-1"
}
}
"""
@@ -594,7 +595,8 @@ private const val CREATE_RESTORE_UPDATE_CIPHER_SUCCESS_JSON = """
"publicKey": "mockPublicKey-1",
"privateKey": "mockPrivateKey-1",
"keyFingerprint": "mockKeyFingerprint-1"
}
},
"encryptedFor": "mockEncryptedFor-1"
}
"""
@@ -315,7 +315,8 @@ private const val SYNC_SUCCESS_JSON = """
"publicKey": "mockPublicKey-1",
"privateKey": "mockPrivateKey-1",
"keyFingerprint": "mockKeyFingerprint-1"
}
},
"encryptedFor": "mockEncryptedFor-1"
}
],
"domains": {
@@ -29,6 +29,7 @@ fun createMockCipherJsonRequest(
reprompt: CipherRepromptTypeJson = CipherRepromptTypeJson.NONE,
lastKnownRevisionDate: ZonedDateTime? = ZonedDateTime.parse("2023-10-27T12:00:00Z"),
key: String? = "mockKey-$number",
encryptedFor: String? = "mockEncryptedFor-$number",
): CipherJsonRequest =
CipherJsonRequest(
attachments = attachments,
@@ -48,4 +49,5 @@ fun createMockCipherJsonRequest(
reprompt = reprompt,
lastKnownRevisionDate = lastKnownRevisionDate,
key = key,
encryptedFor = encryptedFor,
)
@@ -43,6 +43,7 @@ fun createMockCipher(
shouldOrganizationUseTotp: Boolean = false,
shouldViewPassword: Boolean = false,
key: String? = "mockKey-$number",
encryptedFor: String? = "mockEncryptedFor-$number",
): SyncResponseJson.Cipher =
SyncResponseJson.Cipher(
id = id,
@@ -70,6 +71,7 @@ fun createMockCipher(
shouldOrganizationUseTotp = shouldOrganizationUseTotp,
shouldViewPassword = shouldViewPassword,
key = key,
encryptedFor = encryptedFor,
)
/**