From 84cb0d357b27139ac73a5249e754862569d91d68 Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Mon, 25 Nov 2024 16:46:24 -0500 Subject: [PATCH] Fix export bugs causing validation errors. --- .../database/MessageTableArchiveExtensions.kt | 11 +++++++++++ .../v2/exporters/ChatItemArchiveExporter.kt | 12 ++++++++++-- .../model/GroupsV2UpdateMessageConverter.kt | 17 ++++++++++++----- .../signalservice/api/push/ServiceId.kt | 5 +++++ 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/MessageTableArchiveExtensions.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/MessageTableArchiveExtensions.kt index d3b49ce4cb..9893ca7dfe 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/MessageTableArchiveExtensions.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/MessageTableArchiveExtensions.kt @@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.backup.v2.exporters.ChatItemArchiveExporter import org.thoughtcrime.securesms.backup.v2.importer.ChatItemArchiveImporter import org.thoughtcrime.securesms.database.GroupTable import org.thoughtcrime.securesms.database.MessageTable +import org.thoughtcrime.securesms.database.MessageTypes import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.recipients.RecipientId @@ -78,6 +79,16 @@ fun MessageTable.getMessagesForBackup(db: SignalDatabase, backupTime: Long, medi """ ) + // If someone re-registers with a new phone number, previous outgoing messages will no longer be associated with self. + // This cleans it up by changing the from to be the current self id for all outgoing messages. + db.rawWritableDatabase.execSQL( + """ + UPDATE ${MessageTable.TABLE_NAME} + SET ${MessageTable.FROM_RECIPIENT_ID} = ${selfRecipientId.toLong()} + WHERE (${MessageTable.TYPE} & ${MessageTypes.BASE_TYPE_MASK}) IN (${MessageTypes.OUTGOING_MESSAGE_TYPES.joinToString(",")}) + """ + ) + return ChatItemArchiveExporter( db = db, backupStartTime = backupTime, diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatItemArchiveExporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatItemArchiveExporter.kt index 84dcbba7eb..d96302d163 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatItemArchiveExporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatItemArchiveExporter.kt @@ -237,7 +237,12 @@ class ChatItemArchiveExporter( } MessageTypes.isGroupV2(record.type) && MessageTypes.isGroupUpdate(record.type) -> { - builder.updateMessage = record.toRemoteGroupUpdate() ?: continue + val update = record.toRemoteGroupUpdate() ?: continue + if (update.groupChange!!.updates.isEmpty()) { + Log.w(TAG, "Group update record with ID ${record.id} missing updates. Skipping.") + continue + } + builder.updateMessage = update } MessageTypes.isGroupV1MigrationEvent(record.type) -> { @@ -541,7 +546,10 @@ private fun CallTable.Call.toRemoteCallUpdate(db: SignalDatabase, messageRecord: CallTable.Event.NOT_ACCEPTED -> IndividualCall.State.NOT_ACCEPTED CallTable.Event.ONGOING -> IndividualCall.State.ACCEPTED CallTable.Event.DELETE -> return null - else -> IndividualCall.State.UNKNOWN_STATE + else -> { + Log.w(TAG, "Unable to map 1:1 call state from event: ${this.event.name}") + IndividualCall.State.UNKNOWN_STATE + } }, startedCallTimestamp = this.timestamp, read = messageRecord.read diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageConverter.kt b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageConverter.kt index 6e50e35f81..ae52e61b86 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageConverter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageConverter.kt @@ -6,6 +6,7 @@ package org.thoughtcrime.securesms.database.model import okio.ByteString +import okio.ByteString.Companion.toByteString import org.signal.core.util.StringUtil import org.signal.core.util.isNullOrEmpty import org.signal.storageservice.protos.groups.AccessControl @@ -50,7 +51,7 @@ import org.thoughtcrime.securesms.backup.v2.proto.SelfInvitedOtherUserToGroupUpd import org.thoughtcrime.securesms.backup.v2.proto.SelfInvitedToGroupUpdate import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil -import org.whispersystems.signalservice.api.push.ServiceId.Companion.parseOrNull +import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.push.ServiceIds import org.whispersystems.signalservice.api.util.UuidUtil import java.util.LinkedList @@ -131,7 +132,7 @@ object GroupsV2UpdateMessageConverter { } val updates: MutableList = LinkedList() var editorUnknown = change.editorServiceIdBytes.size == 0 - val editorServiceId = if (editorUnknown) null else parseOrNull(change.editorServiceIdBytes) + val editorServiceId = if (editorUnknown) null else ServiceId.parseOrNull(change.editorServiceIdBytes) if (editorServiceId == null || editorServiceId.isUnknown) { editorUnknown = true } @@ -253,10 +254,13 @@ object GroupsV2UpdateMessageConverter { ) ) } else { + val serviceId = ServiceId.parseOrNull(invitee.serviceIdBytes) revokedInvitees.add( - GroupInvitationRevokedUpdate.Invitee( - inviteeAci = invitee.serviceIdBytes - ) + when (serviceId) { + is ServiceId.ACI -> GroupInvitationRevokedUpdate.Invitee(inviteeAci = serviceId.toByteString()) + is ServiceId.PNI -> GroupInvitationRevokedUpdate.Invitee(inviteePni = serviceId.toByteStringWithoutPrefix()) + else -> throw IllegalStateException() + } ) } } @@ -465,6 +469,7 @@ object GroupsV2UpdateMessageConverter { } ) } + AccessRequired.ADMINISTRATOR -> { groupLinkEnabled = true updates.add( @@ -485,6 +490,7 @@ object GroupsV2UpdateMessageConverter { } ) } + AccessRequired.UNSATISFIABLE -> { updates.add( GroupChangeChatUpdate.Update( @@ -494,6 +500,7 @@ object GroupsV2UpdateMessageConverter { ) ) } + else -> {} } if (!groupLinkEnabled && change.newInviteLinkPassword.size > 0) { diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/push/ServiceId.kt b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/push/ServiceId.kt index 6562589e48..0dc4de0076 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/push/ServiceId.kt +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/push/ServiceId.kt @@ -1,12 +1,14 @@ package org.whispersystems.signalservice.api.push import okio.ByteString +import okio.ByteString.Companion.toByteString import org.signal.libsignal.protocol.ServiceId.InvalidServiceIdException import org.signal.libsignal.protocol.SignalProtocolAddress import org.signal.libsignal.protocol.logging.Log import org.whispersystems.signalservice.api.push.ServiceId.ACI import org.whispersystems.signalservice.api.push.ServiceId.PNI import org.whispersystems.signalservice.api.util.UuidUtil +import org.whispersystems.signalservice.api.util.toByteArray import java.util.UUID import org.signal.libsignal.protocol.ServiceId as LibSignalServiceId import org.signal.libsignal.protocol.ServiceId.Aci as LibSignalAci @@ -229,5 +231,8 @@ sealed class ServiceId(val libSignalServiceId: LibSignalServiceId) { /** String version without the PNI: prefix. This is only for specific proto fields. For application storage, prefer [toString]. */ fun toStringWithoutPrefix(): String = rawUuid.toString() + + /** [ByteString] version without the PNI byte prefix. */ + fun toByteStringWithoutPrefix(): ByteString = rawUuid.toByteArray().toByteString() } }