BIT-2403: Update process for moving item to organization (#1421)

This commit is contained in:
David Perez 2024-06-04 11:38:39 -05:00 committed by Álison Fernandes
parent 51d65f602d
commit 1dcfad4451
8 changed files with 71 additions and 7 deletions

View file

@ -355,6 +355,15 @@ interface VaultSdkSource {
time: DateTime,
): Result<TotpResponse>
/**
* Re-encrypts the [cipherView] with the organizations encryption key.
*/
suspend fun moveToOrganization(
userId: String,
organizationId: String,
cipherView: CipherView,
): Result<Cipher>
/**
* Validates that the given password matches the password hash.
*/

View file

@ -25,6 +25,7 @@ import com.bitwarden.sdk.BitwardenException
import com.bitwarden.sdk.Client
import com.bitwarden.sdk.ClientVault
import com.x8bit.bitwarden.data.platform.manager.SdkClientManager
import com.x8bit.bitwarden.data.platform.util.flatMap
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.InitializeCryptoResult
import java.io.File
@ -371,6 +372,18 @@ class VaultSdkSourceImpl(
)
}
override suspend fun moveToOrganization(
userId: String,
organizationId: String,
cipherView: CipherView,
): Result<Cipher> = runCatching {
getClient(userId = userId)
.vault()
.ciphers()
.moveToOrganization(cipher = cipherView, organizationId = organizationId)
}
.flatMap { encryptCipher(userId = userId, cipherView = it) }
override suspend fun validatePassword(
userId: String,
password: String,

View file

@ -260,6 +260,7 @@ interface VaultRepository : VaultLockManager {
*/
suspend fun shareCipher(
cipherId: String,
organizationId: String,
cipherView: CipherView,
collectionIds: List<String>,
): ShareCipherResult

View file

@ -811,13 +811,15 @@ class VaultRepositoryImpl(
override suspend fun shareCipher(
cipherId: String,
organizationId: String,
cipherView: CipherView,
collectionIds: List<String>,
): ShareCipherResult {
val userId = activeUserId ?: return ShareCipherResult.Error
return vaultSdkSource
.encryptCipher(
.moveToOrganization(
userId = userId,
organizationId = organizationId,
cipherView = cipherView,
)
.flatMap { cipher ->

View file

@ -298,9 +298,8 @@ class VaultMoveToOrganizationViewModel @Inject constructor(
VaultMoveToOrganizationAction.Internal.ShareCipherResultReceive(
shareCipherResult = vaultRepository.shareCipher(
cipherId = state.vaultItemId,
cipherView = cipherView.copy(
organizationId = contentState.selectedOrganizationId,
),
organizationId = contentState.selectedOrganizationId,
cipherView = cipherView,
collectionIds = collectionIds,
),
successToast = R.string.moved_item_to_org.asText(

View file

@ -24,6 +24,7 @@ import com.bitwarden.crypto.TrustDeviceResponse
import com.bitwarden.sdk.BitwardenException
import com.bitwarden.sdk.Client
import com.bitwarden.sdk.ClientAuth
import com.bitwarden.sdk.ClientCiphers
import com.bitwarden.sdk.ClientCrypto
import com.bitwarden.sdk.ClientExporters
import com.bitwarden.sdk.ClientPasswordHistory
@ -849,6 +850,29 @@ class VaultSdkSourceTest {
coVerify { sdkClientManager.getOrCreateClient(userId = userId) }
}
@Test
fun `moveToOrganization should call SDK and a Result with correct data`() = runTest {
val userId = "userId"
val organizationId = "organizationId"
val mockCipher = mockk<CipherView>()
val expectedResult = mockk<Cipher>()
val clientCipher = mockk<ClientCiphers> {
coEvery {
moveToOrganization(cipher = mockCipher, organizationId = organizationId)
} returns mockCipher
coEvery { encrypt(cipherView = mockCipher) } returns expectedResult
}
every { clientVault.ciphers() } returns clientCipher
val result = vaultSdkSource.moveToOrganization(
userId = userId,
organizationId = organizationId,
cipherView = mockCipher,
)
assertEquals(expectedResult.asSuccess(), result)
}
@Test
fun `validatePassword should call SDK and a Result with correct data`() = runTest {
val userId = "userId"

View file

@ -3094,6 +3094,7 @@ class VaultRepositoryTest {
val result = vaultRepository.shareCipher(
cipherId = "cipherId",
organizationId = "organizationId",
cipherView = mockk(),
collectionIds = emptyList(),
)
@ -3110,9 +3111,11 @@ class VaultRepositoryTest {
runTest {
fakeAuthDiskSource.userState = MOCK_USER_STATE
val userId = "mockId-1"
val organizationId = "organizationId"
coEvery {
vaultSdkSource.encryptCipher(
vaultSdkSource.moveToOrganization(
userId = userId,
organizationId = organizationId,
cipherView = createMockCipherView(number = 1),
)
} returns createMockSdkCipher(number = 1, clock = clock).asSuccess()
@ -3135,6 +3138,7 @@ class VaultRepositoryTest {
val result = vaultRepository.shareCipher(
cipherId = "mockId-1",
organizationId = organizationId,
cipherView = createMockCipherView(number = 1),
collectionIds = listOf("mockId-1"),
)
@ -3151,9 +3155,11 @@ class VaultRepositoryTest {
runTest {
fakeAuthDiskSource.userState = MOCK_USER_STATE
val userId = "mockId-1"
val organizationId = "organizationId"
coEvery {
vaultSdkSource.encryptCipher(
vaultSdkSource.moveToOrganization(
userId = userId,
organizationId = organizationId,
cipherView = createMockCipherView(number = 1),
)
} returns createMockSdkCipher(number = 1, clock = clock).asSuccess()
@ -3170,6 +3176,7 @@ class VaultRepositoryTest {
val result = vaultRepository.shareCipher(
cipherId = "mockId-1",
organizationId = organizationId,
cipherView = createMockCipherView(number = 1),
collectionIds = listOf("mockId-1"),
)
@ -3186,9 +3193,11 @@ class VaultRepositoryTest {
runTest {
fakeAuthDiskSource.userState = MOCK_USER_STATE
val userId = "mockId-1"
val organizationId = "organizationId"
coEvery {
vaultSdkSource.encryptCipher(
vaultSdkSource.moveToOrganization(
userId = userId,
organizationId = organizationId,
cipherView = createMockCipherView(number = 1),
)
} returns Throwable("Fail").asFailure()
@ -3205,6 +3214,7 @@ class VaultRepositoryTest {
val result = vaultRepository.shareCipher(
cipherId = "mockId-1",
organizationId = organizationId,
cipherView = createMockCipherView(number = 1),
collectionIds = listOf("mockId-1"),
)

View file

@ -240,6 +240,7 @@ class VaultMoveToOrganizationViewModelTest : BaseViewModelTest() {
coEvery {
vaultRepository.shareCipher(
cipherId = "mockCipherId",
organizationId = "mockOrganizationId-1",
cipherView = createMockCipherView(number = 1),
collectionIds = listOf("mockId-1"),
)
@ -284,6 +285,7 @@ class VaultMoveToOrganizationViewModelTest : BaseViewModelTest() {
coVerify {
vaultRepository.shareCipher(
cipherId = "mockCipherId",
organizationId = "mockOrganizationId-1",
cipherView = createMockCipherView(number = 1),
collectionIds = listOf("mockId-1"),
)
@ -298,6 +300,7 @@ class VaultMoveToOrganizationViewModelTest : BaseViewModelTest() {
coEvery {
vaultRepository.shareCipher(
cipherId = "mockCipherId",
organizationId = "mockOrganizationId-1",
cipherView = createMockCipherView(number = 1),
collectionIds = listOf("mockId-1"),
)
@ -344,6 +347,7 @@ class VaultMoveToOrganizationViewModelTest : BaseViewModelTest() {
coVerify {
vaultRepository.shareCipher(
cipherId = "mockCipherId",
organizationId = "mockOrganizationId-1",
cipherView = createMockCipherView(number = 1),
collectionIds = listOf("mockId-1"),
)
@ -358,6 +362,7 @@ class VaultMoveToOrganizationViewModelTest : BaseViewModelTest() {
coEvery {
vaultRepository.shareCipher(
cipherId = "mockCipherId",
organizationId = "mockOrganizationId-1",
cipherView = createMockCipherView(number = 1),
collectionIds = listOf("mockId-1"),
)
@ -381,6 +386,7 @@ class VaultMoveToOrganizationViewModelTest : BaseViewModelTest() {
coVerify {
vaultRepository.shareCipher(
cipherId = "mockCipherId",
organizationId = "mockOrganizationId-1",
cipherView = createMockCipherView(number = 1),
collectionIds = listOf("mockId-1"),
)