mirror of
https://github.com/bitwarden/android.git
synced 2025-12-11 13:57:03 -06:00
PM-25462: Allow SYNC_FOLDER_DELETE notification to delete Folders for inactive user (#5832)
This commit is contained in:
parent
eec4233486
commit
aa39e6c6be
@ -227,9 +227,14 @@ class PushManagerImpl @Inject constructor(
|
|||||||
.decodeFromString<NotificationPayload.SyncFolderNotification>(
|
.decodeFromString<NotificationPayload.SyncFolderNotification>(
|
||||||
string = notification.payload,
|
string = notification.payload,
|
||||||
)
|
)
|
||||||
.takeIf { isLoggedIn(userId) && it.userMatchesNotification(userId) }
|
.takeIf { it.userId != null && it.folderId != null }
|
||||||
?.folderId
|
?.let {
|
||||||
?.let { mutableSyncFolderDeleteSharedFlow.tryEmit(SyncFolderDeleteData(it)) }
|
SyncFolderDeleteData(
|
||||||
|
userId = requireNotNull(it.userId),
|
||||||
|
folderId = requireNotNull(it.folderId),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
?.let { mutableSyncFolderDeleteSharedFlow.tryEmit(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationType.SYNC_ORG_KEYS -> {
|
NotificationType.SYNC_ORG_KEYS -> {
|
||||||
|
|||||||
@ -2,9 +2,8 @@ package com.x8bit.bitwarden.data.platform.manager.model
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Required data for sync folder delete operations.
|
* Required data for sync folder delete operations.
|
||||||
*
|
|
||||||
* @property folderId The folder ID.
|
|
||||||
*/
|
*/
|
||||||
data class SyncFolderDeleteData(
|
data class SyncFolderDeleteData(
|
||||||
|
val userId: String,
|
||||||
val folderId: String,
|
val folderId: String,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -929,11 +929,9 @@ class VaultRepositoryImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun clearFolderIdFromCiphers(folderId: String, userId: String) {
|
private suspend fun clearFolderIdFromCiphers(folderId: String, userId: String) {
|
||||||
vaultDiskSource.getCiphersFlow(userId).firstOrNull()?.forEach {
|
vaultDiskSource.getCiphers(userId = userId).forEach {
|
||||||
if (it.folderId == folderId) {
|
if (it.folderId == folderId) {
|
||||||
vaultDiskSource.saveCipher(
|
vaultDiskSource.saveCipher(userId = userId, cipher = it.copy(folderId = null))
|
||||||
userId, it.copy(folderId = null),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1433,16 +1431,13 @@ class VaultRepositoryImpl(
|
|||||||
* Deletes the folder specified by [syncFolderDeleteData] from disk.
|
* Deletes the folder specified by [syncFolderDeleteData] from disk.
|
||||||
*/
|
*/
|
||||||
private suspend fun deleteFolder(syncFolderDeleteData: SyncFolderDeleteData) {
|
private suspend fun deleteFolder(syncFolderDeleteData: SyncFolderDeleteData) {
|
||||||
val userId = activeUserId ?: return
|
|
||||||
|
|
||||||
val folderId = syncFolderDeleteData.folderId
|
|
||||||
clearFolderIdFromCiphers(
|
clearFolderIdFromCiphers(
|
||||||
folderId = folderId,
|
folderId = syncFolderDeleteData.folderId,
|
||||||
userId = userId,
|
userId = syncFolderDeleteData.userId,
|
||||||
)
|
)
|
||||||
vaultDiskSource.deleteFolder(
|
vaultDiskSource.deleteFolder(
|
||||||
folderId = folderId,
|
folderId = syncFolderDeleteData.folderId,
|
||||||
userId = userId,
|
userId = syncFolderDeleteData.userId,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -285,6 +285,7 @@ class PushManagerTest {
|
|||||||
pushManager.onMessageReceived(SYNC_FOLDER_DELETE_NOTIFICATION_MAP)
|
pushManager.onMessageReceived(SYNC_FOLDER_DELETE_NOTIFICATION_MAP)
|
||||||
assertEquals(
|
assertEquals(
|
||||||
SyncFolderDeleteData(
|
SyncFolderDeleteData(
|
||||||
|
userId = "078966a2-93c2-4618-ae2a-0a2394c88d37",
|
||||||
folderId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321",
|
folderId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321",
|
||||||
),
|
),
|
||||||
awaitItem(),
|
awaitItem(),
|
||||||
@ -425,10 +426,17 @@ class PushManagerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `onMessageReceived with sync folder delete does nothing`() = runTest {
|
fun `onMessageReceived with sync folder delete emits to syncFolderDeleteFlow`() =
|
||||||
|
runTest {
|
||||||
pushManager.syncFolderDeleteFlow.test {
|
pushManager.syncFolderDeleteFlow.test {
|
||||||
pushManager.onMessageReceived(SYNC_FOLDER_DELETE_NOTIFICATION_MAP)
|
pushManager.onMessageReceived(SYNC_FOLDER_DELETE_NOTIFICATION_MAP)
|
||||||
expectNoEvents()
|
assertEquals(
|
||||||
|
SyncFolderDeleteData(
|
||||||
|
userId = "078966a2-93c2-4618-ae2a-0a2394c88d37",
|
||||||
|
folderId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321",
|
||||||
|
),
|
||||||
|
awaitItem(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2834,46 +2834,26 @@ class VaultRepositoryTest {
|
|||||||
fun `DeleteFolder with folderService Delete success should return DeleteFolderResult Success and update ciphers`() =
|
fun `DeleteFolder with folderService Delete success should return DeleteFolderResult Success and update ciphers`() =
|
||||||
runTest {
|
runTest {
|
||||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||||
|
val userId = MOCK_USER_STATE.activeUserId
|
||||||
val folderId = "mockFolderId-1"
|
val folderId = "mockFolderId-1"
|
||||||
|
val mockCipher = createMockCipher(number = 1)
|
||||||
|
val ciphers = listOf(mockCipher, createMockCipher(number = 2))
|
||||||
coEvery { folderService.deleteFolder(folderId) } returns Unit.asSuccess()
|
coEvery { folderService.deleteFolder(folderId) } returns Unit.asSuccess()
|
||||||
coEvery {
|
coEvery { vaultDiskSource.deleteFolder(userId = userId, folderId = folderId) } just runs
|
||||||
vaultDiskSource.deleteFolder(
|
coEvery { vaultDiskSource.getCiphers(userId = userId) } returns ciphers
|
||||||
MOCK_USER_STATE.activeUserId,
|
|
||||||
folderId,
|
|
||||||
)
|
|
||||||
} just runs
|
|
||||||
|
|
||||||
val mockCipher = createMockCipher(1)
|
|
||||||
|
|
||||||
val mutableCiphersStateFlow =
|
|
||||||
MutableStateFlow(
|
|
||||||
listOf(
|
|
||||||
mockCipher,
|
|
||||||
createMockCipher(2),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
coEvery {
|
|
||||||
vaultDiskSource.getCiphersFlow(MOCK_USER_STATE.activeUserId)
|
|
||||||
} returns mutableCiphersStateFlow
|
|
||||||
|
|
||||||
coEvery {
|
coEvery {
|
||||||
vaultDiskSource.saveCipher(
|
vaultDiskSource.saveCipher(
|
||||||
MOCK_USER_STATE.activeUserId,
|
userId = userId,
|
||||||
mockCipher.copy(
|
cipher = mockCipher.copy(folderId = null),
|
||||||
folderId = null,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
} just runs
|
} just runs
|
||||||
|
|
||||||
val result = vaultRepository.deleteFolder(folderId)
|
val result = vaultRepository.deleteFolder(folderId = folderId)
|
||||||
|
|
||||||
coVerify(exactly = 1) {
|
coVerify(exactly = 1) {
|
||||||
vaultDiskSource.saveCipher(
|
vaultDiskSource.saveCipher(
|
||||||
MOCK_USER_STATE.activeUserId,
|
userId = userId,
|
||||||
mockCipher.copy(
|
cipher = mockCipher.copy(folderId = null),
|
||||||
folderId = null,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4020,20 +4000,21 @@ class VaultRepositoryTest {
|
|||||||
fun `syncFolderDeleteFlow should delete folder from disk and update ciphers`() {
|
fun `syncFolderDeleteFlow should delete folder from disk and update ciphers`() {
|
||||||
val userId = "mockId-1"
|
val userId = "mockId-1"
|
||||||
val folderId = "mockId-1"
|
val folderId = "mockId-1"
|
||||||
|
val cipher = createMockCipher(number = 1, folderId = folderId)
|
||||||
|
val updatedCipher = createMockCipher(number = 1, folderId = null)
|
||||||
|
|
||||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
|
||||||
coEvery { vaultDiskSource.deleteFolder(userId = userId, folderId = folderId) } just runs
|
coEvery { vaultDiskSource.deleteFolder(userId = userId, folderId = folderId) } just runs
|
||||||
coEvery {
|
coEvery { vaultDiskSource.getCiphers(userId = userId) } returns listOf(cipher)
|
||||||
vaultDiskSource.getCiphersFlow(userId)
|
coEvery { vaultDiskSource.saveCipher(userId = userId, cipher = updatedCipher) } just runs
|
||||||
} returns flowOf()
|
|
||||||
|
|
||||||
mutableSyncFolderDeleteFlow.tryEmit(
|
mutableSyncFolderDeleteFlow.tryEmit(
|
||||||
SyncFolderDeleteData(folderId = folderId),
|
SyncFolderDeleteData(userId = userId, folderId = folderId),
|
||||||
)
|
)
|
||||||
|
|
||||||
coVerify {
|
coVerify(exactly = 1) {
|
||||||
vaultDiskSource.deleteFolder(userId = userId, folderId = folderId)
|
vaultDiskSource.deleteFolder(userId = userId, folderId = folderId)
|
||||||
vaultDiskSource.getCiphersFlow(userId)
|
vaultDiskSource.getCiphers(userId = userId)
|
||||||
|
vaultDiskSource.saveCipher(userId = userId, cipher = updatedCipher)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user