mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-05-01 22:25:46 +01:00
Introduce new add member labels permission.
This commit is contained in:
@@ -48,4 +48,6 @@ public interface ChangeSetModifier {
|
||||
void removePromotePendingPniAciMembers(int i);
|
||||
|
||||
void removeModifyMemberLabels(int i);
|
||||
|
||||
void clearModifyMemberLabelAccess();
|
||||
}
|
||||
|
||||
@@ -114,6 +114,10 @@ internal class DecryptedGroupChangeActionsBuilderChangeSetModifier(private val r
|
||||
result.modifyMemberLabels = result.modifyMemberLabels.removeIndex(i)
|
||||
}
|
||||
|
||||
override fun clearModifyMemberLabelAccess() {
|
||||
result.newMemberLabelAccess = AccessControl.AccessRequired.UNKNOWN
|
||||
}
|
||||
|
||||
private fun <T> List<T>.removeIndex(i: Int): List<T> {
|
||||
val modifiedList = this.toMutableList()
|
||||
modifiedList.removeAt(i)
|
||||
|
||||
@@ -74,6 +74,7 @@ fun DecryptedGroupChange.getChangedFields(): Set<GroupChangeField> {
|
||||
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 (newMemberLabelAccess != AccessControl.AccessRequired.UNKNOWN) add(GroupChangeField.MEMBER_LABEL_ACCESS)
|
||||
if (modifyMemberLabels.isNotEmpty()) add(GroupChangeField.MEMBER_LABELS)
|
||||
if (deleteMembers.isNotEmpty()) add(GroupChangeField.MEMBER_REMOVALS)
|
||||
if (modifyMemberRoles.isNotEmpty()) add(GroupChangeField.MEMBER_ROLES)
|
||||
@@ -115,6 +116,7 @@ enum class GroupChangeField(val changeSilently: Boolean = false) {
|
||||
INVITE_LINK_ACCESS,
|
||||
INVITE_LINK_PASSWORD,
|
||||
MEMBER_ACCESS,
|
||||
MEMBER_LABEL_ACCESS,
|
||||
MEMBER_LABELS(changeSilently = true),
|
||||
MEMBER_REMOVALS,
|
||||
MEMBER_ROLES,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.whispersystems.signalservice.api.groupsv2;
|
||||
|
||||
import org.signal.core.models.ServiceId;
|
||||
import org.signal.core.models.ServiceId.ACI;
|
||||
import org.signal.libsignal.protocol.logging.Log;
|
||||
import org.signal.storageservice.storage.protos.groups.AccessControl;
|
||||
import org.signal.storageservice.storage.protos.groups.Member;
|
||||
@@ -13,8 +15,6 @@ import org.signal.storageservice.storage.protos.groups.local.DecryptedPendingMem
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedPendingMemberRemoval;
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedRequestingMember;
|
||||
import org.signal.storageservice.storage.protos.groups.local.EnabledState;
|
||||
import org.signal.core.models.ServiceId;
|
||||
import org.signal.core.models.ServiceId.ACI;
|
||||
import org.whispersystems.signalservice.api.push.ServiceIds;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -323,6 +323,8 @@ public final class DecryptedGroupUtil {
|
||||
|
||||
applyModifyAddFromInviteLinkAccessControlAction(builder, change);
|
||||
|
||||
applyModifyMemberLabelAccessControlAction(builder, change);
|
||||
|
||||
applyAddRequestingMembers(builder, change.newRequestingMembers);
|
||||
|
||||
applyDeleteRequestingMembers(builder, change.deleteRequestingMembers);
|
||||
@@ -524,6 +526,15 @@ public final class DecryptedGroupUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyModifyMemberLabelAccessControlAction(DecryptedGroup.Builder builder, DecryptedGroupChange change) {
|
||||
AccessControl.AccessRequired newAccessLevel = change.newMemberLabelAccess;
|
||||
|
||||
if (newAccessLevel != AccessControl.AccessRequired.UNKNOWN) {
|
||||
AccessControl.Builder accessControlBuilder = builder.accessControl != null ? builder.accessControl.newBuilder() : new AccessControl.Builder();
|
||||
builder.accessControl(accessControlBuilder.memberLabel(newAccessLevel).build());
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyAddRequestingMembers(DecryptedGroup.Builder builder, List<DecryptedRequestingMember> newRequestingMembers) {
|
||||
List<DecryptedRequestingMember> requestingMembers = new ArrayList<>(builder.requestingMembers);
|
||||
requestingMembers.addAll(newRequestingMembers);
|
||||
|
||||
@@ -105,6 +105,10 @@ internal class GroupChangeActionsBuilderChangeSetModifier(private val result: Gr
|
||||
result.modifyMemberLabels = result.modifyMemberLabels.removeIndex(i)
|
||||
}
|
||||
|
||||
override fun clearModifyMemberLabelAccess() {
|
||||
result.modifyMemberLabelAccess = null
|
||||
}
|
||||
|
||||
private fun <T> List<T>.removeIndex(i: Int): List<T> {
|
||||
val modifiedList = this.toMutableList()
|
||||
modifiedList.removeAt(i)
|
||||
|
||||
@@ -151,6 +151,12 @@ public final class GroupChangeReconstruct {
|
||||
}
|
||||
}
|
||||
|
||||
if (fromState.accessControl == null || (toState.accessControl != null && !fromState.accessControl.memberLabel.equals(toState.accessControl.memberLabel))) {
|
||||
if (toState.accessControl != null) {
|
||||
builder.newMemberLabelAccess(toState.accessControl.memberLabel);
|
||||
}
|
||||
}
|
||||
|
||||
builder.newRequestingMembers(new ArrayList<>(intersectRequestingByAci(toState.requestingMembers, newRequestingMemberAcis)));
|
||||
|
||||
builder.deleteRequestingMembers(rejectedRequestMembers.stream().map(requestingMember -> requestingMember.aciBytes).collect(Collectors.toList()));
|
||||
|
||||
@@ -29,29 +29,30 @@ public final class GroupChangeUtil {
|
||||
* True iff there are no change actions.
|
||||
*/
|
||||
public static boolean changeIsEmpty(GroupChange.Actions change) {
|
||||
return change.addMembers.size() == 0 && // field 3
|
||||
change.deleteMembers.size() == 0 && // field 4
|
||||
change.modifyMemberRoles.size() == 0 && // field 5
|
||||
change.modifyMemberProfileKeys.size() == 0 && // field 6
|
||||
change.addMembersPendingProfileKey.size() == 0 && // field 7
|
||||
change.deleteMembersPendingProfileKey.size() == 0 && // field 8
|
||||
change.promoteMembersPendingProfileKey.size() == 0 && // field 9
|
||||
change.modifyTitle == null && // field 10
|
||||
change.modifyAvatar == null && // field 11
|
||||
change.modifyDisappearingMessageTimer == null && // field 12
|
||||
change.modifyAttributesAccess == null && // field 13
|
||||
change.modifyMemberAccess == null && // field 14
|
||||
change.modifyAddFromInviteLinkAccess == null && // field 15
|
||||
change.addMembersPendingAdminApproval.size() == 0 && // field 16
|
||||
change.deleteMembersPendingAdminApproval.size() == 0 && // field 17
|
||||
change.promoteMembersPendingAdminApproval.size() == 0 && // field 18
|
||||
change.modifyInviteLinkPassword == null && // field 19
|
||||
change.modifyDescription == null && // field 20
|
||||
change.modify_announcements_only == null && // field 21
|
||||
change.add_members_banned.size() == 0 && // field 22
|
||||
change.delete_members_banned.size() == 0 && // field 23
|
||||
change.promote_members_pending_pni_aci_profile_key.size() == 0 && // field 24
|
||||
change.modifyMemberLabels.isEmpty(); // field 26
|
||||
return change.addMembers.isEmpty() && // field 3
|
||||
change.deleteMembers.isEmpty() && // field 4
|
||||
change.modifyMemberRoles.isEmpty() && // field 5
|
||||
change.modifyMemberProfileKeys.isEmpty() && // field 6
|
||||
change.addMembersPendingProfileKey.isEmpty() && // field 7
|
||||
change.deleteMembersPendingProfileKey.isEmpty() && // field 8
|
||||
change.promoteMembersPendingProfileKey.isEmpty() && // field 9
|
||||
change.modifyTitle == null && // field 10
|
||||
change.modifyAvatar == null && // field 11
|
||||
change.modifyDisappearingMessageTimer == null && // field 12
|
||||
change.modifyAttributesAccess == null && // field 13
|
||||
change.modifyMemberAccess == null && // field 14
|
||||
change.modifyAddFromInviteLinkAccess == null && // field 15
|
||||
change.addMembersPendingAdminApproval.isEmpty() && // field 16
|
||||
change.deleteMembersPendingAdminApproval.isEmpty() && // field 17
|
||||
change.promoteMembersPendingAdminApproval.isEmpty() && // field 18
|
||||
change.modifyInviteLinkPassword == null && // field 19
|
||||
change.modifyDescription == null && // field 20
|
||||
change.modify_announcements_only == null && // field 21
|
||||
change.add_members_banned.isEmpty() && // field 22
|
||||
change.delete_members_banned.isEmpty() && // field 23
|
||||
change.promote_members_pending_pni_aci_profile_key.isEmpty() && // field 24
|
||||
change.modifyMemberLabels.isEmpty() && // field 26
|
||||
change.modifyMemberLabelAccess == null; // field 27
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,6 +156,7 @@ public final class GroupChangeUtil {
|
||||
resolveField23DeleteBannedMembers (conflictingChange, changeSetModifier, bannedMembersByServiceId);
|
||||
resolveField24PromotePendingPniAciMembers (conflictingChange, changeSetModifier, fullMembersByUuid);
|
||||
resolveField26ModifyMemberLabels (conflictingChange, changeSetModifier, fullMembersByUuid);
|
||||
resolveField27ModifyMemberLabelAccess (groupState, conflictingChange, changeSetModifier);
|
||||
}
|
||||
|
||||
private static void resolveField3AddMembers(DecryptedGroupChange conflictingChange, ChangeSetModifier result, HashMap<ByteString, DecryptedMember> fullMembersByUuid, HashMap<ByteString, DecryptedPendingMember> pendingMembersByServiceId) {
|
||||
@@ -390,4 +392,15 @@ public final class GroupChangeUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void resolveField27ModifyMemberLabelAccess(
|
||||
@Nonnull DecryptedGroup groupState,
|
||||
@Nonnull DecryptedGroupChange conflictingChange,
|
||||
@Nonnull ChangeSetModifier result
|
||||
)
|
||||
{
|
||||
if (groupState.accessControl != null && conflictingChange.newMemberLabelAccess == groupState.accessControl.memberLabel) {
|
||||
result.clearModifyMemberLabelAccess();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package org.whispersystems.signalservice.api.groupsv2;
|
||||
|
||||
import org.signal.core.models.ServiceId;
|
||||
import org.signal.core.models.ServiceId.ACI;
|
||||
import org.signal.core.models.ServiceId.PNI;
|
||||
import org.signal.core.util.UuidUtil;
|
||||
import org.signal.libsignal.protocol.logging.Log;
|
||||
import org.signal.libsignal.zkgroup.InvalidInputException;
|
||||
import org.signal.libsignal.zkgroup.NotarySignature;
|
||||
@@ -17,14 +21,14 @@ import org.signal.libsignal.zkgroup.profiles.ExpiringProfileKeyCredential;
|
||||
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
|
||||
import org.signal.libsignal.zkgroup.profiles.ProfileKeyCredentialPresentation;
|
||||
import org.signal.storageservice.storage.protos.groups.AccessControl;
|
||||
import org.signal.storageservice.storage.protos.groups.MemberBanned;
|
||||
import org.signal.storageservice.storage.protos.groups.Group;
|
||||
import org.signal.storageservice.storage.protos.groups.GroupAttributeBlob;
|
||||
import org.signal.storageservice.storage.protos.groups.GroupChange;
|
||||
import org.signal.storageservice.storage.protos.groups.GroupJoinInfo;
|
||||
import org.signal.storageservice.storage.protos.groups.Member;
|
||||
import org.signal.storageservice.storage.protos.groups.MemberPendingProfileKey;
|
||||
import org.signal.storageservice.storage.protos.groups.MemberBanned;
|
||||
import org.signal.storageservice.storage.protos.groups.MemberPendingAdminApproval;
|
||||
import org.signal.storageservice.storage.protos.groups.MemberPendingProfileKey;
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedApproveMember;
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedBannedMember;
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroup;
|
||||
@@ -39,10 +43,6 @@ import org.signal.storageservice.storage.protos.groups.local.DecryptedRequesting
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedString;
|
||||
import org.signal.storageservice.storage.protos.groups.local.DecryptedTimer;
|
||||
import org.signal.storageservice.storage.protos.groups.local.EnabledState;
|
||||
import org.signal.core.models.ServiceId;
|
||||
import org.signal.core.models.ServiceId.ACI;
|
||||
import org.signal.core.models.ServiceId.PNI;
|
||||
import org.signal.core.util.UuidUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -53,11 +53,11 @@ import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
@@ -344,6 +344,12 @@ public final class GroupsV2Operations {
|
||||
);
|
||||
}
|
||||
|
||||
public GroupChange.Actions.Builder createChangeMemberLabelRights(AccessControl.AccessRequired newRights) {
|
||||
return new GroupChange.Actions.Builder().modifyMemberLabelAccess(
|
||||
new GroupChange.Actions.ModifyMemberLabelAccessControlAction.Builder().memberLabelAccess(newRights).build()
|
||||
);
|
||||
}
|
||||
|
||||
public GroupChange.Actions.Builder createAnnouncementGroupChange(boolean isAnnouncementGroup) {
|
||||
return new GroupChange.Actions.Builder().modify_announcements_only(
|
||||
new GroupChange.Actions.ModifyAnnouncementsOnlyAction.Builder().announcements_only(isAnnouncementGroup).build()
|
||||
@@ -770,6 +776,11 @@ public final class GroupsV2Operations {
|
||||
}
|
||||
builder.modifyMemberLabels(modifyMemberLabels);
|
||||
|
||||
// Field 27
|
||||
if (actions.modifyMemberLabelAccess != null) {
|
||||
builder.newMemberLabelAccess(actions.modifyMemberLabelAccess.memberLabelAccess);
|
||||
}
|
||||
|
||||
if (editorServiceId instanceof ServiceId.PNI) {
|
||||
if (actions.addMembers.size() == 1 && builder.newMembers.size() == 1) {
|
||||
GroupChange.Actions.AddMemberAction addMemberAction = actions.addMembers.get(0);
|
||||
|
||||
@@ -111,6 +111,7 @@ message DecryptedGroupChange {
|
||||
repeated DecryptedBannedMember deleteBannedMembers = 23;
|
||||
repeated DecryptedMember promotePendingPniAciMembers = 24;
|
||||
repeated DecryptedModifyMemberLabel modifyMemberLabels = 26;
|
||||
AccessControl.AccessRequired newMemberLabelAccess = 27;
|
||||
}
|
||||
|
||||
message DecryptedString {
|
||||
|
||||
@@ -69,6 +69,7 @@ message AccessControl {
|
||||
AccessRequired attributes = 1;
|
||||
AccessRequired members = 2;
|
||||
AccessRequired addFromInviteLink = 3;
|
||||
AccessRequired memberLabel = 4;
|
||||
}
|
||||
|
||||
message Group {
|
||||
@@ -225,6 +226,10 @@ message GroupChange {
|
||||
AccessControl.AccessRequired addFromInviteLinkAccess = 1;
|
||||
}
|
||||
|
||||
message ModifyMemberLabelAccessControlAction {
|
||||
AccessControl.AccessRequired memberLabelAccess = 1;
|
||||
}
|
||||
|
||||
message ModifyInviteLinkPasswordAction {
|
||||
bytes inviteLinkPassword = 1;
|
||||
}
|
||||
@@ -262,7 +267,8 @@ message GroupChange {
|
||||
repeated DeleteMemberBannedAction delete_members_banned = 23; // change epoch = 4
|
||||
repeated PromoteMemberPendingPniAciProfileKeyAction promote_members_pending_pni_aci_profile_key = 24; // change epoch = 5
|
||||
repeated ModifyMemberLabelAction modifyMemberLabels = 26; // change epoch = 6;
|
||||
// next: 27
|
||||
ModifyMemberLabelAccessControlAction modifyMemberLabelAccess = 27; // change epoch = 6
|
||||
// next: 28
|
||||
}
|
||||
|
||||
bytes actions = 1;
|
||||
|
||||
Reference in New Issue
Block a user