]> nmode's Git Repositories - signal-cli/commitdiff
Implement remove group members
authorAsamK <asamk@gmx.de>
Fri, 14 May 2021 20:23:13 +0000 (22:23 +0200)
committerAsamK <asamk@gmx.de>
Sat, 15 May 2021 15:04:22 +0000 (17:04 +0200)
lib/src/main/java/org/asamk/signal/manager/Manager.java
lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java
src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java
src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java

index 454041543349656a5878a57c8f0dccab7ebfddd1..9d73ac814d61d612d1624df98142ff0f787957f2 100644 (file)
@@ -826,22 +826,33 @@ public class Manager implements Closeable {
     }
 
     public Pair<Long, List<SendMessageResult>> updateGroup(
-            GroupId groupId, String name, String description, List<String> members, File avatarFile
+            GroupId groupId,
+            String name,
+            String description,
+            List<String> members,
+            List<String> removeMembers,
+            File avatarFile
     ) throws IOException, GroupNotFoundException, AttachmentInvalidException, InvalidNumberException, NotAGroupMemberException {
         return updateGroup(groupId,
                 name,
                 description,
                 members == null ? null : getSignalServiceAddresses(members),
+                removeMembers == null ? null : getSignalServiceAddresses(removeMembers),
                 avatarFile);
     }
 
     private Pair<Long, List<SendMessageResult>> updateGroup(
-            GroupId groupId, String name, String description, Set<RecipientId> members, File avatarFile
+            GroupId groupId,
+            String name,
+            String description,
+            Set<RecipientId> members,
+            final Set<RecipientId> removeMembers,
+            File avatarFile
     ) throws IOException, GroupNotFoundException, AttachmentInvalidException, NotAGroupMemberException {
         var group = getGroupForUpdating(groupId);
 
         if (group instanceof GroupInfoV2) {
-            return updateGroupV2((GroupInfoV2) group, name, description, members, avatarFile);
+            return updateGroupV2((GroupInfoV2) group, name, description, members, removeMembers, avatarFile);
         }
 
         return updateGroupV1((GroupInfoV1) group, name, members, avatarFile);
@@ -901,6 +912,7 @@ public class Manager implements Closeable {
             final String name,
             final String description,
             final Set<RecipientId> members,
+            final Set<RecipientId> removeMembers,
             final File avatarFile
     ) throws IOException {
         Pair<Long, List<SendMessageResult>> result = null;
@@ -917,6 +929,24 @@ public class Manager implements Closeable {
                 result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second());
             }
         }
+
+        if (removeMembers != null) {
+            var existingRemoveMembers = new HashSet<>(removeMembers);
+            existingRemoveMembers.retainAll(group.getMembers());
+            existingRemoveMembers.remove(getSelfRecipientId());// self can be removed with sendQuitGroupMessage
+            if (existingRemoveMembers.size() > 0) {
+                var groupGroupChangePair = groupHelper.removeMembers(group, existingRemoveMembers);
+                result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second());
+            }
+
+            var pendingRemoveMembers = new HashSet<>(removeMembers);
+            pendingRemoveMembers.retainAll(group.getPendingMembers());
+            if (pendingRemoveMembers.size() > 0) {
+                var groupGroupChangePair = groupHelper.revokeInvitedMembers(group, pendingRemoveMembers);
+                result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second());
+            }
+        }
+
         if (result == null || name != null || description != null || avatarFile != null) {
             var groupGroupChangePair = groupHelper.updateGroupV2(group, name, description, avatarFile);
             if (avatarFile != null) {
@@ -954,10 +984,14 @@ public class Manager implements Closeable {
     private Pair<Long, List<SendMessageResult>> sendUpdateGroupV2Message(
             GroupInfoV2 group, DecryptedGroup newDecryptedGroup, GroupChange groupChange
     ) throws IOException {
+        final var selfRecipientId = account.getSelfRecipientId();
+        final var members = group.getMembersIncludingPendingWithout(selfRecipientId);
         group.setGroup(newDecryptedGroup, this::resolveRecipient);
+        members.addAll(group.getMembersIncludingPendingWithout(selfRecipientId));
+
         final var messageBuilder = getGroupUpdateMessageBuilder(group, groupChange.toByteArray());
         account.getGroupStore().updateGroup(group);
-        return sendMessage(messageBuilder, group.getMembersIncludingPendingWithout(account.getSelfRecipientId()));
+        return sendMessage(messageBuilder, members);
     }
 
     private static int currentTimeDays() {
index 0bf4069e18a40f2afcd2962b69ac2df393967012..527fa7ab41ee646181a8bebb00ef944f30b2706a 100644 (file)
@@ -263,6 +263,34 @@ public class GroupHelper {
         }
     }
 
+    public Pair<DecryptedGroup, GroupChange> removeMembers(
+            GroupInfoV2 groupInfoV2, Set<RecipientId> members
+    ) throws IOException {
+        final var memberUuids = members.stream()
+                .map(addressResolver::resolveSignalServiceAddress)
+                .map(SignalServiceAddress::getUuid)
+                .filter(Optional::isPresent)
+                .map(Optional::get)
+                .collect(Collectors.toSet());
+        return ejectMembers(groupInfoV2, memberUuids);
+    }
+
+    public Pair<DecryptedGroup, GroupChange> revokeInvitedMembers(
+            GroupInfoV2 groupInfoV2, Set<RecipientId> members
+    ) throws IOException {
+        var pendingMembersList = groupInfoV2.getGroup().getPendingMembersList();
+        final var memberUuids = members.stream()
+                .map(addressResolver::resolveSignalServiceAddress)
+                .map(SignalServiceAddress::getUuid)
+                .filter(Optional::isPresent)
+                .map(Optional::get)
+                .map(uuid -> DecryptedGroupUtil.findPendingByUuid(pendingMembersList, uuid))
+                .filter(Optional::isPresent)
+                .map(Optional::get)
+                .collect(Collectors.toSet());
+        return revokeInvites(groupInfoV2, memberUuids);
+    }
+
     public GroupChange joinGroup(
             GroupMasterKey groupMasterKey,
             GroupLinkPassword groupLinkPassword,
@@ -309,7 +337,7 @@ public class GroupHelper {
         return commitChange(groupInfoV2, change);
     }
 
-    public Pair<DecryptedGroup, GroupChange> revokeInvites(
+    private Pair<DecryptedGroup, GroupChange> revokeInvites(
             GroupInfoV2 groupInfoV2, Set<DecryptedPendingMember> pendingMembers
     ) throws IOException {
         final var groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupInfoV2.getMasterKey());
@@ -324,7 +352,9 @@ public class GroupHelper {
         return commitChange(groupInfoV2, groupOperations.createRemoveInvitationChange(uuidCipherTexts));
     }
 
-    public Pair<DecryptedGroup, GroupChange> ejectMembers(GroupInfoV2 groupInfoV2, Set<UUID> uuids) throws IOException {
+    private Pair<DecryptedGroup, GroupChange> ejectMembers(
+            GroupInfoV2 groupInfoV2, Set<UUID> uuids
+    ) throws IOException {
         final var groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupInfoV2.getMasterKey());
         final var groupOperations = groupsV2Operations.forGroup(groupSecretParams);
         return commitChange(groupInfoV2, groupOperations.createRemoveMembersChange(uuids));
index 00dd10d98a91648f73129a22e551c88a5d2ddfa6..513ec2e4c7b0fed88f16211eb9b9534119cb395a 100644 (file)
@@ -38,6 +38,9 @@ public class UpdateGroupCommand implements DbusCommand, LocalCommand {
         subparser.addArgument("-d", "--description").help("Specify the new group description.");
         subparser.addArgument("-a", "--avatar").help("Specify a new group avatar image file");
         subparser.addArgument("-m", "--member").nargs("*").help("Specify one or more members to add to the group");
+        subparser.addArgument("-r", "--remove-member")
+                .nargs("*")
+                .help("Specify one or more members to remove from the group");
     }
 
     @Override
@@ -59,6 +62,8 @@ public class UpdateGroupCommand implements DbusCommand, LocalCommand {
 
         List<String> groupMembers = ns.getList("member");
 
+        List<String> groupRemoveMembers = ns.getList("remove-member");
+
         var groupAvatar = ns.getString("avatar");
 
         try {
@@ -74,6 +79,7 @@ public class UpdateGroupCommand implements DbusCommand, LocalCommand {
                         groupName,
                         groupDescription,
                         groupMembers,
+                        groupRemoveMembers,
                         groupAvatar == null ? null : new File(groupAvatar));
                 ErrorUtils.handleTimestampAndSendMessageResults(writer, results.first(), results.second());
             }
index cdc9e8d5300eee419dd2045d3bf77765696d02f1..6606e966a14ac78fc8476cdfde29f0d421cf07ba 100644 (file)
@@ -344,6 +344,7 @@ public class DbusSignalImpl implements Signal {
                         name,
                         null,
                         members,
+                        null,
                         avatar == null ? null : new File(avatar));
                 checkSendMessageResults(results.first(), results.second());
                 return groupId;