From fb69fc5af2207fd97e2de88ebbb80bb0cb87ce7c Mon Sep 17 00:00:00 2001 From: Clark Chen Date: Fri, 10 Nov 2023 12:34:22 -0500 Subject: [PATCH] Add backupV2 support for simple update messages. --- .../v2/database/ChatItemExportIterator.kt | 34 +++++++++++++++++ .../v2/database/ChatItemImportInserter.kt | 37 +++++++++++++++++++ app/src/main/protowire/Backup.proto | 1 + 3 files changed, 72 insertions(+) diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemExportIterator.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemExportIterator.kt index 49a29c11f7..4cdcfbe538 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemExportIterator.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemExportIterator.kt @@ -6,6 +6,7 @@ package org.thoughtcrime.securesms.backup.v2.database import android.database.Cursor +import org.signal.core.util.Base64 import org.signal.core.util.logging.Log import org.signal.core.util.requireBlob import org.signal.core.util.requireBoolean @@ -13,12 +14,16 @@ import org.signal.core.util.requireInt import org.signal.core.util.requireLong import org.signal.core.util.requireString import org.thoughtcrime.securesms.backup.v2.proto.ChatItem +import org.thoughtcrime.securesms.backup.v2.proto.ExpirationTimerChange +import org.thoughtcrime.securesms.backup.v2.proto.ProfileChange import org.thoughtcrime.securesms.backup.v2.proto.Quote import org.thoughtcrime.securesms.backup.v2.proto.Reaction import org.thoughtcrime.securesms.backup.v2.proto.RemoteDeletedMessage import org.thoughtcrime.securesms.backup.v2.proto.SendStatus +import org.thoughtcrime.securesms.backup.v2.proto.SimpleUpdate import org.thoughtcrime.securesms.backup.v2.proto.StandardMessage import org.thoughtcrime.securesms.backup.v2.proto.Text +import org.thoughtcrime.securesms.backup.v2.proto.UpdateMessage import org.thoughtcrime.securesms.database.GroupReceiptTable import org.thoughtcrime.securesms.database.MessageTable import org.thoughtcrime.securesms.database.MessageTypes @@ -27,6 +32,7 @@ import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatchSet import org.thoughtcrime.securesms.database.documents.NetworkFailureSet import org.thoughtcrime.securesms.database.model.ReactionRecord import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList +import org.thoughtcrime.securesms.database.model.databaseprotos.ProfileChangeDetails import org.thoughtcrime.securesms.mms.QuoteModel import org.thoughtcrime.securesms.util.JsonUtils import java.io.Closeable @@ -84,6 +90,34 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: when { record.remoteDeleted -> builder.remoteDeletedMessage = RemoteDeletedMessage() + MessageTypes.isJoinedType(record.type) -> builder.updateMessage = UpdateMessage(simpleUpdate = SimpleUpdate(type = SimpleUpdate.Type.JOINED_SIGNAL)) + MessageTypes.isIdentityUpdate(record.type) -> builder.updateMessage = UpdateMessage(simpleUpdate = SimpleUpdate(type = SimpleUpdate.Type.IDENTITY_UPDATE)) + MessageTypes.isIdentityVerified(record.type) -> builder.updateMessage = UpdateMessage(simpleUpdate = SimpleUpdate(type = SimpleUpdate.Type.IDENTITY_VERIFIED)) + MessageTypes.isIdentityDefault(record.type) -> builder.updateMessage = UpdateMessage(simpleUpdate = SimpleUpdate(type = SimpleUpdate.Type.IDENTITY_DEFAULT)) + MessageTypes.isChangeNumber(record.type) -> builder.updateMessage = UpdateMessage(simpleUpdate = SimpleUpdate(type = SimpleUpdate.Type.CHANGE_NUMBER)) + MessageTypes.isBoostRequest(record.type) -> builder.updateMessage = UpdateMessage(simpleUpdate = SimpleUpdate(type = SimpleUpdate.Type.BOOST_REQUEST)) + MessageTypes.isEndSessionType(record.type) -> builder.updateMessage = UpdateMessage(simpleUpdate = SimpleUpdate(type = SimpleUpdate.Type.END_SESSION)) + MessageTypes.isChatSessionRefresh(record.type) -> builder.updateMessage = UpdateMessage(simpleUpdate = SimpleUpdate(type = SimpleUpdate.Type.CHAT_SESSION_REFRESH)) + MessageTypes.isBadDecryptType(record.type) -> builder.updateMessage = UpdateMessage(simpleUpdate = SimpleUpdate(type = SimpleUpdate.Type.BAD_DECRYPT)) + MessageTypes.isPaymentsActivated(record.type) -> builder.updateMessage = UpdateMessage(simpleUpdate = SimpleUpdate(type = SimpleUpdate.Type.PAYMENTS_ACTIVATED)) + MessageTypes.isPaymentsRequestToActivate(record.type) -> builder.updateMessage = UpdateMessage(simpleUpdate = SimpleUpdate(type = SimpleUpdate.Type.PAYMENT_ACTIVATION_REQUEST)) + MessageTypes.isExpirationTimerUpdate(record.type) -> builder.updateMessage = UpdateMessage(expirationTimerChange = ExpirationTimerChange((record.expiresIn / 1000).toInt())) + MessageTypes.isProfileChange(record.type) -> { + builder.updateMessage = UpdateMessage( + profileChange = try { + val decoded: ByteArray = Base64.decode(record.body!!) + val profileChangeDetails = ProfileChangeDetails.ADAPTER.decode(decoded) + if (profileChangeDetails.profileNameChange != null) { + ProfileChange(previousName = profileChangeDetails.profileNameChange.previous, newName = profileChangeDetails.profileNameChange.newValue) + } else { + ProfileChange() + } + } catch (e: IOException) { + Log.w(TAG, "Profile name change details could not be read", e) + ProfileChange() + } + ) + } else -> builder.standardMessage = record.toTextMessage(reactionsById[id]) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemImportInserter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemImportInserter.kt index 1253e1d1c9..9fc5d759a8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemImportInserter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/ChatItemImportInserter.kt @@ -7,6 +7,7 @@ package org.thoughtcrime.securesms.backup.v2.database import android.content.ContentValues import androidx.core.content.contentValuesOf +import org.signal.core.util.Base64 import org.signal.core.util.SqlUtil import org.signal.core.util.logging.Log import org.signal.core.util.toInt @@ -16,7 +17,9 @@ import org.thoughtcrime.securesms.backup.v2.proto.ChatItem import org.thoughtcrime.securesms.backup.v2.proto.Quote import org.thoughtcrime.securesms.backup.v2.proto.Reaction import org.thoughtcrime.securesms.backup.v2.proto.SendStatus +import org.thoughtcrime.securesms.backup.v2.proto.SimpleUpdate import org.thoughtcrime.securesms.backup.v2.proto.StandardMessage +import org.thoughtcrime.securesms.backup.v2.proto.UpdateMessage import org.thoughtcrime.securesms.database.GroupReceiptTable import org.thoughtcrime.securesms.database.MessageTable import org.thoughtcrime.securesms.database.MessageTypes @@ -27,6 +30,7 @@ import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatchSet import org.thoughtcrime.securesms.database.documents.NetworkFailure import org.thoughtcrime.securesms.database.documents.NetworkFailureSet import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList +import org.thoughtcrime.securesms.database.model.databaseprotos.ProfileChangeDetails import org.thoughtcrime.securesms.mms.QuoteModel import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId @@ -208,6 +212,7 @@ class ChatItemImportInserter( when { this.standardMessage != null -> contentValues.addStandardMessage(this.standardMessage) this.remoteDeletedMessage != null -> contentValues.put(MessageTable.REMOTE_DELETED, 1) + this.updateMessage != null -> contentValues.addUpdateMessage(this.updateMessage) } return contentValues @@ -303,6 +308,38 @@ class ChatItemImportInserter( } } + private fun ContentValues.addUpdateMessage(updateMessage: UpdateMessage) { + var typeFlags: Long = 0 + when { + updateMessage.simpleUpdate != null -> { + typeFlags = when (updateMessage.simpleUpdate.type) { + SimpleUpdate.Type.JOINED_SIGNAL -> MessageTypes.JOINED_TYPE + SimpleUpdate.Type.IDENTITY_UPDATE -> MessageTypes.KEY_EXCHANGE_IDENTITY_UPDATE_BIT + SimpleUpdate.Type.IDENTITY_VERIFIED -> MessageTypes.KEY_EXCHANGE_IDENTITY_VERIFIED_BIT + SimpleUpdate.Type.IDENTITY_DEFAULT -> MessageTypes.KEY_EXCHANGE_IDENTITY_DEFAULT_BIT + SimpleUpdate.Type.CHANGE_NUMBER -> MessageTypes.CHANGE_NUMBER_TYPE + SimpleUpdate.Type.BOOST_REQUEST -> MessageTypes.BOOST_REQUEST_TYPE + SimpleUpdate.Type.END_SESSION -> MessageTypes.END_SESSION_BIT + SimpleUpdate.Type.CHAT_SESSION_REFRESH -> MessageTypes.ENCRYPTION_REMOTE_FAILED_BIT + SimpleUpdate.Type.BAD_DECRYPT -> MessageTypes.BAD_DECRYPT_TYPE + SimpleUpdate.Type.PAYMENTS_ACTIVATED -> MessageTypes.SPECIAL_TYPE_PAYMENTS_ACTIVATED + SimpleUpdate.Type.PAYMENT_ACTIVATION_REQUEST -> MessageTypes.SPECIAL_TYPE_PAYMENTS_ACTIVATE_REQUEST + } + } + updateMessage.expirationTimerChange != null -> { + typeFlags = MessageTypes.EXPIRATION_TIMER_UPDATE_BIT + put(MessageTable.EXPIRES_IN, updateMessage.expirationTimerChange.expiresIn.toLong() * 1000) + } + updateMessage.profileChange != null -> { + typeFlags = MessageTypes.PROFILE_CHANGE_TYPE + val profileChangeDetails = ProfileChangeDetails(profileNameChange = ProfileChangeDetails.StringChange(previous = updateMessage.profileChange.previousName, newValue = updateMessage.profileChange.newName)) + .encode() + put(MessageTable.BODY, Base64.encodeWithPadding(profileChangeDetails)) + } + } + this.put(MessageTable.TYPE, getAsLong(MessageTable.TYPE) or typeFlags) + } + private fun ContentValues.addQuote(quote: Quote) { this.put(MessageTable.QUOTE_ID, quote.targetSentTimestamp) this.put(MessageTable.QUOTE_AUTHOR, backupState.backupToLocalRecipientId[quote.authorId]!!.serialize()) diff --git a/app/src/main/protowire/Backup.proto b/app/src/main/protowire/Backup.proto index b15514dcf1..ef4ffdf1b7 100644 --- a/app/src/main/protowire/Backup.proto +++ b/app/src/main/protowire/Backup.proto @@ -504,6 +504,7 @@ message SimpleUpdate { PAYMENTS_ACTIVATED = 9; PAYMENT_ACTIVATION_REQUEST = 10; } + Type type = 1; } message GroupDescriptionUpdate {