Merge ab7f34b4460aaa4339ad65112b8d315821618943 into 14297986f28ea09166c33b167a98042ab5e90716

This commit is contained in:
Brian Exelbierd 2026-01-24 21:31:49 +00:00 committed by GitHub
commit 63c13adb99
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 90 additions and 30 deletions

View File

@ -18,6 +18,8 @@ Requires libsignal-client version 0.86.12.
- Add sendPollCreate, sendPollVote, sendPollTerminate commands for polls
- Add updateDevice command to set device name of linked devices
- Add --ignore-avatars flag to prevent downloading avatars
- Add --ignore-stickers flag to prevent downloading sticker packs
### Changed

View File

@ -1,3 +1,3 @@
package org.asamk.signal.manager.api;
public record ReceiveConfig(boolean ignoreAttachments, boolean ignoreStories, boolean sendReadReceipts) {}
public record ReceiveConfig(boolean ignoreAttachments, boolean ignoreStories, boolean ignoreAvatars, boolean ignoreStickers, boolean sendReadReceipts) {}

View File

@ -107,7 +107,10 @@ public class GroupHelper {
return group != null && group.isBlocked();
}
public void downloadGroupAvatar(GroupIdV1 groupId, SignalServiceAttachment avatar) {
public void downloadGroupAvatar(GroupIdV1 groupId, SignalServiceAttachment avatar, boolean ignoreAvatars) {
if (ignoreAvatars) {
return;
}
try {
context.getAvatarStore()
.storeGroupAvatar(groupId,
@ -167,7 +170,7 @@ public class GroupHelper {
storeProfileKeysFromMembers(group);
final var avatar = group.avatar;
if (!avatar.isEmpty()) {
downloadGroupAvatar(groupId, groupSecretParams, avatar);
downloadGroupAvatar(groupId, groupSecretParams, avatar, false);
}
}
groupInfoV2.setGroup(group);
@ -506,13 +509,16 @@ public class GroupHelper {
storeProfileKeysFromMembers(decryptedGroup);
final var avatar = decryptedGroup.avatar;
if (!avatar.isEmpty()) {
downloadGroupAvatar(groupInfoV2.getGroupId(), groupSecretParams, avatar);
downloadGroupAvatar(groupInfoV2.getGroupId(), groupSecretParams, avatar, false);
}
groupInfoV2.setGroup(decryptedGroup);
account.getGroupStore().updateGroup(group);
}
private void downloadGroupAvatar(GroupIdV2 groupId, GroupSecretParams groupSecretParams, String cdnKey) {
private void downloadGroupAvatar(GroupIdV2 groupId, GroupSecretParams groupSecretParams, String cdnKey, boolean ignoreAvatars) {
if (ignoreAvatars) {
return;
}
try {
context.getAvatarStore()
.storeGroupAvatar(groupId,

View File

@ -369,7 +369,7 @@ public final class IncomingMessageHandler {
false,
senderDeviceAddress,
destination,
receiveConfig.ignoreAttachments()));
receiveConfig));
}
if (content.getStoryMessage().isPresent()) {
@ -382,7 +382,7 @@ public final class IncomingMessageHandler {
actions.addAll(handleSyncMessage(envelope,
syncMessage,
senderDeviceAddress,
receiveConfig.ignoreAttachments()));
receiveConfig));
}
return actions;
@ -475,7 +475,7 @@ public final class IncomingMessageHandler {
final SignalServiceEnvelope envelope,
final SignalServiceSyncMessage syncMessage,
final DeviceAddress sender,
final boolean ignoreAttachments
final ReceiveConfig receiveConfig
) {
var actions = new ArrayList<HandleAction>();
account.setMultiDevice(true);
@ -491,12 +491,12 @@ public final class IncomingMessageHandler {
: new DeviceAddress(account.getRecipientResolver().resolveRecipient(destination),
destination.getServiceId(),
0),
ignoreAttachments));
receiveConfig));
}
if (message.getStoryMessage().isPresent()) {
actions.addAll(handleSignalServiceStoryMessage(message.getStoryMessage().get(),
sender.recipientId(),
ignoreAttachments));
receiveConfig.ignoreAttachments()));
}
}
if (syncMessage.getRequest().isPresent() && account.isPrimaryDevice()) {
@ -522,7 +522,7 @@ public final class IncomingMessageHandler {
try {
final var groupsMessage = syncMessage.getGroups().get();
context.getAttachmentHelper()
.retrieveAttachment(groupsMessage, context.getSyncHelper()::handleSyncDeviceGroups);
.retrieveAttachment(groupsMessage, input -> context.getSyncHelper().handleSyncDeviceGroups(input, receiveConfig.ignoreAvatars()));
} catch (Exception e) {
logger.warn("Failed to handle received sync groups, ignoring: {}", e.getMessage());
}
@ -550,7 +550,7 @@ public final class IncomingMessageHandler {
final var contactsMessage = syncMessage.getContacts().get();
context.getAttachmentHelper()
.retrieveAttachment(contactsMessage.getContactsStream(),
context.getSyncHelper()::handleSyncDeviceContacts);
input -> context.getSyncHelper().handleSyncDeviceContacts(input, receiveConfig.ignoreAvatars()));
} catch (Exception e) {
logger.warn("Failed to handle received sync contacts, ignoring: {}", e.getMessage());
}
@ -576,7 +576,7 @@ public final class IncomingMessageHandler {
final var sticker = context.getStickerHelper()
.addOrUpdateStickerPack(stickerPackId, stickerPackKey, installed);
if (sticker != null && installed) {
if (sticker != null && installed && !receiveConfig.ignoreStickers()) {
context.getJobExecutor().enqueueJob(new RetrieveStickerPackJob(stickerPackId, sticker.packKey()));
}
}
@ -738,7 +738,7 @@ public final class IncomingMessageHandler {
boolean isSync,
DeviceAddress source,
DeviceAddress destination,
boolean ignoreAttachments
ReceiveConfig receiveConfig
) {
var actions = new ArrayList<HandleAction>();
if (message.getGroupContext().isPresent()) {
@ -757,7 +757,7 @@ public final class IncomingMessageHandler {
if (groupInfo.getAvatar().isPresent()) {
var avatar = groupInfo.getAvatar().get();
context.getGroupHelper().downloadGroupAvatar(groupV1.getGroupId(), avatar);
context.getGroupHelper().downloadGroupAvatar(groupV1.getGroupId(), avatar, receiveConfig.ignoreAvatars());
}
if (groupInfo.getName().isPresent()) {
@ -830,7 +830,7 @@ public final class IncomingMessageHandler {
message.getExpireTimerVersion());
}
}
if (!ignoreAttachments) {
if (!receiveConfig.ignoreAttachments()) {
if (message.getAttachments().isPresent()) {
for (var attachment : message.getAttachments().get()) {
context.getAttachmentHelper().downloadAttachment(attachment);
@ -878,7 +878,9 @@ public final class IncomingMessageHandler {
sticker = new StickerPack(stickerPackId, messageSticker.getPackKey());
account.getStickerStore().addStickerPack(sticker);
}
context.getJobExecutor().enqueueJob(new RetrieveStickerPackJob(stickerPackId, messageSticker.getPackKey()));
if (!receiveConfig.ignoreStickers()) {
context.getJobExecutor().enqueueJob(new RetrieveStickerPackJob(stickerPackId, messageSticker.getPackKey()));
}
}
return actions;
}

View File

@ -275,10 +275,13 @@ public final class ProfileHelper {
private Profile decryptProfileAndDownloadAvatar(
final RecipientId recipientId,
final ProfileKey profileKey,
final SignalServiceProfile encryptedProfile
final SignalServiceProfile encryptedProfile,
final boolean ignoreAvatars
) {
final var avatarPath = encryptedProfile.getAvatar();
downloadProfileAvatar(recipientId, avatarPath, profileKey);
if (!ignoreAvatars) {
downloadProfileAvatar(recipientId, avatarPath, profileKey, ignoreAvatars);
}
return ProfileUtils.decryptProfile(profileKey, encryptedProfile);
}
@ -286,8 +289,12 @@ public final class ProfileHelper {
public void downloadProfileAvatar(
final RecipientId recipientId,
final String avatarPath,
final ProfileKey profileKey
final ProfileKey profileKey,
final boolean ignoreAvatars
) {
if (ignoreAvatars) {
return;
}
var profile = account.getProfileStore().getProfile(recipientId);
if (profile == null || !Objects.equals(avatarPath, profile.getAvatarUrlPath())) {
logger.trace("Downloading profile avatar for {}", recipientId);
@ -341,7 +348,7 @@ public final class ProfileHelper {
Profile newProfile = null;
if (profileKey.isPresent()) {
logger.trace("Decrypting profile");
newProfile = decryptProfileAndDownloadAvatar(recipientId, profileKey.get(), encryptedProfile);
newProfile = decryptProfileAndDownloadAvatar(recipientId, profileKey.get(), encryptedProfile, false);
}
if (newProfile == null) {

View File

@ -40,7 +40,7 @@ public class ReceiveHelper {
private final SignalDependencies dependencies;
private final Context context;
private ReceiveConfig receiveConfig = new ReceiveConfig(false, false, false);
private ReceiveConfig receiveConfig = new ReceiveConfig(false, false, false, false, false);
private boolean hasCaughtUpWithOldMessages = false;
private boolean isWaitingForMessage = false;
private boolean shouldStop = false;

View File

@ -293,7 +293,7 @@ public class SyncHelper {
return context.getSendHelper().sendSyncMessage(SignalServiceSyncMessage.forConfiguration(configurationMessage));
}
public void handleSyncDeviceGroups(final InputStream input) {
public void handleSyncDeviceGroups(final InputStream input, final boolean ignoreAvatars) {
final var s = new DeviceGroupsInputStream(input);
DeviceGroup g;
while (true) {
@ -327,7 +327,7 @@ public class SyncHelper {
}
if (g.getAvatar().isPresent()) {
context.getGroupHelper().downloadGroupAvatar(syncGroup.getGroupId(), g.getAvatar().get());
context.getGroupHelper().downloadGroupAvatar(syncGroup.getGroupId(), g.getAvatar().get(), ignoreAvatars);
}
syncGroup.archived = g.isArchived();
account.getGroupStore().updateGroup(syncGroup);
@ -335,7 +335,7 @@ public class SyncHelper {
}
}
public void handleSyncDeviceContacts(final InputStream input) throws IOException {
public void handleSyncDeviceContacts(final InputStream input, final boolean ignoreAvatars) throws IOException {
final var s = new DeviceContactsInputStream(input);
DeviceContact c;
while (true) {
@ -381,7 +381,7 @@ public class SyncHelper {
account.getContactStore().storeContact(recipientId, builder.build());
if (c.getAvatar().isPresent()) {
storeContactAvatar(c.getAvatar().get(), address);
storeContactAvatar(c.getAvatar().get(), address, ignoreAvatars);
}
}
}
@ -430,7 +430,10 @@ public class SyncHelper {
streamDetails.getContentType()));
}
private void storeContactAvatar(DeviceContactAvatar avatar, RecipientAddress address) {
private void storeContactAvatar(DeviceContactAvatar avatar, RecipientAddress address, boolean ignoreAvatars) {
if (ignoreAvatars) {
return;
}
try {
context.getAvatarStore()
.storeContactAvatar(address,

View File

@ -18,6 +18,6 @@ public class DownloadProfileAvatarJob implements Job {
logger.trace("Downloading profile avatar {}", avatarPath);
final var account = context.getAccount();
context.getProfileHelper()
.downloadProfileAvatar(account.getSelfRecipientId(), avatarPath, account.getProfileKey());
.downloadProfileAvatar(account.getSelfRecipientId(), avatarPath, account.getProfileKey(), false);
}
}

View File

@ -587,6 +587,12 @@ Dont download attachments of received messages.
*--ignore-stories*::
Dont receive story messages from the server.
*--ignore-avatars*::
Don't download avatars of received messages.
*--ignore-stickers*::
Don't download sticker packs of received messages.
*--send-read-receipts*::
Send read receipts for all incoming data messages (in addition to the default delivery receipts)
@ -950,6 +956,12 @@ Dont download attachments of received messages.
*--ignore-stories*::
Dont receive story messages from the server.
*--ignore-avatars*::
Don't download avatars of received messages.
*--ignore-stickers*::
Don't download sticker packs of received messages.
*--send-read-receipts*::
Send read receipts for all incoming data messages (in addition to the default delivery receipts)
@ -971,6 +983,12 @@ Dont download attachments of received messages.
*--ignore-stories*::
Dont receive story messages from the server.
*--ignore-avatars*::
Don't download avatars of received messages.
*--ignore-stickers*::
Don't download sticker packs of received messages.
*--send-read-receipts*::
Send read receipts for all incoming data messages (in addition to the default delivery receipts)

View File

@ -82,6 +82,12 @@ public class DaemonCommand implements MultiLocalCommand, LocalCommand {
subparser.addArgument("--ignore-stories")
.help("Dont receive story messages from the server.")
.action(Arguments.storeTrue());
subparser.addArgument("--ignore-avatars")
.help("Don't download avatars of received messages.")
.action(Arguments.storeTrue());
subparser.addArgument("--ignore-stickers")
.help("Don't download sticker packs of received messages.")
.action(Arguments.storeTrue());
subparser.addArgument("--send-read-receipts")
.help("Send read receipts for all incoming data messages (in addition to the default delivery receipts)")
.action(Arguments.storeTrue());

View File

@ -44,6 +44,12 @@ public class JsonRpcDispatcherCommand implements LocalCommand, MultiLocalCommand
subparser.addArgument("--ignore-stories")
.help("Dont receive story messages from the server.")
.action(Arguments.storeTrue());
subparser.addArgument("--ignore-avatars")
.help("Don't download avatars of received messages.")
.action(Arguments.storeTrue());
subparser.addArgument("--ignore-stickers")
.help("Don't download sticker packs of received messages.")
.action(Arguments.storeTrue());
subparser.addArgument("--send-read-receipts")
.help("Send read receipts for all incoming data messages (in addition to the default delivery receipts)")
.action(Arguments.storeTrue());

View File

@ -55,6 +55,12 @@ public class ReceiveCommand implements LocalCommand, JsonRpcSingleCommand<Receiv
subparser.addArgument("--ignore-stories")
.help("Dont receive story messages from the server.")
.action(Arguments.storeTrue());
subparser.addArgument("--ignore-avatars")
.help("Don't download avatars of received messages.")
.action(Arguments.storeTrue());
subparser.addArgument("--ignore-stickers")
.help("Don't download sticker packs of received messages.")
.action(Arguments.storeTrue());
subparser.addArgument("--send-read-receipts")
.help("Send read receipts for all incoming data messages (in addition to the default delivery receipts)")
.action(Arguments.storeTrue());
@ -76,8 +82,10 @@ public class ReceiveCommand implements LocalCommand, JsonRpcSingleCommand<Receiv
final var maxMessagesRaw = ns.getInt("max-messages");
final var ignoreAttachments = Boolean.TRUE.equals(ns.getBoolean("ignore-attachments"));
final var ignoreStories = Boolean.TRUE.equals(ns.getBoolean("ignore-stories"));
final var ignoreAvatars = Boolean.TRUE.equals(ns.getBoolean("ignore-avatars"));
final var ignoreStickers = Boolean.TRUE.equals(ns.getBoolean("ignore-stickers"));
final var sendReadReceipts = Boolean.TRUE.equals(ns.getBoolean("send-read-receipts"));
m.setReceiveConfig(new ReceiveConfig(ignoreAttachments, ignoreStories, sendReadReceipts));
m.setReceiveConfig(new ReceiveConfig(ignoreAttachments, ignoreStories, ignoreAvatars, ignoreStickers, sendReadReceipts));
try {
final var handler = switch (outputWriter) {
case JsonWriter writer -> new JsonReceiveMessageHandler(m, writer);

View File

@ -146,8 +146,10 @@ public class CommandUtil {
public static ReceiveConfig getReceiveConfig(final Namespace ns) {
final var ignoreAttachments = Boolean.TRUE.equals(ns.getBoolean("ignore-attachments"));
final var ignoreStories = Boolean.TRUE.equals(ns.getBoolean("ignore-stories"));
final var ignoreAvatars = Boolean.TRUE.equals(ns.getBoolean("ignore-avatars"));
final var ignoreStickers = Boolean.TRUE.equals(ns.getBoolean("ignore-stickers"));
final var sendReadReceipts = Boolean.TRUE.equals(ns.getBoolean("send-read-receipts"));
return new ReceiveConfig(ignoreAttachments, ignoreStories, sendReadReceipts);
return new ReceiveConfig(ignoreAttachments, ignoreStories, ignoreAvatars, ignoreStickers, sendReadReceipts);
}
}