mirror of
https://github.com/bitwarden/android.git
synced 2024-11-26 19:36:18 +03:00
Add flow for creating attachments (#777)
This commit is contained in:
parent
3e9852e9e7
commit
465cce42f0
14 changed files with 822 additions and 8 deletions
|
@ -1,8 +1,11 @@
|
|||
package com.x8bit.bitwarden.data.vault.datasource.network.api
|
||||
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.AttachmentJsonRequest
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.AttachmentJsonResponse
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.CipherJsonRequest
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.ShareCipherJsonRequest
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||
import okhttp3.MultipartBody
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.DELETE
|
||||
import retrofit2.http.POST
|
||||
|
@ -20,6 +23,25 @@ interface CiphersApi {
|
|||
@POST("ciphers")
|
||||
suspend fun createCipher(@Body body: CipherJsonRequest): Result<SyncResponseJson.Cipher>
|
||||
|
||||
/**
|
||||
* Associates an attachment with a cipher.
|
||||
*/
|
||||
@POST("ciphers/{cipherId}/attachment/v2")
|
||||
suspend fun createAttachment(
|
||||
@Path("cipherId") cipherId: String,
|
||||
@Body body: AttachmentJsonRequest,
|
||||
): Result<AttachmentJsonResponse>
|
||||
|
||||
/**
|
||||
* Uploads the attachment associated with a cipher.
|
||||
*/
|
||||
@POST("ciphers/{cipherId}/attachment/{attachmentId}")
|
||||
suspend fun uploadAttachment(
|
||||
@Path("cipherId") cipherId: String,
|
||||
@Path("attachmentId") attachmentId: String,
|
||||
@Body body: MultipartBody,
|
||||
): Result<Unit>
|
||||
|
||||
/**
|
||||
* Updates a cipher.
|
||||
*/
|
||||
|
|
|
@ -28,9 +28,17 @@ object VaultNetworkModule {
|
|||
fun provideCiphersService(
|
||||
retrofits: Retrofits,
|
||||
json: Json,
|
||||
clock: Clock,
|
||||
): CiphersService = CiphersServiceImpl(
|
||||
azureApi = retrofits
|
||||
.staticRetrofitBuilder
|
||||
// This URL will be overridden dynamically
|
||||
.baseUrl("https://www.bitwarden.com")
|
||||
.build()
|
||||
.create(),
|
||||
ciphersApi = retrofits.authenticatedApiRetrofit.create(),
|
||||
json = json,
|
||||
clock = clock,
|
||||
)
|
||||
|
||||
@Provides
|
||||
|
@ -43,7 +51,7 @@ object VaultNetworkModule {
|
|||
azureApi = retrofits
|
||||
.staticRetrofitBuilder
|
||||
// This URL will be overridden dynamically
|
||||
.baseUrl("https://www.bitwaredn.com")
|
||||
.baseUrl("https://www.bitwarden.com")
|
||||
.build()
|
||||
.create(),
|
||||
sendsApi = retrofits.authenticatedApiRetrofit.create(),
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
package com.x8bit.bitwarden.data.vault.datasource.network.model
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* Represents a request to create an attachment.
|
||||
*/
|
||||
@Serializable
|
||||
data class AttachmentJsonRequest(
|
||||
@SerialName("fileName")
|
||||
val fileName: String,
|
||||
|
||||
@SerialName("key")
|
||||
val key: String,
|
||||
|
||||
@SerialName("fileSize")
|
||||
val fileSize: String,
|
||||
)
|
|
@ -0,0 +1,22 @@
|
|||
package com.x8bit.bitwarden.data.vault.datasource.network.model
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* Represents the JSON response from creating a new attachment.
|
||||
*/
|
||||
@Serializable
|
||||
data class AttachmentJsonResponse(
|
||||
@SerialName("attachmentId")
|
||||
val attachmentId: String,
|
||||
|
||||
@SerialName("url")
|
||||
val url: String,
|
||||
|
||||
@SerialName("fileUploadType")
|
||||
val fileUploadType: FileUploadType,
|
||||
|
||||
@SerialName("cipherResponse")
|
||||
val cipherResponse: SyncResponseJson.Cipher,
|
||||
)
|
|
@ -1,5 +1,7 @@
|
|||
package com.x8bit.bitwarden.data.vault.datasource.network.service
|
||||
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.AttachmentJsonRequest
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.AttachmentJsonResponse
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.CipherJsonRequest
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.ShareCipherJsonRequest
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||
|
@ -14,6 +16,22 @@ interface CiphersService {
|
|||
*/
|
||||
suspend fun createCipher(body: CipherJsonRequest): Result<SyncResponseJson.Cipher>
|
||||
|
||||
/**
|
||||
* Attempt to upload an attachment file.
|
||||
*/
|
||||
suspend fun uploadAttachment(
|
||||
attachmentJsonResponse: AttachmentJsonResponse,
|
||||
encryptedFile: ByteArray,
|
||||
): Result<SyncResponseJson.Cipher>
|
||||
|
||||
/**
|
||||
* Attempt to create an attachment.
|
||||
*/
|
||||
suspend fun createAttachment(
|
||||
cipherId: String,
|
||||
body: AttachmentJsonRequest,
|
||||
): Result<AttachmentJsonResponse>
|
||||
|
||||
/**
|
||||
* Attempt to update a cipher.
|
||||
*/
|
||||
|
|
|
@ -1,21 +1,88 @@
|
|||
package com.x8bit.bitwarden.data.vault.datasource.network.service
|
||||
|
||||
import androidx.core.net.toUri
|
||||
import com.x8bit.bitwarden.data.platform.datasource.network.model.toBitwardenError
|
||||
import com.x8bit.bitwarden.data.platform.datasource.network.util.parseErrorBodyOrNull
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.api.AzureApi
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.api.CiphersApi
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.AttachmentJsonRequest
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.AttachmentJsonResponse
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.CipherJsonRequest
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.FileUploadType
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.ShareCipherJsonRequest
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.UpdateCipherResponseJson
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import java.time.Clock
|
||||
import java.time.ZoneOffset
|
||||
import java.time.ZonedDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
class CiphersServiceImpl constructor(
|
||||
class CiphersServiceImpl(
|
||||
private val azureApi: AzureApi,
|
||||
private val ciphersApi: CiphersApi,
|
||||
private val json: Json,
|
||||
private val clock: Clock,
|
||||
) : CiphersService {
|
||||
override suspend fun createCipher(body: CipherJsonRequest): Result<SyncResponseJson.Cipher> =
|
||||
ciphersApi.createCipher(body = body)
|
||||
|
||||
override suspend fun createAttachment(
|
||||
cipherId: String,
|
||||
body: AttachmentJsonRequest,
|
||||
): Result<AttachmentJsonResponse> =
|
||||
ciphersApi.createAttachment(
|
||||
cipherId = cipherId,
|
||||
body = body,
|
||||
)
|
||||
|
||||
override suspend fun uploadAttachment(
|
||||
attachmentJsonResponse: AttachmentJsonResponse,
|
||||
encryptedFile: ByteArray,
|
||||
): Result<SyncResponseJson.Cipher> {
|
||||
val cipher = attachmentJsonResponse.cipherResponse
|
||||
return when (attachmentJsonResponse.fileUploadType) {
|
||||
FileUploadType.DIRECT -> {
|
||||
ciphersApi.uploadAttachment(
|
||||
cipherId = requireNotNull(cipher.id),
|
||||
attachmentId = attachmentJsonResponse.attachmentId,
|
||||
body = MultipartBody
|
||||
.Builder(
|
||||
boundary = "--BWMobileFormBoundary${clock.instant().toEpochMilli()}",
|
||||
)
|
||||
.addPart(
|
||||
part = MultipartBody.Part.createFormData(
|
||||
body = encryptedFile.toRequestBody(
|
||||
contentType = "application/octet-stream".toMediaType(),
|
||||
),
|
||||
name = "data",
|
||||
filename = cipher
|
||||
.attachments
|
||||
?.find { it.id == attachmentJsonResponse.attachmentId }
|
||||
?.fileName,
|
||||
),
|
||||
)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
|
||||
FileUploadType.AZURE -> {
|
||||
azureApi.uploadAzureBlob(
|
||||
url = attachmentJsonResponse.url,
|
||||
date = DateTimeFormatter
|
||||
.RFC_1123_DATE_TIME
|
||||
.format(ZonedDateTime.ofInstant(clock.instant(), ZoneOffset.UTC)),
|
||||
version = attachmentJsonResponse.url.toUri().getQueryParameter("sv"),
|
||||
body = encryptedFile.toRequestBody(),
|
||||
)
|
||||
}
|
||||
}
|
||||
.map { cipher }
|
||||
}
|
||||
|
||||
override suspend fun updateCipher(
|
||||
cipherId: String,
|
||||
body: CipherJsonRequest,
|
||||
|
|
|
@ -11,6 +11,7 @@ import com.bitwarden.crypto.Kdf
|
|||
import com.x8bit.bitwarden.data.platform.repository.model.DataState
|
||||
import com.x8bit.bitwarden.data.vault.manager.VaultLockManager
|
||||
import com.x8bit.bitwarden.data.vault.manager.model.VerificationCodeItem
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateAttachmentResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateSendResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.DeleteAttachmentResult
|
||||
|
@ -182,6 +183,17 @@ interface VaultRepository : VaultLockManager {
|
|||
*/
|
||||
suspend fun createCipher(cipherView: CipherView): CreateCipherResult
|
||||
|
||||
/**
|
||||
* Attempt to create an attachment for the given [cipherView].
|
||||
*/
|
||||
suspend fun createAttachment(
|
||||
cipherId: String,
|
||||
cipherView: CipherView,
|
||||
fileSizeBytes: String,
|
||||
fileName: String,
|
||||
fileUri: Uri,
|
||||
): CreateAttachmentResult
|
||||
|
||||
/**
|
||||
* Attempt to delete a cipher.
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.x8bit.bitwarden.data.vault.repository
|
||||
|
||||
import android.net.Uri
|
||||
import com.bitwarden.core.AttachmentView
|
||||
import com.bitwarden.core.CipherType
|
||||
import com.bitwarden.core.CipherView
|
||||
import com.bitwarden.core.CollectionView
|
||||
|
@ -26,6 +27,7 @@ import com.x8bit.bitwarden.data.platform.repository.util.updateToPendingOrLoadin
|
|||
import com.x8bit.bitwarden.data.platform.util.asFailure
|
||||
import com.x8bit.bitwarden.data.platform.util.flatMap
|
||||
import com.x8bit.bitwarden.data.vault.datasource.disk.VaultDiskSource
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.AttachmentJsonRequest
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.ShareCipherJsonRequest
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.UpdateCipherResponseJson
|
||||
|
@ -38,6 +40,7 @@ import com.x8bit.bitwarden.data.vault.manager.FileManager
|
|||
import com.x8bit.bitwarden.data.vault.manager.TotpCodeManager
|
||||
import com.x8bit.bitwarden.data.vault.manager.VaultLockManager
|
||||
import com.x8bit.bitwarden.data.vault.manager.model.VerificationCodeItem
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateAttachmentResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateSendResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.DeleteAttachmentResult
|
||||
|
@ -56,6 +59,7 @@ import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult
|
|||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedNetworkCipher
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedNetworkCipherResponse
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedNetworkSend
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedSdkCipher
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedSdkCipherList
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedSdkCollectionList
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedSdkFolderList
|
||||
|
@ -643,6 +647,71 @@ class VaultRepositoryImpl(
|
|||
)
|
||||
}
|
||||
|
||||
override suspend fun createAttachment(
|
||||
cipherId: String,
|
||||
cipherView: CipherView,
|
||||
fileSizeBytes: String,
|
||||
fileName: String,
|
||||
fileUri: Uri,
|
||||
): CreateAttachmentResult {
|
||||
val userId = requireNotNull(activeUserId)
|
||||
val attachmentView = AttachmentView(
|
||||
id = null,
|
||||
url = null,
|
||||
size = fileSizeBytes,
|
||||
sizeName = null,
|
||||
fileName = fileName,
|
||||
key = null,
|
||||
)
|
||||
return vaultSdkSource
|
||||
.encryptCipher(
|
||||
userId = userId,
|
||||
cipherView = cipherView,
|
||||
)
|
||||
.flatMap { cipher ->
|
||||
vaultSdkSource.encryptAttachment(
|
||||
userId = userId,
|
||||
cipher = cipher,
|
||||
attachmentView = attachmentView,
|
||||
fileBuffer = fileManager.uriToByteArray(fileUri = fileUri),
|
||||
)
|
||||
}
|
||||
.flatMap { attachmentEncryptResult ->
|
||||
ciphersService
|
||||
.createAttachment(
|
||||
cipherId = cipherId,
|
||||
body = AttachmentJsonRequest(
|
||||
// We know these values are present because
|
||||
// - the filename/size are passed into the function
|
||||
// - the SDK call fills in the key
|
||||
fileName = requireNotNull(attachmentEncryptResult.attachment.fileName),
|
||||
key = requireNotNull(attachmentEncryptResult.attachment.key),
|
||||
fileSize = requireNotNull(attachmentEncryptResult.attachment.size),
|
||||
),
|
||||
)
|
||||
.flatMap { attachmentJsonResponse ->
|
||||
ciphersService.uploadAttachment(
|
||||
attachmentJsonResponse = attachmentJsonResponse,
|
||||
encryptedFile = attachmentEncryptResult.contents,
|
||||
)
|
||||
}
|
||||
}
|
||||
.onSuccess {
|
||||
// Save the send immediately, regardless of whether the decrypt succeeds
|
||||
vaultDiskSource.saveCipher(userId = userId, cipher = it)
|
||||
}
|
||||
.flatMap {
|
||||
vaultSdkSource.decryptCipher(
|
||||
userId = userId,
|
||||
cipher = it.toEncryptedSdkCipher(),
|
||||
)
|
||||
}
|
||||
.fold(
|
||||
onFailure = { CreateAttachmentResult.Error },
|
||||
onSuccess = { CreateAttachmentResult.Success(it) },
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun createSend(
|
||||
sendView: SendView,
|
||||
fileUri: Uri?,
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package com.x8bit.bitwarden.data.vault.repository.model
|
||||
|
||||
import com.bitwarden.core.CipherView
|
||||
|
||||
/**
|
||||
* Models result of creating an attachment.
|
||||
*/
|
||||
sealed class CreateAttachmentResult {
|
||||
|
||||
/**
|
||||
* Attachment created successfully.
|
||||
*/
|
||||
data class Success(
|
||||
val cipherView: CipherView,
|
||||
) : CreateAttachmentResult()
|
||||
|
||||
/**
|
||||
* Generic error while creating an attachment.
|
||||
*/
|
||||
data object Error : CreateAttachmentResult()
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.x8bit.bitwarden.data.vault.datasource.network.model
|
||||
|
||||
import com.bitwarden.core.AttachmentEncryptResult
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockSdkAttachment
|
||||
|
||||
/**
|
||||
* Create a mock [AttachmentEncryptResult] with a given [number].
|
||||
*/
|
||||
fun createMockAttachmentEncryptResult(number: Int): AttachmentEncryptResult =
|
||||
AttachmentEncryptResult(
|
||||
attachment = createMockSdkAttachment(number = 1),
|
||||
contents = byteArrayOf(number.toByte()),
|
||||
)
|
|
@ -0,0 +1,11 @@
|
|||
package com.x8bit.bitwarden.data.vault.datasource.network.model
|
||||
|
||||
/**
|
||||
* Create a mock [CipherJsonRequest] with a given [number].
|
||||
*/
|
||||
fun createMockAttachmentJsonRequest(number: Int): AttachmentJsonRequest =
|
||||
AttachmentJsonRequest(
|
||||
fileName = "mockFileName-$number",
|
||||
key = "mockKey-$number",
|
||||
fileSize = "1000",
|
||||
)
|
|
@ -0,0 +1,15 @@
|
|||
package com.x8bit.bitwarden.data.vault.datasource.network.model
|
||||
|
||||
/**
|
||||
* Create a mock [AttachmentJsonResponse] with a given [number].
|
||||
*/
|
||||
fun createMockAttachmentJsonResponse(
|
||||
number: Int,
|
||||
fileUploadType: FileUploadType = FileUploadType.AZURE,
|
||||
): AttachmentJsonResponse =
|
||||
AttachmentJsonResponse(
|
||||
attachmentId = "mockAttachmentId-$number",
|
||||
url = "mockUrl-$number",
|
||||
fileUploadType = fileUploadType,
|
||||
cipherResponse = createMockCipher(number = number),
|
||||
)
|
|
@ -1,25 +1,56 @@
|
|||
package com.x8bit.bitwarden.data.vault.datasource.network.service
|
||||
|
||||
import android.net.Uri
|
||||
import com.x8bit.bitwarden.data.platform.base.BaseServiceTest
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.api.AzureApi
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.api.CiphersApi
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.FileUploadType
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.ShareCipherJsonRequest
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.UpdateCipherResponseJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockAttachmentJsonRequest
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockAttachmentJsonResponse
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockCipher
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockCipherJsonRequest
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.unmockkStatic
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import okhttp3.mockwebserver.MockResponse
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import retrofit2.create
|
||||
import java.time.Clock
|
||||
import java.time.Instant
|
||||
import java.time.ZoneOffset
|
||||
|
||||
class CiphersServiceTest : BaseServiceTest() {
|
||||
private val clock: Clock = Clock.fixed(
|
||||
Instant.parse("2023-10-27T12:00:00Z"),
|
||||
ZoneOffset.UTC,
|
||||
)
|
||||
private val azureApi: AzureApi = retrofit.create()
|
||||
private val ciphersApi: CiphersApi = retrofit.create()
|
||||
|
||||
private val ciphersService: CiphersService = CiphersServiceImpl(
|
||||
azureApi = azureApi,
|
||||
ciphersApi = ciphersApi,
|
||||
json = json,
|
||||
clock = clock,
|
||||
)
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
mockkStatic(Uri::class)
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun tearDown() {
|
||||
unmockkStatic(Uri::class)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `createCipher should return the correct response`() = runTest {
|
||||
server.enqueue(MockResponse().setBody(CREATE_UPDATE_CIPHER_SUCCESS_JSON))
|
||||
|
@ -32,6 +63,56 @@ class CiphersServiceTest : BaseServiceTest() {
|
|||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `createAttachment should return the correct response`() = runTest {
|
||||
server.enqueue(MockResponse().setBody(CREATE_ATTACHMENT_SUCCESS_JSON))
|
||||
val result = ciphersService.createAttachment(
|
||||
cipherId = "mockId-1",
|
||||
body = createMockAttachmentJsonRequest(number = 1),
|
||||
)
|
||||
assertEquals(
|
||||
createMockAttachmentJsonResponse(number = 1),
|
||||
result.getOrThrow(),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `uploadAttachment with Azure uploadFile success should return cipher`() = runTest {
|
||||
setupMockUri(url = "mockUrl-1", queryParams = mapOf("sv" to "2024-04-03"))
|
||||
val mockCipher = createMockCipher(number = 1)
|
||||
val attachmentJsonResponse = createMockAttachmentJsonResponse(
|
||||
number = 1,
|
||||
fileUploadType = FileUploadType.AZURE,
|
||||
)
|
||||
val encryptedFile = byteArrayOf()
|
||||
server.enqueue(MockResponse().setResponseCode(201))
|
||||
|
||||
val result = ciphersService.uploadAttachment(
|
||||
attachmentJsonResponse = attachmentJsonResponse,
|
||||
encryptedFile = encryptedFile,
|
||||
)
|
||||
|
||||
assertEquals(mockCipher, result.getOrThrow())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `uploadAttachment with Direct uploadFile success should return cipher`() = runTest {
|
||||
val mockCipher = createMockCipher(number = 1)
|
||||
val attachmentJsonResponse = createMockAttachmentJsonResponse(
|
||||
number = 1,
|
||||
fileUploadType = FileUploadType.DIRECT,
|
||||
)
|
||||
val encryptedFile = byteArrayOf()
|
||||
server.enqueue(MockResponse().setResponseCode(201))
|
||||
|
||||
val result = ciphersService.uploadAttachment(
|
||||
attachmentJsonResponse = attachmentJsonResponse,
|
||||
encryptedFile = encryptedFile,
|
||||
)
|
||||
|
||||
assertEquals(mockCipher, result.getOrThrow())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `updateCipher with success response should return a Success with the correct cipher`() =
|
||||
runTest {
|
||||
|
@ -123,6 +204,116 @@ class CiphersServiceTest : BaseServiceTest() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun setupMockUri(
|
||||
url: String,
|
||||
queryParams: Map<String, String>,
|
||||
): Uri {
|
||||
val mockUri = mockk<Uri> {
|
||||
queryParams.forEach {
|
||||
every { getQueryParameter(it.key) } returns it.value
|
||||
}
|
||||
}
|
||||
every { Uri.parse(url) } returns mockUri
|
||||
return mockUri
|
||||
}
|
||||
|
||||
private const val CREATE_ATTACHMENT_SUCCESS_JSON = """
|
||||
{
|
||||
"attachmentId":"mockAttachmentId-1",
|
||||
"url":"mockUrl-1",
|
||||
"fileUploadType":1,
|
||||
"cipherResponse":{
|
||||
"notes": "mockNotes-1",
|
||||
"attachments": [
|
||||
{
|
||||
"fileName": "mockFileName-1",
|
||||
"size": 1,
|
||||
"sizeName": "mockSizeName-1",
|
||||
"id": "mockId-1",
|
||||
"url": "mockUrl-1",
|
||||
"key": "mockKey-1"
|
||||
}
|
||||
],
|
||||
"organizationUseTotp": false,
|
||||
"reprompt": 0,
|
||||
"edit": false,
|
||||
"passwordHistory": [
|
||||
{
|
||||
"password": "mockPassword-1",
|
||||
"lastUsedDate": "2023-10-27T12:00:00.00Z"
|
||||
}
|
||||
],
|
||||
"revisionDate": "2023-10-27T12:00:00.00Z",
|
||||
"type": 1,
|
||||
"login": {
|
||||
"uris": [
|
||||
{
|
||||
"match": 1,
|
||||
"uri": "mockUri-1"
|
||||
}
|
||||
],
|
||||
"totp": "mockTotp-1",
|
||||
"password": "mockPassword-1",
|
||||
"passwordRevisionDate": "2023-10-27T12:00:00.00Z",
|
||||
"autofillOnPageLoad": false,
|
||||
"uri": "mockUri-1",
|
||||
"username": "mockUsername-1"
|
||||
},
|
||||
"creationDate": "2023-10-27T12:00:00.00Z",
|
||||
"secureNote": {
|
||||
"type": 0
|
||||
},
|
||||
"folderId": "mockFolderId-1",
|
||||
"organizationId": "mockOrganizationId-1",
|
||||
"deletedDate": "2023-10-27T12:00:00.00Z",
|
||||
"identity": {
|
||||
"passportNumber": "mockPassportNumber-1",
|
||||
"lastName": "mockLastName-1",
|
||||
"address3": "mockAddress3-1",
|
||||
"address2": "mockAddress2-1",
|
||||
"city": "mockCity-1",
|
||||
"country": "mockCountry-1",
|
||||
"address1": "mockAddress1-1",
|
||||
"postalCode": "mockPostalCode-1",
|
||||
"title": "mockTitle-1",
|
||||
"ssn": "mockSsn-1",
|
||||
"firstName": "mockFirstName-1",
|
||||
"phone": "mockPhone-1",
|
||||
"middleName": "mockMiddleName-1",
|
||||
"company": "mockCompany-1",
|
||||
"licenseNumber": "mockLicenseNumber-1",
|
||||
"state": "mockState-1",
|
||||
"email": "mockEmail-1",
|
||||
"username": "mockUsername-1"
|
||||
},
|
||||
"collectionIds": [
|
||||
"mockCollectionId-1"
|
||||
],
|
||||
"name": "mockName-1",
|
||||
"id": "mockId-1"
|
||||
"fields": [
|
||||
{
|
||||
"linkedId": 100,
|
||||
"name": "mockName-1",
|
||||
"type": 1,
|
||||
"value": "mockValue-1"
|
||||
}
|
||||
],
|
||||
"viewPassword": false,
|
||||
"favorite": false,
|
||||
"card": {
|
||||
"number": "mockNumber-1",
|
||||
"expMonth": "mockExpMonth-1",
|
||||
"code": "mockCode-1",
|
||||
"expYear": "mockExpirationYear-1",
|
||||
"cardholderName": "mockCardholderName-1",
|
||||
"brand": "mockBrand-1"
|
||||
},
|
||||
"key": "mockKey-1"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
private const val CREATE_UPDATE_CIPHER_SUCCESS_JSON = """
|
||||
{
|
||||
"notes": "mockNotes-1",
|
||||
|
|
|
@ -27,6 +27,7 @@ import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFl
|
|||
import com.x8bit.bitwarden.data.platform.util.asFailure
|
||||
import com.x8bit.bitwarden.data.platform.util.asSuccess
|
||||
import com.x8bit.bitwarden.data.vault.datasource.disk.VaultDiskSource
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.AttachmentJsonRequest
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.FileUploadType
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SendFileResponseJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SendTypeJson
|
||||
|
@ -34,6 +35,8 @@ import com.x8bit.bitwarden.data.vault.datasource.network.model.ShareCipherJsonRe
|
|||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.UpdateCipherResponseJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.UpdateSendResponseJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockAttachmentEncryptResult
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockAttachmentJsonResponse
|
||||
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.createMockCollection
|
||||
|
@ -48,6 +51,7 @@ import com.x8bit.bitwarden.data.vault.datasource.network.service.SendsService
|
|||
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.model.InitializeCryptoResult
|
||||
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.createMockCollectionView
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockFolderView
|
||||
|
@ -60,6 +64,7 @@ import com.x8bit.bitwarden.data.vault.manager.FileManager
|
|||
import com.x8bit.bitwarden.data.vault.manager.TotpCodeManager
|
||||
import com.x8bit.bitwarden.data.vault.manager.VaultLockManager
|
||||
import com.x8bit.bitwarden.data.vault.manager.model.VerificationCodeItem
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateAttachmentResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateSendResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.DeleteAttachmentResult
|
||||
|
@ -76,6 +81,7 @@ import com.x8bit.bitwarden.data.vault.repository.model.VaultData
|
|||
import com.x8bit.bitwarden.data.vault.repository.model.VaultState
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedNetworkCipherResponse
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedSdkCipher
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedSdkCipherList
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedSdkCollectionList
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedSdkFolderList
|
||||
|
@ -2367,6 +2373,332 @@ class VaultRepositoryTest {
|
|||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `createAttachment with encryptCipher failure should return CreateAttachmentResult Error`() =
|
||||
runTest {
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
val userId = "mockId-1"
|
||||
val cipherId = "cipherId-1"
|
||||
val mockUri = setupMockUri(url = "www.test.com")
|
||||
val mockCipherView = createMockCipherView(number = 1)
|
||||
val mockFileName = "mockFileName-1"
|
||||
val mockFileSize = "1"
|
||||
coEvery {
|
||||
vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView)
|
||||
} returns Throwable("Fail").asFailure()
|
||||
|
||||
val result = vaultRepository.createAttachment(
|
||||
cipherId = cipherId,
|
||||
cipherView = mockCipherView,
|
||||
fileSizeBytes = mockFileSize,
|
||||
fileName = mockFileName,
|
||||
fileUri = mockUri,
|
||||
)
|
||||
|
||||
assertEquals(CreateAttachmentResult.Error, result)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `createAttachment with encryptAttachment failure should return CreateAttachmentResult Error`() =
|
||||
runTest {
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
val userId = "mockId-1"
|
||||
val cipherId = "cipherId-1"
|
||||
val mockUri = setupMockUri(url = "www.test.com")
|
||||
val mockCipherView = createMockCipherView(number = 1)
|
||||
val mockCipher = createMockSdkCipher(number = 1)
|
||||
val mockFileName = "mockFileName-1"
|
||||
val mockFileSize = "1"
|
||||
val mockAttachmentView = createMockAttachmentView(number = 1).copy(
|
||||
sizeName = null,
|
||||
id = null,
|
||||
url = null,
|
||||
key = null,
|
||||
)
|
||||
val mockByteArray = byteArrayOf(1, 2)
|
||||
coEvery {
|
||||
vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView)
|
||||
} returns mockCipher.asSuccess()
|
||||
every { fileManager.uriToByteArray(fileUri = mockUri) } returns mockByteArray
|
||||
coEvery {
|
||||
vaultSdkSource.encryptAttachment(
|
||||
userId = userId,
|
||||
cipher = mockCipher,
|
||||
attachmentView = mockAttachmentView,
|
||||
fileBuffer = mockByteArray,
|
||||
)
|
||||
} returns Throwable("Fail").asFailure()
|
||||
|
||||
val result = vaultRepository.createAttachment(
|
||||
cipherId = cipherId,
|
||||
cipherView = mockCipherView,
|
||||
fileSizeBytes = mockFileSize,
|
||||
fileName = mockFileName,
|
||||
fileUri = mockUri,
|
||||
)
|
||||
|
||||
assertEquals(CreateAttachmentResult.Error, result)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `createAttachment with createAttachment failure should return CreateAttachmentResult Error`() =
|
||||
runTest {
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
val userId = "mockId-1"
|
||||
val cipherId = "cipherId-1"
|
||||
val mockUri = setupMockUri(url = "www.test.com")
|
||||
val mockCipherView = createMockCipherView(number = 1)
|
||||
val mockCipher = createMockSdkCipher(number = 1)
|
||||
val mockFileName = "mockFileName-1"
|
||||
val mockFileSize = "1"
|
||||
val mockAttachmentView = createMockAttachmentView(number = 1).copy(
|
||||
sizeName = null,
|
||||
id = null,
|
||||
url = null,
|
||||
key = null,
|
||||
)
|
||||
val mockByteArray = byteArrayOf(1, 2)
|
||||
val mockAttachmentEncryptResult = createMockAttachmentEncryptResult(number = 1)
|
||||
coEvery {
|
||||
vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView)
|
||||
} returns mockCipher.asSuccess()
|
||||
every { fileManager.uriToByteArray(fileUri = mockUri) } returns mockByteArray
|
||||
coEvery {
|
||||
vaultSdkSource.encryptAttachment(
|
||||
userId = userId,
|
||||
cipher = mockCipher,
|
||||
attachmentView = mockAttachmentView,
|
||||
fileBuffer = mockByteArray,
|
||||
)
|
||||
} returns mockAttachmentEncryptResult.asSuccess()
|
||||
coEvery {
|
||||
ciphersService.createAttachment(
|
||||
cipherId = cipherId,
|
||||
body = AttachmentJsonRequest(
|
||||
fileName = mockFileName,
|
||||
key = "mockKey-1",
|
||||
fileSize = mockFileSize,
|
||||
),
|
||||
)
|
||||
} returns Throwable("Fail").asFailure()
|
||||
|
||||
val result = vaultRepository.createAttachment(
|
||||
cipherId = cipherId,
|
||||
cipherView = mockCipherView,
|
||||
fileSizeBytes = mockFileSize,
|
||||
fileName = mockFileName,
|
||||
fileUri = mockUri,
|
||||
)
|
||||
|
||||
assertEquals(CreateAttachmentResult.Error, result)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `createAttachment with uploadAttachment failure should return CreateAttachmentResult Error`() =
|
||||
runTest {
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
val userId = "mockId-1"
|
||||
val cipherId = "cipherId-1"
|
||||
val mockUri = setupMockUri(url = "www.test.com")
|
||||
val mockCipherView = createMockCipherView(number = 1)
|
||||
val mockCipher = createMockSdkCipher(number = 1)
|
||||
val mockFileName = "mockFileName-1"
|
||||
val mockFileSize = "1"
|
||||
val mockAttachmentView = createMockAttachmentView(number = 1).copy(
|
||||
sizeName = null,
|
||||
id = null,
|
||||
url = null,
|
||||
key = null,
|
||||
)
|
||||
val mockByteArray = byteArrayOf(1, 2)
|
||||
val mockAttachmentEncryptResult = createMockAttachmentEncryptResult(number = 1)
|
||||
val mockAttachmentJsonResponse = createMockAttachmentJsonResponse(number = 1)
|
||||
coEvery {
|
||||
vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView)
|
||||
} returns mockCipher.asSuccess()
|
||||
every { fileManager.uriToByteArray(fileUri = mockUri) } returns mockByteArray
|
||||
coEvery {
|
||||
vaultSdkSource.encryptAttachment(
|
||||
userId = userId,
|
||||
cipher = mockCipher,
|
||||
attachmentView = mockAttachmentView,
|
||||
fileBuffer = mockByteArray,
|
||||
)
|
||||
} returns mockAttachmentEncryptResult.asSuccess()
|
||||
coEvery {
|
||||
ciphersService.createAttachment(
|
||||
cipherId = cipherId,
|
||||
body = AttachmentJsonRequest(
|
||||
fileName = mockFileName,
|
||||
key = "mockKey-1",
|
||||
fileSize = mockFileSize,
|
||||
),
|
||||
)
|
||||
} returns mockAttachmentJsonResponse.asSuccess()
|
||||
coEvery {
|
||||
ciphersService.uploadAttachment(
|
||||
attachmentJsonResponse = mockAttachmentJsonResponse,
|
||||
encryptedFile = mockAttachmentEncryptResult.contents,
|
||||
)
|
||||
} returns Throwable("Fail").asFailure()
|
||||
|
||||
val result = vaultRepository.createAttachment(
|
||||
cipherId = cipherId,
|
||||
cipherView = mockCipherView,
|
||||
fileSizeBytes = mockFileSize,
|
||||
fileName = mockFileName,
|
||||
fileUri = mockUri,
|
||||
)
|
||||
|
||||
assertEquals(CreateAttachmentResult.Error, result)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `createAttachment with decryptCipher failure should return CreateAttachmentResult Error`() =
|
||||
runTest {
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
val userId = "mockId-1"
|
||||
val cipherId = "cipherId-1"
|
||||
val mockUri = setupMockUri(url = "www.test.com")
|
||||
val mockCipherView = createMockCipherView(number = 1)
|
||||
val mockCipher = createMockSdkCipher(number = 1)
|
||||
val mockFileName = "mockFileName-1"
|
||||
val mockFileSize = "1"
|
||||
val mockAttachmentView = createMockAttachmentView(number = 1).copy(
|
||||
sizeName = null,
|
||||
id = null,
|
||||
url = null,
|
||||
key = null,
|
||||
)
|
||||
val mockByteArray = byteArrayOf(1, 2)
|
||||
val mockAttachmentEncryptResult = createMockAttachmentEncryptResult(number = 1)
|
||||
val mockAttachmentJsonResponse = createMockAttachmentJsonResponse(number = 1)
|
||||
val mockCipherResponse = createMockCipher(number = 1)
|
||||
coEvery {
|
||||
vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView)
|
||||
} returns mockCipher.asSuccess()
|
||||
every { fileManager.uriToByteArray(fileUri = mockUri) } returns mockByteArray
|
||||
coEvery {
|
||||
vaultSdkSource.encryptAttachment(
|
||||
userId = userId,
|
||||
cipher = mockCipher,
|
||||
attachmentView = mockAttachmentView,
|
||||
fileBuffer = mockByteArray,
|
||||
)
|
||||
} returns mockAttachmentEncryptResult.asSuccess()
|
||||
coEvery {
|
||||
ciphersService.createAttachment(
|
||||
cipherId = cipherId,
|
||||
body = AttachmentJsonRequest(
|
||||
fileName = mockFileName,
|
||||
key = "mockKey-1",
|
||||
fileSize = mockFileSize,
|
||||
),
|
||||
)
|
||||
} returns mockAttachmentJsonResponse.asSuccess()
|
||||
coEvery {
|
||||
ciphersService.uploadAttachment(
|
||||
attachmentJsonResponse = mockAttachmentJsonResponse,
|
||||
encryptedFile = mockAttachmentEncryptResult.contents,
|
||||
)
|
||||
} returns mockCipherResponse.asSuccess()
|
||||
coEvery {
|
||||
vaultDiskSource.saveCipher(userId = userId, cipher = mockCipherResponse)
|
||||
} just runs
|
||||
coEvery {
|
||||
vaultSdkSource.decryptCipher(
|
||||
userId = userId,
|
||||
cipher = mockCipherResponse.toEncryptedSdkCipher(),
|
||||
)
|
||||
} returns Throwable("Fail").asFailure()
|
||||
|
||||
val result = vaultRepository.createAttachment(
|
||||
cipherId = cipherId,
|
||||
cipherView = mockCipherView,
|
||||
fileSizeBytes = mockFileSize,
|
||||
fileName = mockFileName,
|
||||
fileUri = mockUri,
|
||||
)
|
||||
|
||||
assertEquals(CreateAttachmentResult.Error, result)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `createAttachment with createAttachment success should return CreateAttachmentResult Success`() =
|
||||
runTest {
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
val userId = "mockId-1"
|
||||
val cipherId = "cipherId-1"
|
||||
val mockUri = setupMockUri(url = "www.test.com")
|
||||
val mockCipherView = createMockCipherView(number = 1)
|
||||
val mockCipher = createMockSdkCipher(number = 1)
|
||||
val mockFileName = "mockFileName-1"
|
||||
val mockFileSize = "1"
|
||||
val mockAttachmentView = createMockAttachmentView(number = 1).copy(
|
||||
sizeName = null,
|
||||
id = null,
|
||||
url = null,
|
||||
key = null,
|
||||
)
|
||||
val mockByteArray = byteArrayOf(1, 2)
|
||||
val mockAttachmentEncryptResult = createMockAttachmentEncryptResult(number = 1)
|
||||
val mockAttachmentJsonResponse = createMockAttachmentJsonResponse(number = 1)
|
||||
val mockCipherResponse = createMockCipher(number = 1)
|
||||
coEvery {
|
||||
vaultSdkSource.encryptCipher(userId = userId, cipherView = mockCipherView)
|
||||
} returns mockCipher.asSuccess()
|
||||
every { fileManager.uriToByteArray(fileUri = mockUri) } returns mockByteArray
|
||||
coEvery {
|
||||
vaultSdkSource.encryptAttachment(
|
||||
userId = userId,
|
||||
cipher = mockCipher,
|
||||
attachmentView = mockAttachmentView,
|
||||
fileBuffer = mockByteArray,
|
||||
)
|
||||
} returns mockAttachmentEncryptResult.asSuccess()
|
||||
coEvery {
|
||||
ciphersService.createAttachment(
|
||||
cipherId = cipherId,
|
||||
body = AttachmentJsonRequest(
|
||||
fileName = mockFileName,
|
||||
key = "mockKey-1",
|
||||
fileSize = mockFileSize,
|
||||
),
|
||||
)
|
||||
} returns mockAttachmentJsonResponse.asSuccess()
|
||||
coEvery {
|
||||
ciphersService.uploadAttachment(
|
||||
attachmentJsonResponse = mockAttachmentJsonResponse,
|
||||
encryptedFile = mockAttachmentEncryptResult.contents,
|
||||
)
|
||||
} returns mockCipherResponse.asSuccess()
|
||||
coEvery {
|
||||
vaultDiskSource.saveCipher(userId = userId, cipher = mockCipherResponse)
|
||||
} just runs
|
||||
coEvery {
|
||||
vaultSdkSource.decryptCipher(
|
||||
userId = userId,
|
||||
cipher = mockCipherResponse.toEncryptedSdkCipher(),
|
||||
)
|
||||
} returns mockCipherView.asSuccess()
|
||||
|
||||
val result = vaultRepository.createAttachment(
|
||||
cipherId = cipherId,
|
||||
cipherView = mockCipherView,
|
||||
fileSizeBytes = mockFileSize,
|
||||
fileName = mockFileName,
|
||||
fileUri = mockUri,
|
||||
)
|
||||
|
||||
assertEquals(CreateAttachmentResult.Success(mockCipherView), result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `generateTotp should return a success result on getting a code`() = runTest {
|
||||
val totpResponse = TotpResponse("Testcode", 30u)
|
||||
|
@ -2728,12 +3060,6 @@ class VaultRepositoryTest {
|
|||
return mockUri
|
||||
}
|
||||
|
||||
private fun setupMockInstant(): Instant {
|
||||
val mockInstant = mockk<Instant>()
|
||||
every { Instant.now() } returns Instant.MIN
|
||||
return mockInstant
|
||||
}
|
||||
|
||||
//endregion Helper functions
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue