From a5c2113c1569949ea052ab8d0c68e8d289cf6480 Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Thu, 20 Feb 2025 13:07:27 -0500 Subject: [PATCH] Add backup delete all to internal settings. --- .../securesms/backup/v2/BackupRepository.kt | 7 +++++ .../InternalBackupPlaygroundFragment.kt | 28 ++++++++++++++++++- .../InternalBackupPlaygroundViewModel.kt | 26 +++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt index bbe40406ae..f42ba63140 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt @@ -1215,6 +1215,13 @@ object BackupRepository { .also { Log.i(TAG, "deleteAbandonedMediaObjectsResult: $it") } } + fun deleteBackup(): NetworkResult { + return initBackupAndFetchAuth() + .then { credential -> + SignalNetwork.archive.deleteBackup(SignalStore.account.requireAci(), credential.messageBackupAccess) + } + } + fun debugDeleteAllArchivedMedia(): NetworkResult { return debugGetArchivedMediaState() .then { archivedMedia -> diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/backup/InternalBackupPlaygroundFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/backup/InternalBackupPlaygroundFragment.kt index 02db0580b0..d7185d3436 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/backup/InternalBackupPlaygroundFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/backup/InternalBackupPlaygroundFragment.kt @@ -64,8 +64,12 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import androidx.compose.ui.window.DialogProperties import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import com.google.android.material.dialog.MaterialAlertDialogBuilder +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.signal.core.ui.Dividers import org.signal.core.ui.Previews import org.signal.core.ui.Rows @@ -222,6 +226,21 @@ class InternalBackupPlaygroundFragment : ComposeFragment() { .setMessage("After you choose a file to import, this will delete all of your chats, then restore them from the file! Only do this on a test device!") .setPositiveButton("Wipe and restore") { _, _ -> viewModel.import(SignalStore.settings.signalBackupDirectory!!) } .show() + }, + onDeleteRemoteBackup = { + MaterialAlertDialogBuilder(context) + .setTitle("Are you sure?") + .setMessage("This will delete all of your remote backup data?") + .setPositiveButton("Delete remote data") { _, _ -> + lifecycleScope.launch { + val success = viewModel.deleteRemoteBackupData() + withContext(Dispatchers.Main) { + Toast.makeText(requireContext(), if (success) "Deleted!" else "Failed!", Toast.LENGTH_SHORT).show() + } + } + } + .setNegativeButton("Cancel", null) + .show() } ) }, @@ -317,7 +336,8 @@ fun Screen( onSavePlaintextBackupToDiskClicked: () -> Unit = {}, onImportEncryptedBackupFromDiskClicked: () -> Unit = {}, onImportEncryptedBackupFromDiskDismissed: () -> Unit = {}, - onImportEncryptedBackupFromDiskConfirmed: (aci: String, backupKey: String) -> Unit = { _, _ -> } + onImportEncryptedBackupFromDiskConfirmed: (aci: String, backupKey: String) -> Unit = { _, _ -> }, + onDeleteRemoteBackup: () -> Unit = {} ) { val context = LocalContext.current val scrollState = rememberScrollState() @@ -492,6 +512,12 @@ fun Screen( onClick = onImportNewStyleLocalBackupClicked ) + Rows.TextRow( + text = "Delete all backup data on server", + label = "Erases all content on the server.", + onClick = onDeleteRemoteBackup + ) + Dividers.Default() Spacer(modifier = Modifier.height(8.dp)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/backup/InternalBackupPlaygroundViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/backup/InternalBackupPlaygroundViewModel.kt index 71449cfcd5..3495e1012d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/backup/InternalBackupPlaygroundViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/backup/InternalBackupPlaygroundViewModel.kt @@ -18,6 +18,8 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.subscribeBy import io.reactivex.rxjava3.schedulers.Schedulers +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import org.signal.core.util.Hex import org.signal.core.util.bytes import org.signal.core.util.concurrent.SignalExecutors @@ -155,6 +157,7 @@ class InternalBackupPlaygroundViewModel : ViewModel() { Log.w(TAG, "Validation failed! Details: ${result.messageDetails}", result.exception) "Validation failed :( Check the logs for details." } + is ArchiveValidator.ValidationResult.RecipientDuplicateE164Error -> { Log.w(TAG, "Validation failed with a duplicate recipient! Details: ${result.details}", result.exception) "Validation failed :( Check the logs for details." @@ -532,6 +535,29 @@ class InternalBackupPlaygroundViewModel : ViewModel() { ) } + suspend fun deleteRemoteBackupData(): Boolean = withContext(Dispatchers.IO) { + when (val result = BackupRepository.debugDeleteAllArchivedMedia()) { + is NetworkResult.Success -> Log.i(TAG, "Remote data deleted") + else -> { + Log.w(TAG, "Unable to delete media", result.getCause()) + return@withContext false + } + } + + when (val result = BackupRepository.deleteBackup()) { + is NetworkResult.Success -> { + SignalStore.backup.backupsInitialized = false + SignalStore.backup.messageCredentials.clearAll() + SignalStore.backup.mediaCredentials.clearAll() + SignalStore.backup.cachedMediaCdnPath = null + return@withContext true + } + else -> Log.w(TAG, "Unable to delete remote data", result.getCause()) + } + + return@withContext false + } + override fun onCleared() { disposables.clear() }