From 03589f858ba2cf52df4d85a9d68df3f3cda5cb74 Mon Sep 17 00:00:00 2001 From: AsamK Date: Sat, 15 May 2021 13:14:12 +0200 Subject: [PATCH] Implement configuring of group link --- .../org/asamk/signal/manager/Manager.java | 21 +++++++++++ .../signal/manager/groups/GroupLinkState.java | 7 ++++ .../signal/manager/helper/GroupV2Helper.java | 37 +++++++++++++++++++ .../manager/storage/groups/GroupInfoV2.java | 2 +- .../java/org/asamk/signal/GroupLinkState.java | 35 ++++++++++++++++++ .../signal/commands/UpdateGroupCommand.java | 22 +++++++++-- .../org/asamk/signal/dbus/DbusSignalImpl.java | 2 + 7 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 lib/src/main/java/org/asamk/signal/manager/groups/GroupLinkState.java create mode 100644 src/main/java/org/asamk/signal/GroupLinkState.java diff --git a/lib/src/main/java/org/asamk/signal/manager/Manager.java b/lib/src/main/java/org/asamk/signal/manager/Manager.java index b003279a..03f4e8e9 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -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 removeMembers, List admins, List 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 removeMembers, final Set admins, final Set 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 removeMembers, final Set admins, final Set removeAdmins, + final boolean resetGroupLink, + final GroupLinkState groupLinkState, final File avatarFile ) throws IOException { Pair> 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 index 00000000..ad567fbf --- /dev/null +++ b/lib/src/main/java/org/asamk/signal/manager/groups/GroupLinkState.java @@ -0,0 +1,7 @@ +package org.asamk.signal.manager.groups; + +public enum GroupLinkState { + ENABLED, + ENABLED_WITH_APPROVAL, + DISABLED, +} diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/GroupV2Helper.java b/lib/src/main/java/org/asamk/signal/manager/helper/GroupV2Helper.java index 6dab6dab..a72c158d 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/GroupV2Helper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/GroupV2Helper.java @@ -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 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 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); diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupInfoV2.java b/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupInfoV2.java index 308220cb..fe82862e 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupInfoV2.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupInfoV2.java @@ -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 index 00000000..b0a2510f --- /dev/null +++ b/src/main/java/org/asamk/signal/GroupLinkState.java @@ -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(); + } + } +} diff --git a/src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java b/src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java index 87307446..64485f6d 100644 --- a/src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java +++ b/src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java @@ -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 groupMembers = ns.getList("member"); + var groupMembers = ns.getList("member"); - List groupRemoveMembers = ns.getList("remove-member"); + var groupRemoveMembers = ns.getList("remove-member"); - List groupAdmins = ns.getList("admin"); + var groupAdmins = ns.getList("admin"); - List groupRemoveAdmins = ns.getList("remove-admin"); + var groupRemoveAdmins = ns.getList("remove-admin"); var groupAvatar = ns.getString("avatar"); + var groupResetLink = ns.getBoolean("reset-link"); + + var groupLinkState = ns.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()); } diff --git a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java index 9b83ace5..834f0d23 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java @@ -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; -- 2.50.1