From 6d22ceef24945f473a414544b60e2a67007bc595 Mon Sep 17 00:00:00 2001 From: AsamK Date: Sat, 28 Feb 2026 11:07:28 +0100 Subject: [PATCH] Support receiving admin delete messages --- .../signal/manager/api/MessageEnvelope.java | 19 ++++++++++++++--- .../helper/IncomingMessageHandler.java | 16 +++++++++----- .../asamk/signal/ReceiveMessageHandler.java | 10 +++++++++ .../asamk/signal/dbus/DbusManagerImpl.java | 3 +++ .../asamk/signal/json/JsonAdminDelete.java | 21 +++++++++++++++++++ .../asamk/signal/json/JsonDataMessage.java | 7 +++++-- .../signal-cli/reachability-metadata.json | 7 +++++++ 7 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 src/main/java/org/asamk/signal/json/JsonAdminDelete.java diff --git a/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java b/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java index c984cd62..83783e39 100644 --- a/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java +++ b/lib/src/main/java/org/asamk/signal/manager/api/MessageEnvelope.java @@ -122,7 +122,8 @@ public record MessageEnvelope( List previews, List textStyles, Optional pinMessage, - Optional unpinMessage + Optional unpinMessage, + Optional adminDelete ) { static Data from( @@ -173,8 +174,8 @@ public record MessageEnvelope( .map(a -> a.stream().filter(r -> r.style != null).map(TextStyle::from).toList()) .orElse(List.of()), dataMessage.getPinnedMessage().map(p -> PinMessage.from(p, recipientResolver, addressResolver)), - dataMessage.getUnpinnedMessage() - .map(p -> UnpinMessage.from(p, recipientResolver, addressResolver))); + dataMessage.getUnpinnedMessage().map(p -> UnpinMessage.from(p, recipientResolver, addressResolver)), + dataMessage.getAdminDelete().map(p -> AdminDelete.from(p, recipientResolver, addressResolver))); } public record GroupContext(GroupId groupId, boolean isGroupUpdate, int revision) { @@ -602,6 +603,18 @@ public record MessageEnvelope( } } + public record AdminDelete(RecipientAddress targetAuthor, long targetSentTimestamp) { + + static AdminDelete from( + SignalServiceDataMessage.AdminDelete adminDelete, + RecipientResolver recipientResolver, + RecipientAddressResolver addressResolver + ) { + return new AdminDelete(addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient( + adminDelete.getTargetAuthor())).toApiRecipientAddress(), adminDelete.getTargetSentTimestamp()); + } + } + } public record Edit(long targetSentTimestamp, Data dataMessage) { diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java b/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java index e3dfdc27..10276ac9 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java @@ -709,15 +709,21 @@ public final class IncomingMessageHandler { } } - var groupId = GroupUtils.getGroupId(groupContext); - var group = context.getGroupHelper().getGroup(groupId); + final var message = content.getDataMessage().orElse(null); + + final var recipientId = account.getRecipientResolver().resolveRecipient(source); + + final var groupId = GroupUtils.getGroupId(groupContext); + final var group = context.getGroupHelper().getGroup(groupId); + + if (message != null && message.getAdminDelete().isPresent() && (group == null || !group.isAdmin(recipientId))) { + return true; + } + if (group == null) { return false; } - final var message = content.getDataMessage().orElse(null); - - final var recipientId = account.getRecipientResolver().resolveRecipient(source); if (!group.isMember(recipientId) && !( group.isPendingMember(recipientId) && message != null && message.isGroupV2Update() )) { diff --git a/src/main/java/org/asamk/signal/ReceiveMessageHandler.java b/src/main/java/org/asamk/signal/ReceiveMessageHandler.java index ad278f03..18750c98 100644 --- a/src/main/java/org/asamk/signal/ReceiveMessageHandler.java +++ b/src/main/java/org/asamk/signal/ReceiveMessageHandler.java @@ -224,6 +224,11 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler { final var unpinMessage = message.unpinMessage().get(); printUnpinMessage(writer.indentedWriter(), unpinMessage); } + if (message.adminDelete().isPresent()) { + writer.println("Admin Delete:"); + final var adminDelete = message.adminDelete().get(); + printAdminDelete(writer.indentedWriter(), adminDelete); + } } private void printEditMessage(PlainTextWriter writer, MessageEnvelope.Edit message) { @@ -648,6 +653,11 @@ public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler { writer.println("Target timestamp: {}", DateUtils.formatTimestamp(unpinMessage.targetSentTimestamp())); } + private void printAdminDelete(final PlainTextWriter writer, final MessageEnvelope.Data.AdminDelete adminDelete) { + writer.println("Target author: {}", formatContact(adminDelete.targetAuthor())); + writer.println("Target timestamp: {}", DateUtils.formatTimestamp(adminDelete.targetSentTimestamp())); + } + private String formatContact(RecipientAddress address) { final var number = address.getLegacyIdentifier(); final var name = m.getContactOrProfileName(RecipientIdentifier.Single.fromAddress(address)); diff --git a/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java b/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java index b9e90817..b0034b6b 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java @@ -979,6 +979,7 @@ public class DbusManagerImpl implements Manager { List.of(), List.of(), Optional.empty(), + Optional.empty(), Optional.empty())), Optional.empty(), Optional.empty(), @@ -1027,6 +1028,7 @@ public class DbusManagerImpl implements Manager { List.of(), List.of(), Optional.empty(), + Optional.empty(), Optional.empty()))), Optional.empty(), Optional.empty(), @@ -1107,6 +1109,7 @@ public class DbusManagerImpl implements Manager { List.of(), List.of(), Optional.empty(), + Optional.empty(), Optional.empty())), Optional.empty(), Optional.empty())), diff --git a/src/main/java/org/asamk/signal/json/JsonAdminDelete.java b/src/main/java/org/asamk/signal/json/JsonAdminDelete.java new file mode 100644 index 00000000..60ab45bd --- /dev/null +++ b/src/main/java/org/asamk/signal/json/JsonAdminDelete.java @@ -0,0 +1,21 @@ +package org.asamk.signal.json; + +import org.asamk.signal.manager.api.MessageEnvelope; + +import java.util.UUID; + +public record JsonAdminDelete( + @Deprecated String targetAuthor, String targetAuthorNumber, String targetAuthorUuid, long targetSentTimestamp +) { + + static JsonAdminDelete from(MessageEnvelope.Data.AdminDelete adminDelete) { + final var address = adminDelete.targetAuthor(); + final var targetAuthor = address.getLegacyIdentifier(); + final var targetAuthorNumber = address.number().orElse(null); + final var targetAuthorUuid = address.uuid().map(UUID::toString).orElse(null); + final var targetSentTimestamp = adminDelete.targetSentTimestamp(); + + return new JsonAdminDelete(targetAuthor, targetAuthorNumber, targetAuthorUuid, targetSentTimestamp); + } +} + diff --git a/src/main/java/org/asamk/signal/json/JsonDataMessage.java b/src/main/java/org/asamk/signal/json/JsonDataMessage.java index 38699059..44f7f936 100644 --- a/src/main/java/org/asamk/signal/json/JsonDataMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonDataMessage.java @@ -29,7 +29,8 @@ record JsonDataMessage( @JsonInclude(JsonInclude.Include.NON_NULL) JsonGroupInfo groupInfo, @JsonInclude(JsonInclude.Include.NON_NULL) JsonStoryContext storyContext, @JsonInclude(JsonInclude.Include.NON_NULL) JsonPinMessage pinMessage, - @JsonInclude(JsonInclude.Include.NON_NULL) JsonUnpinMessage unpinMessage + @JsonInclude(JsonInclude.Include.NON_NULL) JsonUnpinMessage unpinMessage, + @JsonInclude(JsonInclude.Include.NON_NULL) JsonAdminDelete adminDelete ) { static JsonDataMessage from(MessageEnvelope.Data dataMessage, Manager m) { @@ -75,6 +76,7 @@ record JsonDataMessage( .toList() : null; final var pinMessage = dataMessage.pinMessage().map(JsonPinMessage::from).orElse(null); final var unpinMessage = dataMessage.unpinMessage().map(JsonUnpinMessage::from).orElse(null); + final var adminDelete = dataMessage.adminDelete().map(JsonAdminDelete::from).orElse(null); return new JsonDataMessage(timestamp, message, @@ -97,6 +99,7 @@ record JsonDataMessage( groupInfo, storyContext, pinMessage, - unpinMessage); + unpinMessage, + adminDelete); } } diff --git a/src/main/resources/META-INF/native-image/org.asamk/signal-cli/reachability-metadata.json b/src/main/resources/META-INF/native-image/org.asamk/signal-cli/reachability-metadata.json index a75dd35a..86e14338 100644 --- a/src/main/resources/META-INF/native-image/org.asamk/signal-cli/reachability-metadata.json +++ b/src/main/resources/META-INF/native-image/org.asamk/signal-cli/reachability-metadata.json @@ -2225,6 +2225,9 @@ { "type": "org.asamk.signal.dbus.DbusSignalImpl$DbusSignalIdentityImpl" }, + { + "type": "org.asamk.signal.json.JsonAdminDelete" + }, { "type": "org.asamk.signal.json.JsonAttachment", "allDeclaredFields": true, @@ -5920,6 +5923,10 @@ "type": "org.signal.libsignal.protocol.state.internal.PreKeyStore", "jniAccessible": true }, + { + "type": "org.signal.libsignal.protocol.state.internal.SignedPreKeyStore", + "jniAccessible": true + }, { "type": "org.signal.libsignal.usernames.BadDiscriminatorCharacterException", "jniAccessible": true,