From f2fd3e63c818373bf37dbaffed915674aecfdb8d Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Fri, 5 Jun 2026 13:47:34 -0400 Subject: [PATCH] Prevent accepted group message request from resetting when restored from storage. --- .../securesms/database/RecipientTable.kt | 9 ++++++++ .../v2/processing/GroupsV2StateProcessor.kt | 5 ++++ .../processing/GroupsV2StateProcessorTest.kt | 23 +++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt index e93ae54166..97dc98b642 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientTable.kt @@ -2128,6 +2128,15 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da } } + fun isProfileSharing(groupId: GroupId): Boolean { + return readableDatabase + .select(PROFILE_SHARING) + .from(TABLE_NAME) + .where("$GROUP_ID = ?", groupId.toString()) + .run() + .readToSingleBoolean(defaultValue = false) + } + fun setNotificationChannel(id: RecipientId, notificationChannel: String?) { val contentValues = ContentValues(1).apply { put(NOTIFICATION_CHANNEL, notificationChannel) 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 9046a86cac..2f86c35019 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 @@ -713,6 +713,11 @@ class GroupsV2StateProcessor private constructor( return } + if (SignalDatabase.recipients.isProfileSharing(groupId)) { + Log.i(TAG, "Profile sharing already enabled for $groupId. Leaving as-is.") + return + } + val selfAsMember = DecryptedGroupUtil.findMemberByAci(newLocalState.members, aci).orNull() val selfAsPending = DecryptedGroupUtil.findPendingByServiceId(newLocalState.pendingMembers, aci).orNull() diff --git a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessorTest.kt b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessorTest.kt index 9d3fefe667..79cab4e74a 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessorTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/groups/v2/processing/GroupsV2StateProcessorTest.kt @@ -142,6 +142,8 @@ class GroupsV2StateProcessorTest { mockkObject(ProfileAndMessageHelper) every { ProfileAndMessageHelper.create(any(), any(), any()) } returns profileAndMessageHelper + every { recipientTable.isProfileSharing(groupId) } answers { false } + every { groupsV2Operations.forGroup(secretParams) } answers { callOriginal() } processor = GroupsV2StateProcessor.forGroup(serviceIds, masterKey, secretParams) @@ -1462,4 +1464,25 @@ class GroupsV2StateProcessorTest { verify { groupTable.create(masterKey, result.latestServer!!, null, null) } verify(exactly = 0) { recipientTable.rotateStorageId(any()) } } + + @Test + fun `when group already has profile sharing enabled, then setProfileSharing does not re-derive it from membership`() { + val joinedAtRevision = 1 + val newLocalState = DecryptedGroup( + revision = joinedAtRevision, + members = listOf(member(otherAci), member(selfAci, joinedAt = joinedAtRevision)) + ) + val addedByOtherChange = DecryptedGroupChange( + revision = joinedAtRevision, + editorServiceIdBytes = otherAci.toByteString() + ) + val groupStateDiff = GroupStateDiff(previousGroupState = null, changedGroupState = newLocalState, change = addedByOtherChange) + + every { recipientTable.isProfileSharing(groupId) } answers { true } + + profileAndMessageHelper.setProfileSharing(groupStateDiff, newLocalState, needsAvatarFetch = true) + + verify { recipientTable.isProfileSharing(groupId) } + verify(exactly = 0) { recipientTable.setProfileSharing(any(), any()) } + } }