diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepository.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepository.kt index 0a01adc505..6b916bee65 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepository.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepository.kt @@ -24,6 +24,7 @@ import com.x8bit.bitwarden.data.vault.repository.model.DeleteSendResult import com.x8bit.bitwarden.data.vault.repository.model.DomainsData import com.x8bit.bitwarden.data.vault.repository.model.ExportVaultDataResult import com.x8bit.bitwarden.data.vault.repository.model.GenerateTotpResult +import com.x8bit.bitwarden.data.vault.repository.model.ImportCxfPayloadResult import com.x8bit.bitwarden.data.vault.repository.model.RemovePasswordSendResult import com.x8bit.bitwarden.data.vault.repository.model.SendData import com.x8bit.bitwarden.data.vault.repository.model.SyncVaultDataResult @@ -258,6 +259,13 @@ interface VaultRepository : CipherManager, VaultLockManager { restrictedTypes: List, ): ExportVaultDataResult + /** + * Attempt to import a CXF payload. + * + * @param payload The CXF payload to import. + */ + suspend fun importCxfPayload(payload: String): ImportCxfPayloadResult + /** * Flow that represents the data for a specific vault list item as found by ID. This may emit * `null` if the item cannot be found. diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt index 3a1e429b6e..2363eea097 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt @@ -73,6 +73,7 @@ import com.x8bit.bitwarden.data.vault.repository.model.DeleteSendResult import com.x8bit.bitwarden.data.vault.repository.model.DomainsData import com.x8bit.bitwarden.data.vault.repository.model.ExportVaultDataResult import com.x8bit.bitwarden.data.vault.repository.model.GenerateTotpResult +import com.x8bit.bitwarden.data.vault.repository.model.ImportCxfPayloadResult import com.x8bit.bitwarden.data.vault.repository.model.RemovePasswordSendResult import com.x8bit.bitwarden.data.vault.repository.model.SendData import com.x8bit.bitwarden.data.vault.repository.model.SyncVaultDataResult @@ -971,6 +972,20 @@ class VaultRepositoryImpl( ) } + override suspend fun importCxfPayload(payload: String): ImportCxfPayloadResult { + val userId = activeUserId + ?: return ImportCxfPayloadResult.Error(error = NoActiveUserException()) + return vaultSdkSource + .importCxf( + userId = userId, + payload = payload, + ) + .fold( + onSuccess = { ImportCxfPayloadResult.Success(it) }, + onFailure = { ImportCxfPayloadResult.Error(error = it) }, + ) + } + /** * Checks if the given [userId] has an associated encrypted PIN key but not a pin-protected user * key. This indicates a scenario in which a user has requested PIN unlocking but requires diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/model/ImportCxfPayloadResult.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/model/ImportCxfPayloadResult.kt new file mode 100644 index 0000000000..19c2c20aef --- /dev/null +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/model/ImportCxfPayloadResult.kt @@ -0,0 +1,21 @@ +package com.x8bit.bitwarden.data.vault.repository.model + +import com.bitwarden.vault.Cipher + +/** + * Models result of the vault data being imported from a CXF payload. + */ +sealed class ImportCxfPayloadResult { + + /** + * The vault data has been successfully imported. + */ + data class Success(val ciphers: List) : ImportCxfPayloadResult() + + /** + * There was an error importing the vault data. + * + * @param error The error that occurred during import. + */ + data class Error(val error: Throwable) : ImportCxfPayloadResult() +} diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt index c4fa67b049..275c47d0da 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt @@ -92,6 +92,7 @@ import com.x8bit.bitwarden.data.vault.repository.model.DeleteSendResult import com.x8bit.bitwarden.data.vault.repository.model.DomainsData import com.x8bit.bitwarden.data.vault.repository.model.ExportVaultDataResult import com.x8bit.bitwarden.data.vault.repository.model.GenerateTotpResult +import com.x8bit.bitwarden.data.vault.repository.model.ImportCxfPayloadResult import com.x8bit.bitwarden.data.vault.repository.model.RemovePasswordSendResult import com.x8bit.bitwarden.data.vault.repository.model.SendData import com.x8bit.bitwarden.data.vault.repository.model.SyncVaultDataResult @@ -4255,6 +4256,48 @@ class VaultRepositoryTest { ) } + @Test + fun `importCxfPayload should return success result`() = runTest { + val userId = "mockId-1" + val payload = "payload" + val ciphers = listOf(createMockSdkCipher(number = 1)) + fakeAuthDiskSource.userState = MOCK_USER_STATE + + coEvery { + vaultSdkSource.importCxf( + userId = userId, + payload = payload, + ) + } returns ciphers.asSuccess() + val result = vaultRepository.importCxfPayload(payload) + + assertEquals( + ImportCxfPayloadResult.Success(ciphers), + result, + ) + } + + @Test + fun `importCxfPayload should return error result`() = runTest { + val userId = "mockId-1" + val payload = "payload" + val expected = Throwable() + fakeAuthDiskSource.userState = MOCK_USER_STATE + + coEvery { + vaultSdkSource.importCxf( + userId = userId, + payload = payload, + ) + } returns expected.asFailure() + val result = vaultRepository.importCxfPayload(payload) + + assertEquals( + ImportCxfPayloadResult.Error(expected), + result, + ) + } + @Test fun `silentlyDiscoverCredentials should return result`() = runTest { val userId = "userId"