From 8b6b0a30e54f32e7edb95c560d15d84d0578d0b8 Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Wed, 26 Feb 2025 09:54:24 -0500 Subject: [PATCH] Fix pni in aci only field of decline invite for backupv2. --- .../helpers/SignalDatabaseMigrations.kt | 6 +- .../V267_FixGroupInvitationDeclinedUpdate.kt | 74 +++++++++++++++++++ .../model/GroupsV2UpdateMessageConverter.kt | 3 +- .../model/GroupsV2UpdateMessageProducer.java | 2 +- .../migrations/ApplicationMigrations.java | 7 +- 5 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V267_FixGroupInvitationDeclinedUpdate.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt index 61d040e1fd..d775769d3e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt @@ -122,6 +122,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V263_InAppPaymentsS import org.thoughtcrime.securesms.database.helpers.migration.V264_FixGroupAddMemberUpdate import org.thoughtcrime.securesms.database.helpers.migration.V265_FixFtsTriggers import org.thoughtcrime.securesms.database.helpers.migration.V266_UniqueThreadPinOrder +import org.thoughtcrime.securesms.database.helpers.migration.V267_FixGroupInvitationDeclinedUpdate /** * Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness. @@ -247,10 +248,11 @@ object SignalDatabaseMigrations { 263 to V263_InAppPaymentsSubscriberTableRebuild, 264 to V264_FixGroupAddMemberUpdate, 265 to V265_FixFtsTriggers, - 266 to V266_UniqueThreadPinOrder + 266 to V266_UniqueThreadPinOrder, + 267 to V267_FixGroupInvitationDeclinedUpdate ) - const val DATABASE_VERSION = 266 + const val DATABASE_VERSION = 267 @JvmStatic fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V267_FixGroupInvitationDeclinedUpdate.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V267_FixGroupInvitationDeclinedUpdate.kt new file mode 100644 index 0000000000..585899565b --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V267_FixGroupInvitationDeclinedUpdate.kt @@ -0,0 +1,74 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.thoughtcrime.securesms.database.helpers.migration + +import android.app.Application +import androidx.core.content.contentValuesOf +import net.zetetic.database.sqlcipher.SQLiteDatabase +import okio.IOException +import org.signal.core.util.forEach +import org.signal.core.util.logging.Log +import org.signal.core.util.requireBlob +import org.signal.core.util.requireLong +import org.thoughtcrime.securesms.backup.v2.proto.GroupInvitationDeclinedUpdate +import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExtras +import org.whispersystems.signalservice.api.push.ServiceId + +/** + * Ensure we store ACIs only in the ACI only-field and null for PNIs for field [GroupInvitationDeclinedUpdate.inviteeAci] in [GroupInvitationDeclinedUpdate]. + */ +@Suppress("ClassName") +object V267_FixGroupInvitationDeclinedUpdate : SignalDatabaseMigration { + + private val TAG = Log.tag(V267_FixGroupInvitationDeclinedUpdate::class) + + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + val messageExtrasFixes = mutableListOf>() + + db.query("message", arrayOf("_id", "message_extras"), "message_extras IS NOT NULL AND type & 0x10000 != 0", null, null, null, null) + .forEach { cursor -> + val blob = cursor.requireBlob("message_extras")!! + + val messageExtras: MessageExtras? = try { + MessageExtras.ADAPTER.decode(blob) + } catch (e: IOException) { + Log.w(TAG, "Unable to decode message extras", e) + null + } + + if (messageExtras?.gv2UpdateDescription?.groupChangeUpdate?.updates?.any { it.groupInvitationDeclinedUpdate != null } != true) { + return@forEach + } + + val groupUpdateDescription = messageExtras.gv2UpdateDescription + val groupUpdate = groupUpdateDescription.groupChangeUpdate!! + val updates = groupUpdate.updates.toMutableList() + + updates + .replaceAll { change -> + if (change.groupInvitationDeclinedUpdate != null && ServiceId.parseOrNull(change.groupInvitationDeclinedUpdate.inviteeAci) is ServiceId.PNI) { + change.copy(groupInvitationDeclinedUpdate = change.groupInvitationDeclinedUpdate.copy(inviteeAci = null)) + } else { + change + } + } + + val updatedMessageExtras = messageExtras.copy( + gv2UpdateDescription = groupUpdateDescription.copy( + groupChangeUpdate = groupUpdate.copy( + updates = updates + ) + ) + ) + + messageExtrasFixes += cursor.requireLong("_id") to updatedMessageExtras.encode() + } + + messageExtrasFixes.forEach { (id, extras) -> + db.update("message", contentValuesOf("message_extras" to extras), "_id = $id", null) + } + } +} 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 7a043c5940..6cb9b1c4d1 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 @@ -241,9 +241,10 @@ object GroupsV2UpdateMessageConverter { for (invitee in change.deletePendingMembers) { val decline = invitee.serviceIdBytes == editorAci if (decline) { + val inviteeServiceId = ServiceId.parseOrNull(invitee.serviceIdBytes) updates.add( GroupChangeChatUpdate.Update( - groupInvitationDeclinedUpdate = GroupInvitationDeclinedUpdate(inviteeAci = invitee.serviceIdBytes) + groupInvitationDeclinedUpdate = GroupInvitationDeclinedUpdate(inviteeAci = if (inviteeServiceId is ServiceId.ACI) invitee.serviceIdBytes else null) ) ) } else if (selfIds.matches(invitee.serviceIdBytes)) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java index 6e21e75deb..7a52429712 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java @@ -450,7 +450,7 @@ final class GroupsV2UpdateMessageProducer { } private void describeGroupInvitationDeclinedUpdate(@NonNull GroupInvitationDeclinedUpdate update, @NonNull List updates) { - if (selfIds.matches(update.inviteeAci)) { + if (update.inviteeAci != null && selfIds.matches(update.inviteeAci)) { updates.add(updateDescription(context.getString(R.string.MessageRecord_you_declined_the_invitation_to_the_group), R.drawable.ic_update_group_decline_16)); } else { updates.add(updateDescription(context.getString(R.string.MessageRecord_someone_declined_an_invitation_to_the_group), R.drawable.ic_update_group_decline_16)); diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java index b78e64b12a..145fd67dab 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java @@ -172,9 +172,10 @@ public class ApplicationMigrations { static final int DUPLICATE_E164_FIX = 128; static final int FTS_TRIGGER_FIX = 129; static final int THREAD_TABLE_PINNED_MIGRATION = 130; + static final int GROUP_DECLINE_INVITE_FIX = 131; } - public static final int CURRENT_VERSION = 130; + public static final int CURRENT_VERSION = 131; /** * This *must* be called after the {@link JobManager} has been instantiated, but *before* the call @@ -793,6 +794,10 @@ public class ApplicationMigrations { jobs.put(Version.THREAD_TABLE_PINNED_MIGRATION, new DatabaseMigrationJob()); } + if (lastSeenVersion < Version.GROUP_DECLINE_INVITE_FIX) { + jobs.put(Version.GROUP_DECLINE_INVITE_FIX, new DatabaseMigrationJob()); + } + return jobs; }