From 7f64a9812ca5bb10e8f57cacf3d22b904bd200b4 Mon Sep 17 00:00:00 2001 From: AsamK Date: Thu, 26 Aug 2021 09:34:06 +0200 Subject: [PATCH] Prevent non-admins from sending to announcement groups Only reactions are allowed --- .../org/asamk/signal/manager/Manager.java | 36 ++++++++++++------- .../GroupSendingNotAllowedException.java | 8 +++++ .../signal/manager/helper/GroupHelper.java | 7 ++-- .../signal/manager/helper/SendHelper.java | 25 ++++++++++--- .../signal/commands/RemoteDeleteCommand.java | 3 +- .../asamk/signal/commands/SendCommand.java | 3 +- .../signal/commands/SendReactionCommand.java | 3 +- .../signal/commands/SendTypingCommand.java | 3 +- .../signal/commands/UpdateGroupCommand.java | 3 +- .../org/asamk/signal/dbus/DbusSignalImpl.java | 17 ++++----- 10 files changed, 76 insertions(+), 32 deletions(-) create mode 100644 lib/src/main/java/org/asamk/signal/manager/groups/GroupSendingNotAllowedException.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 3857d803..13696235 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -31,6 +31,7 @@ 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.GroupPermission; +import org.asamk.signal.manager.groups.GroupSendingNotAllowedException; import org.asamk.signal.manager.groups.GroupUtils; import org.asamk.signal.manager.groups.LastGroupAdminException; import org.asamk.signal.manager.groups.NotAGroupMemberException; @@ -697,7 +698,7 @@ public class Manager implements Closeable { File avatarFile, Integer expirationTimer, Boolean isAnnouncementGroup - ) throws IOException, GroupNotFoundException, AttachmentInvalidException, NotAGroupMemberException { + ) throws IOException, GroupNotFoundException, AttachmentInvalidException, NotAGroupMemberException, GroupSendingNotAllowedException { return groupHelper.updateGroup(groupId, name, description, @@ -722,7 +723,7 @@ public class Manager implements Closeable { public SendMessageResults sendMessage( SignalServiceDataMessage.Builder messageBuilder, Set recipients - ) throws IOException, NotAGroupMemberException, GroupNotFoundException { + ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { var results = new HashMap>(); long timestamp = System.currentTimeMillis(); messageBuilder.withTimestamp(timestamp); @@ -745,7 +746,7 @@ public class Manager implements Closeable { public void sendTypingMessage( SignalServiceTypingMessage.Action action, Set recipients - ) throws IOException, UntrustedIdentityException, NotAGroupMemberException, GroupNotFoundException { + ) throws IOException, UntrustedIdentityException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { final var timestamp = System.currentTimeMillis(); for (var recipient : recipients) { if (recipient instanceof RecipientIdentifier.Single) { @@ -806,7 +807,7 @@ public class Manager implements Closeable { public SendMessageResults sendMessage( Message message, Set recipients - ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException { + ) throws IOException, AttachmentInvalidException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { final var messageBuilder = SignalServiceDataMessage.newBuilder(); applyMessage(messageBuilder, message); return sendMessage(messageBuilder, recipients); @@ -836,7 +837,7 @@ public class Manager implements Closeable { public SendMessageResults sendRemoteDeleteMessage( long targetSentTimestamp, Set recipients - ) throws IOException, NotAGroupMemberException, GroupNotFoundException { + ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { var delete = new SignalServiceDataMessage.RemoteDelete(targetSentTimestamp); final var messageBuilder = SignalServiceDataMessage.newBuilder().withRemoteDelete(delete); return sendMessage(messageBuilder, recipients); @@ -848,7 +849,7 @@ public class Manager implements Closeable { RecipientIdentifier.Single targetAuthor, long targetSentTimestamp, Set recipients - ) throws IOException, NotAGroupMemberException, GroupNotFoundException { + ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { var targetAuthorRecipientId = resolveRecipient(targetAuthor); var reaction = new SignalServiceDataMessage.Reaction(emoji, remove, @@ -864,7 +865,7 @@ public class Manager implements Closeable { try { return sendMessage(messageBuilder, recipients.stream().map(RecipientIdentifier.class::cast).collect(Collectors.toSet())); - } catch (GroupNotFoundException | NotAGroupMemberException e) { + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { throw new AssertionError(e); } finally { for (var recipient : recipients) { @@ -931,7 +932,7 @@ public class Manager implements Closeable { final var messageBuilder = SignalServiceDataMessage.newBuilder().asExpirationUpdate(); try { sendMessage(messageBuilder, Set.of(recipient)); - } catch (NotAGroupMemberException | GroupNotFoundException e) { + } catch (NotAGroupMemberException | GroupNotFoundException | GroupSendingNotAllowedException e) { throw new AssertionError(e); } } @@ -1109,7 +1110,7 @@ public class Manager implements Closeable { public void sendTypingMessage( TypingAction action, Set recipients - ) throws IOException, UntrustedIdentityException, NotAGroupMemberException, GroupNotFoundException { + ) throws IOException, UntrustedIdentityException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { sendTypingMessage(action.toSignalService(), recipients); } @@ -1530,9 +1531,20 @@ public class Manager implements Closeable { } final var recipientId = resolveRecipient(source); - return !group.isMember(recipientId) || ( - group.isAnnouncementGroup() && !group.isAdmin(recipientId) - ); + if (!group.isMember(recipientId)) { + return true; + } + + if (group.isAnnouncementGroup() && !group.isAdmin(recipientId)) { + return message.getBody().isPresent() + || message.getAttachments().isPresent() + || message.getQuote() + .isPresent() + || message.getPreviews().isPresent() + || message.getMentions().isPresent() + || message.getSticker().isPresent(); + } + return false; } private List handleMessage( diff --git a/lib/src/main/java/org/asamk/signal/manager/groups/GroupSendingNotAllowedException.java b/lib/src/main/java/org/asamk/signal/manager/groups/GroupSendingNotAllowedException.java new file mode 100644 index 00000000..1a2fa432 --- /dev/null +++ b/lib/src/main/java/org/asamk/signal/manager/groups/GroupSendingNotAllowedException.java @@ -0,0 +1,8 @@ +package org.asamk.signal.manager.groups; + +public class GroupSendingNotAllowedException extends Exception { + + public GroupSendingNotAllowedException(GroupId groupId, String groupName) { + super("User is not allowed to send message to group: " + groupName + " (" + groupId.toBase64() + ")"); + } +} diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java index 0b9cc950..9ff3134e 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java @@ -12,6 +12,7 @@ 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.GroupPermission; +import org.asamk.signal.manager.groups.GroupSendingNotAllowedException; import org.asamk.signal.manager.groups.GroupUtils; import org.asamk.signal.manager.groups.LastGroupAdminException; import org.asamk.signal.manager.groups.NotAGroupMemberException; @@ -195,7 +196,7 @@ public class GroupHelper { final File avatarFile, final Integer expirationTimer, final Boolean isAnnouncementGroup - ) throws IOException, GroupNotFoundException, AttachmentInvalidException, NotAGroupMemberException { + ) throws IOException, GroupNotFoundException, AttachmentInvalidException, NotAGroupMemberException, GroupSendingNotAllowedException { var group = getGroupForUpdating(groupId); if (group instanceof GroupInfoV2) { @@ -410,13 +411,13 @@ public class GroupHelper { */ private void setExpirationTimer( GroupInfoV1 groupInfoV1, int messageExpirationTimer - ) throws NotAGroupMemberException, GroupNotFoundException, IOException { + ) throws NotAGroupMemberException, GroupNotFoundException, IOException, GroupSendingNotAllowedException { groupInfoV1.messageExpirationTime = messageExpirationTimer; account.getGroupStore().updateGroup(groupInfoV1); sendExpirationTimerUpdate(groupInfoV1.getGroupId()); } - private void sendExpirationTimerUpdate(GroupIdV1 groupId) throws IOException, NotAGroupMemberException, GroupNotFoundException { + private void sendExpirationTimerUpdate(GroupIdV1 groupId) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { final var messageBuilder = SignalServiceDataMessage.newBuilder().asExpirationUpdate(); sendHelper.sendAsGroupMessage(messageBuilder, groupId); } diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/SendHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/SendHelper.java index b04ff40d..f92d7bde 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/SendHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/SendHelper.java @@ -3,6 +3,7 @@ package org.asamk.signal.manager.helper; import org.asamk.signal.manager.SignalDependencies; import org.asamk.signal.manager.groups.GroupId; import org.asamk.signal.manager.groups.GroupNotFoundException; +import org.asamk.signal.manager.groups.GroupSendingNotAllowedException; import org.asamk.signal.manager.groups.GroupUtils; import org.asamk.signal.manager.groups.NotAGroupMemberException; import org.asamk.signal.manager.storage.SignalAccount; @@ -86,19 +87,32 @@ public class SendHelper { */ public List sendAsGroupMessage( SignalServiceDataMessage.Builder messageBuilder, GroupId groupId - ) throws IOException, GroupNotFoundException, NotAGroupMemberException { + ) throws IOException, GroupNotFoundException, NotAGroupMemberException, GroupSendingNotAllowedException { final var g = getGroupForSending(groupId); return sendAsGroupMessage(messageBuilder, g); } private List sendAsGroupMessage( final SignalServiceDataMessage.Builder messageBuilder, final GroupInfo g - ) throws IOException { + ) throws IOException, GroupSendingNotAllowedException { GroupUtils.setGroupContext(messageBuilder, g); messageBuilder.withExpiration(g.getMessageExpirationTime()); + final var message = messageBuilder.build(); final var recipients = g.getMembersWithout(account.getSelfRecipientId()); - return sendGroupMessage(messageBuilder.build(), recipients); + + if (g.isAnnouncementGroup() && !g.isAdmin(account.getSelfRecipientId())) { + if (message.getBody().isPresent() + || message.getAttachments().isPresent() + || message.getQuote().isPresent() + || message.getPreviews().isPresent() + || message.getMentions().isPresent() + || message.getSticker().isPresent()) { + throw new GroupSendingNotAllowedException(g.getGroupId(), g.getTitle()); + } + } + + return sendGroupMessage(message, recipients); } /** @@ -181,8 +195,11 @@ public class SendHelper { public void sendGroupTypingMessage( SignalServiceTypingMessage message, GroupId groupId - ) throws IOException, NotAGroupMemberException, GroupNotFoundException { + ) throws IOException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException { final var g = getGroupForSending(groupId); + if (g.isAnnouncementGroup() && !g.isAdmin(account.getSelfRecipientId())) { + throw new GroupSendingNotAllowedException(groupId, g.getTitle()); + } final var messageSender = dependencies.getMessageSender(); final var recipientIdList = new ArrayList<>(g.getMembersWithout(account.getSelfRecipientId())); final var addresses = recipientIdList.stream() diff --git a/src/main/java/org/asamk/signal/commands/RemoteDeleteCommand.java b/src/main/java/org/asamk/signal/commands/RemoteDeleteCommand.java index f033e0b1..e482dd58 100644 --- a/src/main/java/org/asamk/signal/commands/RemoteDeleteCommand.java +++ b/src/main/java/org/asamk/signal/commands/RemoteDeleteCommand.java @@ -13,6 +13,7 @@ import org.asamk.signal.commands.exceptions.UnexpectedErrorException; import org.asamk.signal.commands.exceptions.UserErrorException; import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.groups.GroupNotFoundException; +import org.asamk.signal.manager.groups.GroupSendingNotAllowedException; import org.asamk.signal.manager.groups.NotAGroupMemberException; import org.asamk.signal.util.CommandUtil; import org.asamk.signal.util.ErrorUtils; @@ -60,7 +61,7 @@ public class RemoteDeleteCommand implements DbusCommand, JsonRpcLocalCommand { final var results = m.sendRemoteDeleteMessage(targetTimestamp, recipientIdentifiers); outputResult(outputWriter, results.getTimestamp()); ErrorUtils.handleSendMessageResults(results.getResults()); - } catch (GroupNotFoundException | NotAGroupMemberException e) { + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { throw new UserErrorException(e.getMessage()); } catch (IOException e) { throw new UnexpectedErrorException("Failed to send message: " + e.getMessage()); diff --git a/src/main/java/org/asamk/signal/commands/SendCommand.java b/src/main/java/org/asamk/signal/commands/SendCommand.java index a1e4c296..c29d0268 100644 --- a/src/main/java/org/asamk/signal/commands/SendCommand.java +++ b/src/main/java/org/asamk/signal/commands/SendCommand.java @@ -17,6 +17,7 @@ import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.api.Message; import org.asamk.signal.manager.api.RecipientIdentifier; import org.asamk.signal.manager.groups.GroupNotFoundException; +import org.asamk.signal.manager.groups.GroupSendingNotAllowedException; import org.asamk.signal.manager.groups.NotAGroupMemberException; import org.asamk.signal.util.CommandUtil; import org.asamk.signal.util.ErrorUtils; @@ -108,7 +109,7 @@ public class SendCommand implements DbusCommand, JsonRpcLocalCommand { ErrorUtils.handleSendMessageResults(results.getResults()); } catch (AttachmentInvalidException | IOException e) { throw new UnexpectedErrorException("Failed to send message: " + e.getMessage()); - } catch (GroupNotFoundException | NotAGroupMemberException e) { + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { throw new UserErrorException(e.getMessage()); } } diff --git a/src/main/java/org/asamk/signal/commands/SendReactionCommand.java b/src/main/java/org/asamk/signal/commands/SendReactionCommand.java index c8e339a1..98e5f5ec 100644 --- a/src/main/java/org/asamk/signal/commands/SendReactionCommand.java +++ b/src/main/java/org/asamk/signal/commands/SendReactionCommand.java @@ -13,6 +13,7 @@ import org.asamk.signal.commands.exceptions.UnexpectedErrorException; import org.asamk.signal.commands.exceptions.UserErrorException; import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.groups.GroupNotFoundException; +import org.asamk.signal.manager.groups.GroupSendingNotAllowedException; import org.asamk.signal.manager.groups.NotAGroupMemberException; import org.asamk.signal.util.CommandUtil; import org.asamk.signal.util.ErrorUtils; @@ -76,7 +77,7 @@ public class SendReactionCommand implements DbusCommand, JsonRpcLocalCommand { recipientIdentifiers); outputResult(outputWriter, results.getTimestamp()); ErrorUtils.handleSendMessageResults(results.getResults()); - } catch (GroupNotFoundException | NotAGroupMemberException e) { + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { throw new UserErrorException(e.getMessage()); } catch (IOException e) { throw new UnexpectedErrorException("Failed to send message: " + e.getMessage()); diff --git a/src/main/java/org/asamk/signal/commands/SendTypingCommand.java b/src/main/java/org/asamk/signal/commands/SendTypingCommand.java index 14139885..ace4da85 100644 --- a/src/main/java/org/asamk/signal/commands/SendTypingCommand.java +++ b/src/main/java/org/asamk/signal/commands/SendTypingCommand.java @@ -11,6 +11,7 @@ import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.api.RecipientIdentifier; import org.asamk.signal.manager.api.TypingAction; import org.asamk.signal.manager.groups.GroupNotFoundException; +import org.asamk.signal.manager.groups.GroupSendingNotAllowedException; import org.asamk.signal.manager.groups.NotAGroupMemberException; import org.asamk.signal.util.CommandUtil; import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; @@ -59,7 +60,7 @@ public class SendTypingCommand implements JsonRpcLocalCommand { m.sendTypingMessage(action, recipientIdentifiers); } catch (IOException | UntrustedIdentityException e) { throw new UserErrorException("Failed to send message: " + e.getMessage()); - } catch (GroupNotFoundException | NotAGroupMemberException e) { + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { throw new UserErrorException("Failed to send to group: " + e.getMessage()); } } diff --git a/src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java b/src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java index fc2cfbc0..a8d556f3 100644 --- a/src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java +++ b/src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java @@ -17,6 +17,7 @@ import org.asamk.signal.manager.groups.GroupId; import org.asamk.signal.manager.groups.GroupLinkState; import org.asamk.signal.manager.groups.GroupNotFoundException; import org.asamk.signal.manager.groups.GroupPermission; +import org.asamk.signal.manager.groups.GroupSendingNotAllowedException; import org.asamk.signal.manager.groups.NotAGroupMemberException; import org.asamk.signal.util.CommandUtil; import org.asamk.signal.util.ErrorUtils; @@ -170,7 +171,7 @@ public class UpdateGroupCommand implements DbusCommand, JsonRpcLocalCommand { outputResult(outputWriter, timestamp, isNewGroup ? groupId : null); } catch (AttachmentInvalidException e) { throw new UserErrorException("Failed to add avatar attachment for group\": " + e.getMessage()); - } catch (GroupNotFoundException | NotAGroupMemberException e) { + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { throw new UserErrorException(e.getMessage()); } catch (IOException e) { throw new UnexpectedErrorException("Failed to send message: " + e.getMessage()); diff --git a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java index c5be7501..315e1d8e 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java @@ -10,6 +10,7 @@ import org.asamk.signal.manager.api.RecipientIdentifier; import org.asamk.signal.manager.groups.GroupId; import org.asamk.signal.manager.groups.GroupInviteLinkUrl; import org.asamk.signal.manager.groups.GroupNotFoundException; +import org.asamk.signal.manager.groups.GroupSendingNotAllowedException; import org.asamk.signal.manager.groups.LastGroupAdminException; import org.asamk.signal.manager.groups.NotAGroupMemberException; import org.asamk.signal.manager.storage.identities.IdentityInfo; @@ -77,7 +78,7 @@ public class DbusSignalImpl implements Signal { throw new Error.AttachmentInvalid(e.getMessage()); } catch (IOException e) { throw new Error.Failure(e.getMessage()); - } catch (GroupNotFoundException | NotAGroupMemberException e) { + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { throw new Error.GroupNotFound(e.getMessage()); } } @@ -104,7 +105,7 @@ public class DbusSignalImpl implements Signal { return results.getTimestamp(); } catch (IOException e) { throw new Error.Failure(e.getMessage()); - } catch (GroupNotFoundException | NotAGroupMemberException e) { + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { throw new Error.GroupNotFound(e.getMessage()); } } @@ -120,7 +121,7 @@ public class DbusSignalImpl implements Signal { return results.getTimestamp(); } catch (IOException e) { throw new Error.Failure(e.getMessage()); - } catch (GroupNotFoundException | NotAGroupMemberException e) { + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { throw new Error.GroupNotFound(e.getMessage()); } } @@ -158,7 +159,7 @@ public class DbusSignalImpl implements Signal { return results.getTimestamp(); } catch (IOException e) { throw new Error.Failure(e.getMessage()); - } catch (GroupNotFoundException | NotAGroupMemberException e) { + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { throw new Error.GroupNotFound(e.getMessage()); } } @@ -176,7 +177,7 @@ public class DbusSignalImpl implements Signal { throw new Error.AttachmentInvalid(e.getMessage()); } catch (IOException e) { throw new Error.Failure(e.getMessage()); - } catch (GroupNotFoundException | NotAGroupMemberException e) { + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { throw new Error.GroupNotFound(e.getMessage()); } } @@ -200,7 +201,7 @@ public class DbusSignalImpl implements Signal { return results.getTimestamp(); } catch (IOException e) { throw new Error.Failure(e.getMessage()); - } catch (GroupNotFoundException | NotAGroupMemberException e) { + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { throw new Error.GroupNotFound(e.getMessage()); } catch (AttachmentInvalidException e) { throw new Error.AttachmentInvalid(e.getMessage()); @@ -225,7 +226,7 @@ public class DbusSignalImpl implements Signal { return results.getTimestamp(); } catch (IOException e) { throw new Error.Failure(e.getMessage()); - } catch (GroupNotFoundException | NotAGroupMemberException e) { + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { throw new Error.GroupNotFound(e.getMessage()); } } @@ -337,7 +338,7 @@ public class DbusSignalImpl implements Signal { } } catch (IOException e) { throw new Error.Failure(e.getMessage()); - } catch (GroupNotFoundException | NotAGroupMemberException e) { + } catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) { throw new Error.GroupNotFound(e.getMessage()); } catch (AttachmentInvalidException e) { throw new Error.AttachmentInvalid(e.getMessage()); -- 2.50.1