mirror of
https://github.com/bitwarden/android.git
synced 2026-06-08 23:16:33 -05:00
Adding the Repository folder calls. (#813)
This commit is contained in:
committed by
Álison Fernandes
parent
fa551fa6ab
commit
3be37766e2
@@ -39,6 +39,11 @@ interface VaultDiskSource {
|
||||
*/
|
||||
fun getDomains(userId: String): Flow<SyncResponseJson.Domains>
|
||||
|
||||
/**
|
||||
* Deletes a folder from the data source for the given [userId] and [folderId].
|
||||
*/
|
||||
suspend fun deleteFolder(userId: String, folderId: String)
|
||||
|
||||
/**
|
||||
* Saves a folder to the data source for the given [userId].
|
||||
*/
|
||||
|
||||
@@ -114,6 +114,10 @@ class VaultDiskSourceImpl(
|
||||
json.decodeFromString<SyncResponseJson.Domains>(entity.domainsJson)
|
||||
}
|
||||
|
||||
override suspend fun deleteFolder(userId: String, folderId: String) {
|
||||
foldersDao.deleteFolder(userId = userId, folderId = folderId)
|
||||
}
|
||||
|
||||
override suspend fun saveFolder(userId: String, folder: SyncResponseJson.Folder) {
|
||||
foldersDao.insertFolder(
|
||||
folder = FolderEntity(
|
||||
|
||||
@@ -229,6 +229,18 @@ interface VaultSdkSource {
|
||||
sendList: List<Send>,
|
||||
): Result<List<SendView>>
|
||||
|
||||
/**
|
||||
* Encrypts a [FolderView] for the user with the given [userId], returning a [Folder] wrapped
|
||||
* in a [Result].
|
||||
*
|
||||
* This should only be called after a successful call to [initializeCrypto] for the associated
|
||||
* user.
|
||||
*/
|
||||
suspend fun encryptFolder(
|
||||
userId: String,
|
||||
folder: FolderView,
|
||||
): Result<Folder>
|
||||
|
||||
/**
|
||||
* Decrypts a [Folder] for the user with the given [userId], returning a [FolderView] wrapped
|
||||
* in a [Result].
|
||||
|
||||
@@ -240,6 +240,17 @@ class VaultSdkSourceImpl(
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun encryptFolder(
|
||||
userId: String,
|
||||
folder: FolderView,
|
||||
): Result<Folder> =
|
||||
runCatching {
|
||||
getClient(userId = userId)
|
||||
.vault()
|
||||
.folders()
|
||||
.encrypt(folder)
|
||||
}
|
||||
|
||||
override suspend fun decryptFolder(
|
||||
userId: String,
|
||||
folder: Folder,
|
||||
|
||||
@@ -13,9 +13,11 @@ 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.CreateFolderResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateSendResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.DeleteAttachmentResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.DeleteCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.DeleteFolderResult
|
||||
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.GenerateTotpResult
|
||||
@@ -25,6 +27,7 @@ import com.x8bit.bitwarden.data.vault.repository.model.SendData
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.ShareCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.TotpCodeResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateFolderResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateSendResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultData
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult
|
||||
@@ -283,4 +286,19 @@ interface VaultRepository : VaultLockManager {
|
||||
attachmentId: String,
|
||||
cipherView: CipherView,
|
||||
): DeleteAttachmentResult
|
||||
|
||||
/**
|
||||
* Attempt to create a folder.
|
||||
*/
|
||||
suspend fun createFolder(folderView: FolderView): CreateFolderResult
|
||||
|
||||
/**
|
||||
* Attempt to delete a folder.
|
||||
*/
|
||||
suspend fun deleteFolder(folderId: String): DeleteFolderResult
|
||||
|
||||
/**
|
||||
* Attempt to update a folder.
|
||||
*/
|
||||
suspend fun updateFolder(folderId: String, folderView: FolderView): UpdateFolderResult
|
||||
}
|
||||
|
||||
@@ -31,8 +31,10 @@ import com.x8bit.bitwarden.data.vault.datasource.network.model.AttachmentJsonReq
|
||||
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 com.x8bit.bitwarden.data.vault.datasource.network.model.UpdateFolderResponseJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.UpdateSendResponseJson
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.service.CiphersService
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.service.FolderService
|
||||
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
|
||||
@@ -42,9 +44,11 @@ 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.CreateFolderResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.CreateSendResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.DeleteAttachmentResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.DeleteCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.DeleteFolderResult
|
||||
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.GenerateTotpResult
|
||||
@@ -54,6 +58,7 @@ import com.x8bit.bitwarden.data.vault.repository.model.SendData
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.ShareCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.TotpCodeResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateFolderResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateSendResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultData
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult
|
||||
@@ -61,10 +66,12 @@ import com.x8bit.bitwarden.data.vault.repository.util.sortAlphabetically
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toDomainsData
|
||||
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.toEncryptedNetworkFolder
|
||||
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.toEncryptedSdkFolder
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedSdkFolderList
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedSdkSend
|
||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedSdkSendList
|
||||
@@ -80,6 +87,7 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
@@ -107,6 +115,7 @@ class VaultRepositoryImpl(
|
||||
private val syncService: SyncService,
|
||||
private val ciphersService: CiphersService,
|
||||
private val sendsService: SendsService,
|
||||
private val folderService: FolderService,
|
||||
private val vaultDiskSource: VaultDiskSource,
|
||||
private val vaultSdkSource: VaultSdkSource,
|
||||
private val authDiskSource: AuthDiskSource,
|
||||
@@ -917,6 +926,95 @@ class VaultRepositoryImpl(
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun createFolder(folderView: FolderView): CreateFolderResult {
|
||||
val userId = activeUserId ?: return CreateFolderResult.Error
|
||||
return vaultSdkSource
|
||||
.encryptFolder(
|
||||
userId = userId,
|
||||
folder = folderView,
|
||||
)
|
||||
.flatMap { folder ->
|
||||
folderService
|
||||
.createFolder(
|
||||
body = folder.toEncryptedNetworkFolder(),
|
||||
)
|
||||
}
|
||||
.onSuccess { vaultDiskSource.saveFolder(userId = userId, folder = it) }
|
||||
.flatMap { vaultSdkSource.decryptFolder(userId, it.toEncryptedSdkFolder()) }
|
||||
.fold(
|
||||
onSuccess = { CreateFolderResult.Success(folderView = it) },
|
||||
onFailure = { CreateFolderResult.Error },
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun updateFolder(
|
||||
folderId: String,
|
||||
folderView: FolderView,
|
||||
): UpdateFolderResult {
|
||||
val userId = activeUserId ?: return UpdateFolderResult.Error(null)
|
||||
return vaultSdkSource
|
||||
.encryptFolder(
|
||||
userId = userId,
|
||||
folder = folderView,
|
||||
)
|
||||
.flatMap { folder ->
|
||||
folderService
|
||||
.updateFolder(
|
||||
folderId = folder.id.toString(),
|
||||
body = folder.toEncryptedNetworkFolder(),
|
||||
)
|
||||
}
|
||||
.fold(
|
||||
onSuccess = { response ->
|
||||
when (response) {
|
||||
is UpdateFolderResponseJson.Success -> {
|
||||
vaultDiskSource.saveFolder(userId, response.folder)
|
||||
vaultSdkSource
|
||||
.decryptFolder(
|
||||
userId,
|
||||
response.folder.toEncryptedSdkFolder(),
|
||||
)
|
||||
.fold(
|
||||
onSuccess = { UpdateFolderResult.Success(it) },
|
||||
onFailure = { UpdateFolderResult.Error(errorMessage = null) },
|
||||
)
|
||||
}
|
||||
|
||||
is UpdateFolderResponseJson.Invalid -> {
|
||||
UpdateFolderResult.Error(response.message)
|
||||
}
|
||||
}
|
||||
},
|
||||
onFailure = { UpdateFolderResult.Error(it.message) },
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun deleteFolder(folderId: String): DeleteFolderResult {
|
||||
val userId = activeUserId ?: return DeleteFolderResult.Error
|
||||
return folderService
|
||||
.deleteFolder(
|
||||
folderId = folderId,
|
||||
)
|
||||
.onSuccess {
|
||||
clearFolderIdFromCiphers(folderId, userId)
|
||||
vaultDiskSource.deleteFolder(userId, folderId)
|
||||
}
|
||||
.fold(
|
||||
onSuccess = { DeleteFolderResult.Success },
|
||||
onFailure = { DeleteFolderResult.Error },
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun clearFolderIdFromCiphers(folderId: String, userId: String) {
|
||||
vaultDiskSource.getCiphers(userId).firstOrNull()?.forEach {
|
||||
if (it.folderId == folderId) {
|
||||
vaultDiskSource.saveCipher(
|
||||
userId, it.copy(folderId = null),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
import com.x8bit.bitwarden.data.vault.datasource.disk.VaultDiskSource
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.service.CiphersService
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.service.FolderService
|
||||
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
|
||||
@@ -33,6 +34,7 @@ object VaultRepositoryModule {
|
||||
syncService: SyncService,
|
||||
sendsService: SendsService,
|
||||
ciphersService: CiphersService,
|
||||
folderService: FolderService,
|
||||
vaultDiskSource: VaultDiskSource,
|
||||
vaultSdkSource: VaultSdkSource,
|
||||
authDiskSource: AuthDiskSource,
|
||||
@@ -46,6 +48,7 @@ object VaultRepositoryModule {
|
||||
syncService = syncService,
|
||||
sendsService = sendsService,
|
||||
ciphersService = ciphersService,
|
||||
folderService = folderService,
|
||||
vaultDiskSource = vaultDiskSource,
|
||||
vaultSdkSource = vaultSdkSource,
|
||||
authDiskSource = authDiskSource,
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.x8bit.bitwarden.data.vault.repository.model
|
||||
|
||||
import com.bitwarden.core.FolderView
|
||||
|
||||
/**
|
||||
* Models result of creating a folder.
|
||||
*/
|
||||
sealed class CreateFolderResult {
|
||||
|
||||
/**
|
||||
* Folder created successfully.
|
||||
*/
|
||||
data class Success(val folderView: FolderView) : CreateFolderResult()
|
||||
|
||||
/**
|
||||
* Generic error while creating a folder.
|
||||
*/
|
||||
data object Error : CreateFolderResult()
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.x8bit.bitwarden.data.vault.repository.model
|
||||
|
||||
/**
|
||||
* Models result of deleting a folder.
|
||||
*/
|
||||
sealed class DeleteFolderResult {
|
||||
|
||||
/**
|
||||
* Folder deleted successfully.
|
||||
*/
|
||||
data object Success : DeleteFolderResult()
|
||||
|
||||
/**
|
||||
* Generic error while deleting a folder.
|
||||
*/
|
||||
data object Error : DeleteFolderResult()
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.x8bit.bitwarden.data.vault.repository.model
|
||||
|
||||
import com.bitwarden.core.FolderView
|
||||
|
||||
/**
|
||||
* Models result of updating a folder.
|
||||
*/
|
||||
sealed class UpdateFolderResult {
|
||||
|
||||
/**
|
||||
* Folder updated successfully.
|
||||
*/
|
||||
data class Success(val folderView: FolderView) : UpdateFolderResult()
|
||||
|
||||
/**
|
||||
* Generic error while updating a folder. The optional [errorMessage]
|
||||
* may be displayed directly in the UI when present.
|
||||
*/
|
||||
data class Error(val errorMessage: String?) : UpdateFolderResult()
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.x8bit.bitwarden.data.vault.repository.util
|
||||
|
||||
import com.bitwarden.core.Folder
|
||||
import com.bitwarden.core.FolderView
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.FolderJsonRequest
|
||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||
import java.util.Locale
|
||||
|
||||
@@ -29,3 +30,10 @@ fun SyncResponseJson.Folder.toEncryptedSdkFolder(): Folder =
|
||||
@JvmName("toAlphabeticallySortedFolderList")
|
||||
fun List<FolderView>.sortAlphabetically(): List<FolderView> =
|
||||
this.sortedBy { it.name.uppercase(Locale.getDefault()) }
|
||||
|
||||
/**
|
||||
* Converts a Bitwarden SDK [Folder] objects to a corresponding
|
||||
* [SyncResponseJson.Folder] object.
|
||||
*/
|
||||
fun Folder.toEncryptedNetworkFolder(): FolderJsonRequest =
|
||||
FolderJsonRequest(name = name)
|
||||
|
||||
Reference in New Issue
Block a user