diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt index 249b8c0a2c..a6889c6f4a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt @@ -103,6 +103,8 @@ import org.thoughtcrime.securesms.database.model.StoryType import org.thoughtcrime.securesms.database.model.StoryType.Companion.fromCode import org.thoughtcrime.securesms.database.model.StoryViewState import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList +import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context +import org.thoughtcrime.securesms.database.model.databaseprotos.GV2UpdateDescription import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge import org.thoughtcrime.securesms.database.model.databaseprotos.GroupCallUpdateDetails import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExportState @@ -3817,20 +3819,25 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val secondLatestMessage = reader.getNext() val id: Long - val encodedBody: String + val updatedContext: DecryptedGroupV2Context + val messageExtras: MessageExtras? val changeRevision: Int = message.groupContext?.let { GroupV2UpdateMessageUtil.getChangeRevision(it) } ?: -1 if (secondLatestMessage != null && secondLatestMessage.isGroupV2JoinRequest(changeEditor.get())) { id = secondLatestMessage.id - encodedBody = MessageRecord.createNewContextWithAppendedDeleteJoinRequest(secondLatestMessage, changeRevision, changeEditor.get().toByteString()) + messageExtras = secondLatestMessage.messageExtras + updatedContext = MessageRecord.createNewContextWithAppendedDeleteJoinRequest(secondLatestMessage, changeRevision, changeEditor.get().toByteString()) deleteMessage(latestMessage.id) } else { id = latestMessage.id - encodedBody = MessageRecord.createNewContextWithAppendedDeleteJoinRequest(latestMessage, changeRevision, changeEditor.get().toByteString()) + messageExtras = latestMessage.messageExtras + updatedContext = MessageRecord.createNewContextWithAppendedDeleteJoinRequest(latestMessage, changeRevision, changeEditor.get().toByteString()) } + val updatedMessageExtras = (messageExtras?.newBuilder() ?: MessageExtras.Builder()).gv2UpdateDescription(GV2UpdateDescription(gv2ChangeDescription = updatedContext)).build() + db.update(TABLE_NAME) - .values(BODY to encodedBody) + .values(MESSAGE_EXTRAS to updatedMessageExtras.encode()) .where("$ID = ?", id) .run() diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java index 097cfe267e..394dcef6aa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java @@ -24,12 +24,10 @@ import android.text.style.RelativeSizeSpan; import android.text.style.StyleSpan; import androidx.annotation.ColorInt; -import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.annotation.WorkerThread; -import androidx.compose.ui.text.AnnotatedString; import androidx.core.content.ContextCompat; import com.annimon.stream.Stream; @@ -40,6 +38,8 @@ import org.signal.core.util.logging.Log; import org.signal.storageservice.protos.groups.local.DecryptedGroup; import org.signal.storageservice.protos.groups.local.DecryptedGroupChange; import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.backup.v2.proto.GroupChangeChatUpdate; +import org.thoughtcrime.securesms.backup.v2.proto.GroupCreationUpdate; import org.thoughtcrime.securesms.components.emoji.EmojiProvider; import org.thoughtcrime.securesms.components.emoji.parsing.EmojiParser; import org.thoughtcrime.securesms.components.transfercontrols.TransferControlView; @@ -55,9 +55,7 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.SessionSwitchove import org.thoughtcrime.securesms.database.model.databaseprotos.ThreadMergeEvent; import org.thoughtcrime.securesms.emoji.EmojiSource; import org.thoughtcrime.securesms.emoji.JumboEmoji; -import org.thoughtcrime.securesms.fonts.SignalSymbols; import org.thoughtcrime.securesms.fonts.SignalSymbols.Glyph; -import org.thoughtcrime.securesms.fonts.SignalSymbols.Weight; import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.mms.Slide; @@ -305,12 +303,22 @@ public abstract class MessageRecord extends DisplayRecord { public boolean isSelfCreatedGroup() { DecryptedGroupV2Context decryptedGroupV2Context = getDecryptedGroupV2Context(); - if (decryptedGroupV2Context == null) { - return false; - } - DecryptedGroupChange change = decryptedGroupV2Context.change; + if (decryptedGroupV2Context != null) { + DecryptedGroupChange change = decryptedGroupV2Context.change; - return selfCreatedGroup(change); + return selfCreatedGroup(change); + } + + GroupChangeChatUpdate groupChangeChatUpdate = getGroupChangeChatUpdate(); + if (groupChangeChatUpdate != null) { + GroupCreationUpdate update = groupChangeChatUpdate.updates.stream().filter(u -> u.groupCreationUpdate != null).map(u -> u.groupCreationUpdate).findFirst().orElse(null); + + return update != null && + update.updaterAci != null && + update.updaterAci.equals(SignalStore.account().requireAci().toByteString()); + } + + return false; } public @Nullable MessageExtras getMessageExtras() { @@ -343,6 +351,18 @@ public abstract class MessageRecord extends DisplayRecord { return decryptedGroupV2Context; } + private @Nullable GroupChangeChatUpdate getGroupChangeChatUpdate() { + if (!isGroupUpdate() || !isGroupV2()) { + return null; + } + + if (messageExtras != null && messageExtras.gv2UpdateDescription != null) { + return messageExtras.gv2UpdateDescription.groupChangeUpdate; + } + + return null; + } + private static boolean selfCreatedGroup(@Nullable DecryptedGroupChange change) { return change != null && change.revision == 0 && @@ -552,6 +572,12 @@ public abstract class MessageRecord extends DisplayRecord { if (decryptedGroupV2Context != null) { return decryptedGroupV2Context.change != null && decryptedGroupV2Context.change.newDescription != null; } + + GroupChangeChatUpdate updates = getGroupChangeChatUpdate(); + if (updates != null) { + return updates.updates.stream().anyMatch(update -> update.groupDescriptionUpdate != null); + } + return false; } @@ -560,6 +586,15 @@ public abstract class MessageRecord extends DisplayRecord { if (decryptedGroupV2Context != null && decryptedGroupV2Context.change != null) { return decryptedGroupV2Context.change.newDescription != null ? decryptedGroupV2Context.change.newDescription.value_ : ""; } + + GroupChangeChatUpdate updates = getGroupChangeChatUpdate(); + if (updates != null) { + return updates.updates.stream() + .filter(u -> u.groupDescriptionUpdate != null) + .map(u -> u.groupDescriptionUpdate.newDescription) + .findFirst() + .orElse(""); + } return ""; } @@ -594,7 +629,7 @@ public abstract class MessageRecord extends DisplayRecord { return false; } - public static @NonNull String createNewContextWithAppendedDeleteJoinRequest(@NonNull MessageRecord messageRecord, int revision, @NonNull ByteString id) { + public static @NonNull DecryptedGroupV2Context createNewContextWithAppendedDeleteJoinRequest(@NonNull MessageRecord messageRecord, int revision, @NonNull ByteString id) { DecryptedGroupV2Context decryptedGroupV2Context = messageRecord.getDecryptedGroupV2Context(); if (decryptedGroupV2Context != null && decryptedGroupV2Context.change != null) { @@ -603,13 +638,12 @@ public abstract class MessageRecord extends DisplayRecord { List deleteRequestingMembers = new ArrayList<>(change.deleteRequestingMembers); deleteRequestingMembers.add(id); - return Base64.encodeWithPadding(decryptedGroupV2Context.newBuilder() - .change(change.newBuilder() - .revision(revision) - .deleteRequestingMembers(deleteRequestingMembers) - .build()) - .build() - .encode()); + return decryptedGroupV2Context.newBuilder() + .change(change.newBuilder() + .revision(revision) + .deleteRequestingMembers(deleteRequestingMembers) + .build()) + .build(); } throw new AssertionError("Attempting to modify a message with no change"); diff --git a/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2Transformer.kt b/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2Transformer.kt index 99bee73d83..bdada89108 100644 --- a/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2Transformer.kt +++ b/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2Transformer.kt @@ -36,11 +36,11 @@ private fun DecryptedGroup.formatAsHtml(): String { return """ Revision: $revision Title: $title - Avatar: ${(avatar?.length ?: 0) != 0} - Timer: ${disappearingMessagesTimer!!.duration} + Avatar: ${(avatar.length) != 0} + Timer: ${disappearingMessagesTimer?.duration} Description: "$description" Announcement: $isAnnouncementGroup - Access: attributes(${accessControl!!.attributes}) members(${accessControl!!.members}) link(${accessControl!!.addFromInviteLink}) + Access: attributes(${accessControl?.attributes}) members(${accessControl?.members}) link(${accessControl?.addFromInviteLink}) Members: $members Pending: $pending Requesting: $requesting diff --git a/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2UpdateTransformer.kt b/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2UpdateTransformer.kt index fd78a3231b..b9528bb7b5 100644 --- a/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2UpdateTransformer.kt +++ b/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2UpdateTransformer.kt @@ -50,7 +50,9 @@ object GV2UpdateTransformer : ColumnTransformer { private fun messageExtrasGroupUpdate(messageExtras: MessageExtras): String { val gv2ChangeDescription: UpdateDescription = MessageRecord.getGv2ChangeDescription(AppDependencies.application, messageExtras, null) - return "${gv2ChangeDescription.spannable}

${messageExtras.gv2UpdateDescription!!.gv2ChangeDescription!!.change}" + val gv2ChangeProto: Any? = messageExtras.gv2UpdateDescription?.gv2ChangeDescription?.change ?: messageExtras.gv2UpdateDescription?.groupChangeUpdate + + return "${gv2ChangeDescription.spannable}

$gv2ChangeProto" } } diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/model/MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest.kt b/app/src/test/java/org/thoughtcrime/securesms/database/model/MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest.kt index f15a8edabf..94816fb5d4 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/model/MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/database/model/MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest.kt @@ -6,7 +6,6 @@ import okio.ByteString import okio.ByteString.Companion.toByteString import org.junit.Assert.assertEquals import org.junit.Test -import org.signal.core.util.Base64 import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context import org.thoughtcrime.securesms.groups.v2.ChangeBuilder import org.whispersystems.signalservice.api.push.ServiceId.ACI @@ -65,9 +64,7 @@ class MessageRecordTest_createNewContextWithAppendedDeleteJoinRequest { every { decryptedGroupV2Context } returns context } - val newEncodedBody = MessageRecord.createNewContextWithAppendedDeleteJoinRequest(messageRecord, 10, aliceByteString) - - val newContext = DecryptedGroupV2Context.ADAPTER.decode(Base64.decode(newEncodedBody)) + val newContext = MessageRecord.createNewContextWithAppendedDeleteJoinRequest(messageRecord, 10, aliceByteString) assertEquals("revision updated to 10", newContext.change?.revision, 10) assertEquals("change should retain join request", newContext.change?.newRequestingMembers?.single()?.aciBytes, aliceByteString) diff --git a/spinner/lib/src/main/java/org/signal/spinner/SpinnerServer.kt b/spinner/lib/src/main/java/org/signal/spinner/SpinnerServer.kt index 759284f33c..ef4ab4c6c2 100644 --- a/spinner/lib/src/main/java/org/signal/spinner/SpinnerServer.kt +++ b/spinner/lib/src/main/java/org/signal/spinner/SpinnerServer.kt @@ -350,6 +350,7 @@ internal class SpinnerServer( try { row += transformers[i].transform(null, columnName, this) } catch (e: Exception) { + Log.w(TAG, "Failed to transform", e) row += "*Failed to Transform*\n\n${DefaultColumnTransformer.transform(null, columnName, this)}" } }