]> nmode's Git Repositories - signal-cli/commitdiff
Implement configuring of group link
authorAsamK <asamk@gmx.de>
Sat, 15 May 2021 11:14:12 +0000 (13:14 +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/groups/GroupLinkState.java [new file with mode: 0644]
lib/src/main/java/org/asamk/signal/manager/helper/GroupV2Helper.java
lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupInfoV2.java
src/main/java/org/asamk/signal/GroupLinkState.java [new file with mode: 0644]
src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java
src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java

index b003279a8219685441044039045660dfc9d23f75..03f4e8e9c71b8f82e6d99719c38186ab175a680d 100644 (file)
@@ -23,6 +23,7 @@ import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
 import org.asamk.signal.manager.groups.GroupId;
 import org.asamk.signal.manager.groups.GroupIdV1;
 import org.asamk.signal.manager.groups.GroupInviteLinkUrl;
+import org.asamk.signal.manager.groups.GroupLinkState;
 import org.asamk.signal.manager.groups.GroupNotFoundException;
 import org.asamk.signal.manager.groups.GroupUtils;
 import org.asamk.signal.manager.groups.NotAGroupMemberException;
@@ -833,6 +834,8 @@ public class Manager implements Closeable {
             List<String> removeMembers,
             List<String> admins,
             List<String> removeAdmins,
+            boolean resetGroupLink,
+            GroupLinkState groupLinkState,
             File avatarFile
     ) throws IOException, GroupNotFoundException, AttachmentInvalidException, InvalidNumberException, NotAGroupMemberException {
         return updateGroup(groupId,
@@ -842,6 +845,8 @@ public class Manager implements Closeable {
                 removeMembers == null ? null : getSignalServiceAddresses(removeMembers),
                 admins == null ? null : getSignalServiceAddresses(admins),
                 removeAdmins == null ? null : getSignalServiceAddresses(removeAdmins),
+                resetGroupLink,
+                groupLinkState,
                 avatarFile);
     }
 
@@ -853,6 +858,8 @@ public class Manager implements Closeable {
             final Set<RecipientId> removeMembers,
             final Set<RecipientId> admins,
             final Set<RecipientId> removeAdmins,
+            final boolean resetGroupLink,
+            final GroupLinkState groupLinkState,
             final File avatarFile
     ) throws IOException, GroupNotFoundException, AttachmentInvalidException, NotAGroupMemberException {
         var group = getGroupForUpdating(groupId);
@@ -865,6 +872,8 @@ public class Manager implements Closeable {
                     removeMembers,
                     admins,
                     removeAdmins,
+                    resetGroupLink,
+                    groupLinkState,
                     avatarFile);
         }
 
@@ -928,6 +937,8 @@ public class Manager implements Closeable {
             final Set<RecipientId> removeMembers,
             final Set<RecipientId> admins,
             final Set<RecipientId> removeAdmins,
+            final boolean resetGroupLink,
+            final GroupLinkState groupLinkState,
             final File avatarFile
     ) throws IOException {
         Pair<Long, List<SendMessageResult>> result = null;
@@ -989,6 +1000,16 @@ public class Manager implements Closeable {
             }
         }
 
+        if (resetGroupLink) {
+            var groupGroupChangePair = groupV2Helper.resetGroupLinkPassword(group);
+            result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second());
+        }
+
+        if (groupLinkState != null) {
+            var groupGroupChangePair = groupV2Helper.setGroupLinkState(group, groupLinkState);
+            result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second());
+        }
+
         if (result == null || name != null || description != null || avatarFile != null) {
             var groupGroupChangePair = groupV2Helper.updateGroup(group, name, description, avatarFile);
             if (avatarFile != null) {
diff --git a/lib/src/main/java/org/asamk/signal/manager/groups/GroupLinkState.java b/lib/src/main/java/org/asamk/signal/manager/groups/GroupLinkState.java
new file mode 100644 (file)
index 0000000..ad567fb
--- /dev/null
@@ -0,0 +1,7 @@
+package org.asamk.signal.manager.groups;
+
+public enum GroupLinkState {
+    ENABLED,
+    ENABLED_WITH_APPROVAL,
+    DISABLED,
+}
index 6dab6dab01578ca6c3375fa0a5ba9458ba48f01a..a72c158d9284ef72d53f47fb5544ef888aefd8a7 100644 (file)
@@ -3,6 +3,7 @@ package org.asamk.signal.manager.helper;
 import com.google.protobuf.InvalidProtocolBufferException;
 
 import org.asamk.signal.manager.groups.GroupLinkPassword;
+import org.asamk.signal.manager.groups.GroupLinkState;
 import org.asamk.signal.manager.groups.GroupUtils;
 import org.asamk.signal.manager.storage.groups.GroupInfoV2;
 import org.asamk.signal.manager.storage.recipients.Profile;
@@ -290,6 +291,29 @@ public class GroupV2Helper {
         return revokeInvites(groupInfoV2, memberUuids);
     }
 
+    public Pair<DecryptedGroup, GroupChange> resetGroupLinkPassword(GroupInfoV2 groupInfoV2) throws IOException {
+        final GroupsV2Operations.GroupOperations groupOperations = getGroupOperations(groupInfoV2);
+        final var newGroupLinkPassword = GroupLinkPassword.createNew().serialize();
+        final var change = groupOperations.createModifyGroupLinkPasswordChange(newGroupLinkPassword);
+        return commitChange(groupInfoV2, change);
+    }
+
+    public Pair<DecryptedGroup, GroupChange> setGroupLinkState(
+            GroupInfoV2 groupInfoV2, GroupLinkState state
+    ) throws IOException {
+        final GroupsV2Operations.GroupOperations groupOperations = getGroupOperations(groupInfoV2);
+
+        final var accessRequired = toAccessControl(state);
+        final var requiresNewPassword = state != GroupLinkState.DISABLED && groupInfoV2.getGroup()
+                .getInviteLinkPassword()
+                .isEmpty();
+
+        final var change = requiresNewPassword ? groupOperations.createModifyGroupLinkPasswordAndRightsChange(
+                GroupLinkPassword.createNew().serialize(),
+                accessRequired) : groupOperations.createChangeJoinByLinkRights(accessRequired);
+        return commitChange(groupInfoV2, change);
+    }
+
     public GroupChange joinGroup(
             GroupMasterKey groupMasterKey,
             GroupLinkPassword groupLinkPassword,
@@ -345,6 +369,19 @@ public class GroupV2Helper {
         return commitChange(groupInfoV2, change);
     }
 
+    private AccessControl.AccessRequired toAccessControl(final GroupLinkState state) {
+        switch (state) {
+            case DISABLED:
+                return AccessControl.AccessRequired.UNSATISFIABLE;
+            case ENABLED:
+                return AccessControl.AccessRequired.ANY;
+            case ENABLED_WITH_APPROVAL:
+                return AccessControl.AccessRequired.ADMINISTRATOR;
+            default:
+                throw new AssertionError();
+        }
+    }
+
     private GroupsV2Operations.GroupOperations getGroupOperations(final GroupInfoV2 groupInfoV2) {
         final var groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupInfoV2.getMasterKey());
         return groupsV2Operations.forGroup(groupSecretParams);
index 308220cbd6a9d5bb4517cf09c1adfbb87befe386..fe82862ec4c3bd7a6961d4ce7bb96f5b471bf0c0 100644 (file)
@@ -70,7 +70,7 @@ public class GroupInfoV2 extends GroupInfo {
 
     @Override
     public GroupInviteLinkUrl getGroupInviteLink() {
-        if (this.group == null || this.group.getInviteLinkPassword() == null || (
+        if (this.group == null || this.group.getInviteLinkPassword().isEmpty() || (
                 this.group.getAccessControl().getAddFromInviteLink() != AccessControl.AccessRequired.ANY
                         && this.group.getAccessControl().getAddFromInviteLink()
                         != AccessControl.AccessRequired.ADMINISTRATOR
diff --git a/src/main/java/org/asamk/signal/GroupLinkState.java b/src/main/java/org/asamk/signal/GroupLinkState.java
new file mode 100644 (file)
index 0000000..b0a2510
--- /dev/null
@@ -0,0 +1,35 @@
+package org.asamk.signal;
+
+public enum GroupLinkState {
+    ENABLED {
+        @Override
+        public String toString() {
+            return "enabled";
+        }
+    },
+    ENABLED_WITH_APPROVAL {
+        @Override
+        public String toString() {
+            return "enabled-with-approval";
+        }
+    },
+    DISABLED {
+        @Override
+        public String toString() {
+            return "disabled";
+        }
+    };
+
+    public org.asamk.signal.manager.groups.GroupLinkState toLinkState() {
+        switch (this) {
+            case ENABLED:
+                return org.asamk.signal.manager.groups.GroupLinkState.ENABLED;
+            case ENABLED_WITH_APPROVAL:
+                return org.asamk.signal.manager.groups.GroupLinkState.ENABLED_WITH_APPROVAL;
+            case DISABLED:
+                return org.asamk.signal.manager.groups.GroupLinkState.DISABLED;
+            default:
+                throw new AssertionError();
+        }
+    }
+}
index 873074467e9956462e6576cfcf6877112369b859..64485f6d2427b0f19a588d9f555eee156ee01ff2 100644 (file)
@@ -1,9 +1,11 @@
 package org.asamk.signal.commands;
 
+import net.sourceforge.argparse4j.impl.Arguments;
 import net.sourceforge.argparse4j.inf.Namespace;
 import net.sourceforge.argparse4j.inf.Subparser;
 
 import org.asamk.Signal;
+import org.asamk.signal.GroupLinkState;
 import org.asamk.signal.PlainTextWriterImpl;
 import org.asamk.signal.commands.exceptions.CommandException;
 import org.asamk.signal.commands.exceptions.UnexpectedErrorException;
@@ -46,6 +48,12 @@ public class UpdateGroupCommand implements DbusCommand, LocalCommand {
                 .nargs("*")
                 .help("Specify one or more members to remove group admin privileges");
 
+        subparser.addArgument("--reset-link")
+                .action(Arguments.storeTrue())
+                .help("Reset group link and create new link password");
+        subparser.addArgument("--link")
+                .help("Set group link state, with or without admin approval")
+                .type(Arguments.enumStringType(GroupLinkState.class));
     }
 
     @Override
@@ -65,16 +73,20 @@ public class UpdateGroupCommand implements DbusCommand, LocalCommand {
 
         var groupDescription = ns.getString("description");
 
-        List<String> groupMembers = ns.getList("member");
+        var groupMembers = ns.<String>getList("member");
 
-        List<String> groupRemoveMembers = ns.getList("remove-member");
+        var groupRemoveMembers = ns.<String>getList("remove-member");
 
-        List<String> groupAdmins = ns.getList("admin");
+        var groupAdmins = ns.<String>getList("admin");
 
-        List<String> groupRemoveAdmins = ns.getList("remove-admin");
+        var groupRemoveAdmins = ns.<String>getList("remove-admin");
 
         var groupAvatar = ns.getString("avatar");
 
+        var groupResetLink = ns.getBoolean("reset-link");
+
+        var groupLinkState = ns.<GroupLinkState>get("link");
+
         try {
             if (groupId == null) {
                 var results = m.createGroup(groupName,
@@ -91,6 +103,8 @@ public class UpdateGroupCommand implements DbusCommand, LocalCommand {
                         groupRemoveMembers,
                         groupAdmins,
                         groupRemoveAdmins,
+                        groupResetLink,
+                        groupLinkState != null ? groupLinkState.toLinkState() : null,
                         groupAvatar == null ? null : new File(groupAvatar));
                 ErrorUtils.handleTimestampAndSendMessageResults(writer, results.first(), results.second());
             }
index 9b83ace51b4b33b535d874ac917bade4b1195c0f..834f0d2354e494db7ae89f6d1d8f46b387184a9f 100644 (file)
@@ -347,6 +347,8 @@ public class DbusSignalImpl implements Signal {
                         null,
                         null,
                         null,
+                        false,
+                        null,
                         avatar == null ? null : new File(avatar));
                 checkSendMessageResults(results.first(), results.second());
                 return groupId;