From f427f313039ca08e202f9918df258ab321a02037 Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Wed, 15 Apr 2026 16:09:58 -0400 Subject: [PATCH] Improve group change defensive checks and update logic. --- .../v2/processing/GroupsV2StateProcessor.kt | 44 ++++++++++--------- .../jobs/GroupV2UpdateSelfProfileKeyJob.java | 20 +++++++++ 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessor.kt index 1ec42c2258..4516d3c0c7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessor.kt @@ -591,26 +591,7 @@ class GroupsV2StateProcessor private constructor( Log.i(TAG, "$logPrefix Local state (revision: ${currentLocalState?.revision}) does not match, updating to ${updatedGroupState.revision}") } - val wasTerminated = updatedGroupState.terminated && (currentLocalState == null || !currentLocalState.terminated) - val terminatorRecipientId: RecipientId? = if (wasTerminated) { - groupStateDiff.serverHistory - .mapNotNull { it.change } - .firstOrNull { it.terminateGroup } - ?.let { ServiceId.parseOrNull(it.editorServiceIdBytes) } - ?.let { RecipientId.from(it) } - } else { - null - } - - saveGroupState(groupStateDiff, updatedGroupState, groupSendEndorsements, terminatorRecipientId) - - if (terminatorRecipientId != null) { - profileAndMessageHelper.stopAllTypingForGroup() - } - - if (wasTerminated) { - ConversationShortcutUpdateJob.enqueue() - } + saveGroupState(groupStateDiff, updatedGroupState, groupSendEndorsements) if (currentLocalState == null || currentLocalState.revision == RESTORE_PLACEHOLDER_REVISION) { if (!updatedGroupState.terminated) { @@ -639,13 +620,29 @@ class GroupsV2StateProcessor private constructor( return InternalUpdateResult.Updated(updatedGroupState) } - private fun saveGroupState(groupStateDiff: GroupStateDiff, updatedGroupState: DecryptedGroup, groupSendEndorsements: ReceivedGroupSendEndorsements?, terminatorRecipientId: RecipientId? = null) { + private fun saveGroupState( + groupStateDiff: GroupStateDiff, + updatedGroupState: DecryptedGroup, + groupSendEndorsements: ReceivedGroupSendEndorsements? + ) { val previousGroupState = groupStateDiff.previousGroupState if (groupSendEndorsements != null) { Log.i(TAG, "$logPrefix Updating send endorsements") } + val wasTerminated = updatedGroupState.terminated && (previousGroupState == null || !previousGroupState.terminated) + val terminatorRecipientId: RecipientId? = if (wasTerminated) { + groupStateDiff + .serverHistory + .mapNotNull { it.change } + .firstOrNull { it.terminateGroup } + ?.let { ServiceId.parseOrNull(it.editorServiceIdBytes) } + ?.let { RecipientId.from(it) } + } else { + null + } + val needsAvatarFetch = if (previousGroupState == null) { val groupId = SignalDatabase.groups.create(groupMasterKey, updatedGroupState, groupSendEndorsements) @@ -661,6 +658,11 @@ class GroupsV2StateProcessor private constructor( updatedGroupState.avatar != previousGroupState.avatar } + if (wasTerminated) { + profileAndMessageHelper.stopAllTypingForGroup() + ConversationShortcutUpdateJob.enqueue() + } + if (needsAvatarFetch) { AppDependencies.jobManager.add(AvatarGroupsV2DownloadJob(groupId, updatedGroupState.avatar)) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupV2UpdateSelfProfileKeyJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupV2UpdateSelfProfileKeyJob.java index e5aa0a5a88..a6c4145a81 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupV2UpdateSelfProfileKeyJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupV2UpdateSelfProfileKeyJob.java @@ -123,6 +123,10 @@ public final class GroupV2UpdateSelfProfileKeyJob extends BaseJob { continue; } + if (Recipient.externalGroupExact(id).isBlocked()) { + continue; + } + ByteString selfUuidBytes = Recipient.self().requireAci().toByteString(); boolean isActive = group.get().isActive(); DecryptedMember selfMember = group.get().requireV2GroupProperties().getDecryptedGroup().members @@ -170,6 +174,22 @@ public final class GroupV2UpdateSelfProfileKeyJob extends BaseJob { return; } + Optional group = SignalDatabase.groups().getGroup(groupId); + if (!group.isPresent()) { + Log.w(TAG, "Group " + group + " no longer exists?"); + return; + } + + if (Recipient.externalGroupExact(groupId).isBlocked()) { + Log.i(TAG, "Not updating blocked group " + groupId); + return; + } + + if (!group.get().isActive()) { + Log.i(TAG, "Group is not active, skipping update."); + return; + } + Log.i(TAG, "Ensuring profile key up to date on group " + groupId); GroupManager.updateSelfProfileKeyInGroup(context, groupId); }