From f43674fb56b07bb691da345bb82313abcde7b5ce Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Fri, 24 Jan 2025 16:27:34 -0500 Subject: [PATCH] Add additional logging on failed backup validations. --- .../securesms/backup/v2/ArchiveValidator.kt | 56 ++++++++++++++++++- .../InternalBackupPlaygroundViewModel.kt | 2 +- .../securesms/jobs/BackupMessagesJob.kt | 2 +- .../linkdevice/LinkDeviceRepository.kt | 2 +- 4 files changed, 57 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ArchiveValidator.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ArchiveValidator.kt index 69c05a968c..5dd9f0b2f4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ArchiveValidator.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ArchiveValidator.kt @@ -5,9 +5,13 @@ package org.thoughtcrime.securesms.backup.v2 +import org.signal.core.util.isNotNullOrBlank import org.signal.libsignal.messagebackup.MessageBackup import org.signal.libsignal.messagebackup.ValidationError +import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.util.isStory +import org.thoughtcrime.securesms.util.isStoryReaction import org.whispersystems.signalservice.api.backup.MessageBackupKey import java.io.File import java.io.IOException @@ -31,13 +35,61 @@ object ArchiveValidator { } catch (e: IOException) { ValidationResult.ReadError(e) } catch (e: ValidationError) { - ValidationResult.ValidationError(e) + val sentTimestamp = "\\d{10,}+".toRegex().find(e.message ?: "")?.value?.toLongOrNull() + ValidationResult.ValidationError( + exception = e, + messageDetails = sentTimestamp?.let { fetchMessageDetails(it) } ?: emptyList() + ) + } + } + + private fun fetchMessageDetails(sentTimestamp: Long): List { + val messages = SignalDatabase.messages.getMessagesBySentTimestamp(sentTimestamp) + return messages.map { + MessageDetails( + messageId = it.id, + dateSent = it.dateSent, + threadId = it.threadId, + threadRecipientId = SignalDatabase.threads.getRecipientForThreadId(it.threadId)?.id?.toLong() ?: 0L, + type = it.type, + fromRecipientId = it.fromRecipient.id.toLong(), + toRecipientId = it.toRecipient.id.toLong(), + hasBody = it.body.isNotNullOrBlank(), + hasExtras = it.messageExtras != null, + outgoing = it.isOutgoing, + viewOnce = it.isViewOnce, + isStory = it.isStory(), + isStoryReaction = it.isStoryReaction(), + originalMessageId = it.originalMessageId?.id ?: 0, + isLatestRevision = it.isLatestRevision + ) } } sealed interface ValidationResult { data object Success : ValidationResult data class ReadError(val exception: IOException) : ValidationResult - data class ValidationError(val exception: org.signal.libsignal.messagebackup.ValidationError) : ValidationResult + data class ValidationError( + val exception: org.signal.libsignal.messagebackup.ValidationError, + val messageDetails: List + ) : ValidationResult } + + data class MessageDetails( + val messageId: Long, + val dateSent: Long, + val threadId: Long, + val threadRecipientId: Long, + val type: Long, + val fromRecipientId: Long, + val toRecipientId: Long, + val hasBody: Boolean, + val hasExtras: Boolean, + val outgoing: Boolean, + val viewOnce: Boolean, + val isStory: Boolean, + val isStoryReaction: Boolean, + val originalMessageId: Long, + val isLatestRevision: Boolean + ) } 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 0ed120c392..c387858ffe 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 @@ -152,7 +152,7 @@ class InternalBackupPlaygroundViewModel : ViewModel() { is ArchiveValidator.ValidationResult.ReadError -> "Failed to read backup file!" ArchiveValidator.ValidationResult.Success -> "Validation passed!" is ArchiveValidator.ValidationResult.ValidationError -> { - Log.w(TAG, "Validation failed!", result.exception) + Log.w(TAG, "Validation failed! Details: ${result.messageDetails}", result.exception) "Validation failed :( Check the logs for details." } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupMessagesJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupMessagesJob.kt index f3de98cf7c..0f40dd54e1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupMessagesJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupMessagesJob.kt @@ -226,7 +226,7 @@ class BackupMessagesJob private constructor( } is ArchiveValidator.ValidationResult.ValidationError -> { - Log.w(TAG, "The backup file fails validation! Message: " + result.exception.message) + Log.w(TAG, "The backup file fails validation! Message: ${result.exception.message}, Details: ${result.messageDetails}") ArchiveUploadProgress.onValidationFailure() return BackupFileResult.Failure } diff --git a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceRepository.kt index fe68def73e..ff8338d624 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceRepository.kt @@ -277,7 +277,7 @@ object LinkDeviceRepository { return LinkUploadArchiveResult.BackupCreationFailure(result.exception) } is ArchiveValidator.ValidationResult.ValidationError -> { - Log.w(TAG, "[createAndUploadArchive] The backup file fails validation!", result.exception) + Log.w(TAG, "[createAndUploadArchive] The backup file fails validation! Details: ${result.messageDetails}", result.exception) return LinkUploadArchiveResult.BackupCreationFailure(result.exception) } }