mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-23 02:10:44 +01:00
Don't send group update messages when member labels are changed.
This commit is contained in:
@@ -3,15 +3,20 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
@file:JvmName("DecryptedGroupExtensions")
|
||||
|
||||
package org.whispersystems.signalservice.api.groupsv2
|
||||
|
||||
import org.signal.core.models.ServiceId
|
||||
import org.signal.core.models.ServiceId.ACI
|
||||
import org.signal.storageservice.storage.protos.groups.AccessControl
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroup
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroupChange
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedMember
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedModifyMemberLabel
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedPendingMember
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedRequestingMember
|
||||
import org.signal.storageservice.storage.protos.groups.local.EnabledState
|
||||
import java.util.Optional
|
||||
|
||||
fun Collection<DecryptedMember>.toAciListWithUnknowns(): List<ACI> {
|
||||
@@ -54,3 +59,78 @@ fun DecryptedGroup.Builder.setModifyMemberLabelActions(
|
||||
|
||||
members = updatedMembers
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the group change fields that contain actual changes (value is not empty or default).
|
||||
*/
|
||||
fun DecryptedGroupChange.getChangedFields(): Set<GroupChangeField> {
|
||||
return buildSet {
|
||||
if (newIsAnnouncementGroup != EnabledState.UNKNOWN) add(GroupChangeField.ANNOUNCEMENT_GROUP)
|
||||
if (newAttributeAccess != AccessControl.AccessRequired.UNKNOWN) add(GroupChangeField.ATTRIBUTE_ACCESS)
|
||||
if (newAvatar != null) add(GroupChangeField.AVATAR)
|
||||
if (deleteBannedMembers.isNotEmpty()) add(GroupChangeField.BANNED_MEMBER_REMOVALS)
|
||||
if (newBannedMembers.isNotEmpty()) add(GroupChangeField.BANNED_MEMBERS)
|
||||
if (newDescription != null) add(GroupChangeField.DESCRIPTION)
|
||||
if (newInviteLinkAccess != AccessControl.AccessRequired.UNKNOWN) add(GroupChangeField.INVITE_LINK_ACCESS)
|
||||
if (newInviteLinkPassword.size != 0) add(GroupChangeField.INVITE_LINK_PASSWORD)
|
||||
if (newMemberAccess != AccessControl.AccessRequired.UNKNOWN) add(GroupChangeField.MEMBER_ACCESS)
|
||||
if (modifyMemberLabels.isNotEmpty()) add(GroupChangeField.MEMBER_LABELS)
|
||||
if (deleteMembers.isNotEmpty()) add(GroupChangeField.MEMBER_REMOVALS)
|
||||
if (modifyMemberRoles.isNotEmpty()) add(GroupChangeField.MEMBER_ROLES)
|
||||
if (newMembers.isNotEmpty()) add(GroupChangeField.MEMBERS)
|
||||
if (promotePendingMembers.isNotEmpty()) add(GroupChangeField.PENDING_MEMBER_PROMOTIONS)
|
||||
if (deletePendingMembers.isNotEmpty()) add(GroupChangeField.PENDING_MEMBER_REMOVALS)
|
||||
if (newPendingMembers.isNotEmpty()) add(GroupChangeField.PENDING_MEMBERS)
|
||||
if (promotePendingPniAciMembers.isNotEmpty()) add(GroupChangeField.PNI_ACI_PROMOTIONS)
|
||||
if (modifiedProfileKeys.isNotEmpty()) add(GroupChangeField.PROFILE_KEYS)
|
||||
if (promoteRequestingMembers.isNotEmpty()) add(GroupChangeField.REQUESTING_MEMBER_APPROVALS)
|
||||
if (deleteRequestingMembers.isNotEmpty()) add(GroupChangeField.REQUESTING_MEMBER_REMOVALS)
|
||||
if (newRequestingMembers.isNotEmpty()) add(GroupChangeField.REQUESTING_MEMBERS)
|
||||
if (newTimer != null) add(GroupChangeField.TIMER)
|
||||
if (newTitle != null) add(GroupChangeField.TITLE)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the group change should not be announced to the group members.
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun DecryptedGroupChange.isSilent(
|
||||
changedFields: Set<GroupChangeField> = getChangedFields()
|
||||
): Boolean {
|
||||
return GroupChangeField.silentChanges.containsAll(changedFields)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fields representing possible changes to a group state.
|
||||
* To add a new field, update the enum and add corresponding checks in getChangedFields().
|
||||
*/
|
||||
enum class GroupChangeField(val changeSilently: Boolean = false) {
|
||||
ANNOUNCEMENT_GROUP,
|
||||
ATTRIBUTE_ACCESS,
|
||||
AVATAR,
|
||||
BANNED_MEMBER_REMOVALS,
|
||||
BANNED_MEMBERS(changeSilently = true),
|
||||
DESCRIPTION,
|
||||
INVITE_LINK_ACCESS,
|
||||
INVITE_LINK_PASSWORD,
|
||||
MEMBER_ACCESS,
|
||||
MEMBER_LABELS(changeSilently = true),
|
||||
MEMBER_REMOVALS,
|
||||
MEMBER_ROLES,
|
||||
MEMBERS,
|
||||
PENDING_MEMBER_PROMOTIONS,
|
||||
PENDING_MEMBER_REMOVALS,
|
||||
PENDING_MEMBERS,
|
||||
PNI_ACI_PROMOTIONS,
|
||||
PROFILE_KEYS(changeSilently = true),
|
||||
REQUESTING_MEMBER_APPROVALS,
|
||||
REQUESTING_MEMBER_REMOVALS,
|
||||
REQUESTING_MEMBERS,
|
||||
TIMER,
|
||||
TITLE;
|
||||
|
||||
companion object {
|
||||
val silentChanges = GroupChangeField.entries.filter { it.changeSilently }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import org.signal.storageservice.storage.protos.groups.local.DecryptedBannedMemb
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroup;
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroupChange;
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedMember;
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedModifyMemberLabel;
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedModifyMemberRole;
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedPendingMember;
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedPendingMemberRemoval;
|
||||
@@ -338,7 +337,7 @@ public final class DecryptedGroupUtil {
|
||||
|
||||
applyPromotePendingPniAciMemberActions(builder, change.promotePendingPniAciMembers);
|
||||
|
||||
DecryptedGroupExtensionsKt.setModifyMemberLabelActions(builder, change.modifyMemberLabels);
|
||||
DecryptedGroupExtensions.setModifyMemberLabelActions(builder, change.modifyMemberLabels);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
@@ -722,73 +721,4 @@ public final class DecryptedGroupUtil {
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static boolean changeIsEmpty(DecryptedGroupChange change) {
|
||||
return change.modifiedProfileKeys.size() == 0 && // field 6
|
||||
changeIsEmptyExceptForProfileKeyChanges(change);
|
||||
}
|
||||
|
||||
/*
|
||||
* When updating this, update {@link #changeIsEmptyExceptForBanChangesAndOptionalProfileKeyChanges(DecryptedGroupChange)}
|
||||
*/
|
||||
public static boolean changeIsEmptyExceptForProfileKeyChanges(DecryptedGroupChange change) {
|
||||
return change.newMembers.size() == 0 && // field 3
|
||||
change.deleteMembers.size() == 0 && // field 4
|
||||
change.modifyMemberRoles.size() == 0 && // field 5
|
||||
change.newPendingMembers.size() == 0 && // field 7
|
||||
change.deletePendingMembers.size() == 0 && // field 8
|
||||
change.promotePendingMembers.size() == 0 && // field 9
|
||||
change.newTitle == null && // field 10
|
||||
change.newAvatar == null && // field 11
|
||||
change.newTimer == null && // field 12
|
||||
isEmpty(change.newAttributeAccess) && // field 13
|
||||
isEmpty(change.newMemberAccess) && // field 14
|
||||
isEmpty(change.newInviteLinkAccess) && // field 15
|
||||
change.newRequestingMembers.size() == 0 && // field 16
|
||||
change.deleteRequestingMembers.size() == 0 && // field 17
|
||||
change.promoteRequestingMembers.size() == 0 && // field 18
|
||||
change.newInviteLinkPassword.size() == 0 && // field 19
|
||||
change.newDescription == null && // field 20
|
||||
isEmpty(change.newIsAnnouncementGroup) && // field 21
|
||||
change.newBannedMembers.size() == 0 && // field 22
|
||||
change.deleteBannedMembers.size() == 0 && // field 23
|
||||
change.promotePendingPniAciMembers.size() == 0 && // field 24
|
||||
change.modifyMemberLabels.isEmpty(); // field 26
|
||||
}
|
||||
|
||||
public static boolean changeIsEmptyExceptForBanChangesAndOptionalProfileKeyChanges(DecryptedGroupChange change) {
|
||||
return (change.newBannedMembers.size() != 0 || change.deleteBannedMembers.size() != 0) &&
|
||||
change.newMembers.size() == 0 && // field 3
|
||||
change.deleteMembers.size() == 0 && // field 4
|
||||
change.modifyMemberRoles.size() == 0 && // field 5
|
||||
change.newPendingMembers.size() == 0 && // field 7
|
||||
change.deletePendingMembers.size() == 0 && // field 8
|
||||
change.promotePendingMembers.size() == 0 && // field 9
|
||||
change.newTitle == null && // field 10
|
||||
change.newAvatar == null && // field 11
|
||||
change.newTimer == null && // field 12
|
||||
isEmpty(change.newAttributeAccess) && // field 13
|
||||
isEmpty(change.newMemberAccess) && // field 14
|
||||
isEmpty(change.newInviteLinkAccess) && // field 15
|
||||
change.newRequestingMembers.size() == 0 && // field 16
|
||||
change.deleteRequestingMembers.size() == 0 && // field 17
|
||||
change.promoteRequestingMembers.size() == 0 && // field 18
|
||||
change.newInviteLinkPassword.size() == 0 && // field 19
|
||||
change.newDescription == null && // field 20
|
||||
isEmpty(change.newIsAnnouncementGroup) && // field 21
|
||||
change.promotePendingPniAciMembers.size() == 0 && // field 24
|
||||
change.modifyMemberLabels.isEmpty(); // field 26
|
||||
}
|
||||
|
||||
static boolean isEmpty(AccessControl.AccessRequired newAttributeAccess) {
|
||||
return newAttributeAccess == AccessControl.AccessRequired.UNKNOWN;
|
||||
}
|
||||
|
||||
static boolean isEmpty(EnabledState enabledState) {
|
||||
return enabledState == EnabledState.UNKNOWN;
|
||||
}
|
||||
|
||||
public static boolean changeIsSilent(DecryptedGroupChange plainGroupChange) {
|
||||
return changeIsEmptyExceptForProfileKeyChanges(plainGroupChange) || changeIsEmptyExceptForBanChangesAndOptionalProfileKeyChanges(plainGroupChange);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user