From ca33249170118be0d2fe3e9deed4ad23b34ac875 Mon Sep 17 00:00:00 2001 From: AsamK Date: Sat, 12 Jul 2025 11:03:28 +0200 Subject: [PATCH] Handle rate limit exception correctly when querying usernames Fixes #1797 --- graalvm-config-dir/jni-config.json | 6 ++++- .../org/asamk/signal/manager/Manager.java | 2 +- .../manager/helper/RecipientHelper.java | 25 +++++++++++++------ .../signal/manager/internal/ManagerImpl.java | 2 +- .../signal/commands/GetUserStatusCommand.java | 13 +++++++--- 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/graalvm-config-dir/jni-config.json b/graalvm-config-dir/jni-config.json index 23a2160c..523a6c03 100644 --- a/graalvm-config-dir/jni-config.json +++ b/graalvm-config-dir/jni-config.json @@ -58,7 +58,7 @@ }, { "name":"java.lang.Throwable", - "methods":[{"name":"getMessage","parameterTypes":[] }, {"name":"toString","parameterTypes":[] }] + "methods":[{"name":"getMessage","parameterTypes":[] }, {"name":"setStackTrace","parameterTypes":["java.lang.StackTraceElement[]"] }, {"name":"toString","parameterTypes":[] }] }, { "name":"java.lang.UnsatisfiedLinkError", @@ -126,6 +126,10 @@ "name":"org.signal.libsignal.net.NetworkException", "methods":[{"name":"","parameterTypes":["java.lang.String"] }] }, +{ + "name":"org.signal.libsignal.net.RetryLaterException", + "methods":[{"name":"","parameterTypes":["long"] }] +}, { "name":"org.signal.libsignal.protocol.DuplicateMessageException", "methods":[{"name":"","parameterTypes":["java.lang.String"] }] 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 238084e7..ccb661e1 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -96,7 +96,7 @@ public interface Manager extends Closeable { */ Map getUserStatus(Set numbers) throws IOException, RateLimitException; - Map getUsernameStatus(Set usernames); + Map getUsernameStatus(Set usernames) throws IOException; void updateAccountAttributes( String deviceName, diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/RecipientHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/RecipientHelper.java index ecb85254..a73bb741 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/RecipientHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/RecipientHelper.java @@ -17,6 +17,7 @@ import org.whispersystems.signalservice.api.push.ServiceId.PNI; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.exceptions.CdsiInvalidArgumentException; import org.whispersystems.signalservice.api.push.exceptions.CdsiInvalidTokenException; +import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; import java.io.IOException; import java.util.Collection; @@ -68,7 +69,7 @@ public class RecipientHelper { .toSignalServiceAddress(); } - public Set resolveRecipients(Collection recipients) throws UnregisteredRecipientException { + public Set resolveRecipients(Collection recipients) throws UnregisteredRecipientException, IOException { final var recipientIds = new HashSet(recipients.size()); for (var number : recipients) { final var recipientId = resolveRecipient(number); @@ -91,7 +92,11 @@ public class RecipientHelper { } }); } else if (recipient instanceof RecipientIdentifier.Username(String username)) { - return resolveRecipientByUsernameOrLink(username, false); + try { + return resolveRecipientByUsernameOrLink(username, false); + } catch (Exception e) { + return null; + } } throw new AssertionError("Unexpected RecipientIdentifier: " + recipient); } @@ -99,7 +104,7 @@ public class RecipientHelper { public RecipientId resolveRecipientByUsernameOrLink( String username, boolean forceRefresh - ) throws UnregisteredRecipientException { + ) throws UnregisteredRecipientException, IOException { final Username finalUsername; try { finalUsername = getUsernameFromUsernameOrLink(username); @@ -110,11 +115,15 @@ public class RecipientHelper { try { final var aci = handleResponseException(dependencies.getUsernameApi().getAciByUsername(finalUsername)); return account.getRecipientStore().resolveRecipientTrusted(aci, finalUsername.getUsername()); - } catch (IOException e) { - throw new UnregisteredRecipientException(new org.asamk.signal.manager.api.RecipientAddress(null, - null, - null, - username)); + } catch (NonSuccessfulResponseCodeException e) { + if (e.code == 404) { + throw new UnregisteredRecipientException(new org.asamk.signal.manager.api.RecipientAddress(null, + null, + null, + username)); + } + logger.debug("Failed to get uuid for username: {}", username, e); + throw e; } } return account.getRecipientStore().resolveRecipientByUsername(finalUsername.getUsername(), () -> { diff --git a/lib/src/main/java/org/asamk/signal/manager/internal/ManagerImpl.java b/lib/src/main/java/org/asamk/signal/manager/internal/ManagerImpl.java index ffb74de2..eb672d24 100644 --- a/lib/src/main/java/org/asamk/signal/manager/internal/ManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/internal/ManagerImpl.java @@ -285,7 +285,7 @@ public class ManagerImpl implements Manager { } @Override - public Map getUsernameStatus(Set usernames) { + public Map getUsernameStatus(Set usernames) throws IOException { final var registeredUsers = new HashMap(); for (final var username : usernames) { try { diff --git a/src/main/java/org/asamk/signal/commands/GetUserStatusCommand.java b/src/main/java/org/asamk/signal/commands/GetUserStatusCommand.java index e3d36d85..eab4155c 100644 --- a/src/main/java/org/asamk/signal/commands/GetUserStatusCommand.java +++ b/src/main/java/org/asamk/signal/commands/GetUserStatusCommand.java @@ -64,9 +64,16 @@ public class GetUserStatusCommand implements JsonRpcLocalCommand { } final var usernames = ns.getList("username"); - final var registeredUsernames = usernames == null - ? Map.of() - : m.getUsernameStatus(new HashSet<>(usernames)); + final Map registeredUsernames; + try { + registeredUsernames = usernames == null ? Map.of() : m.getUsernameStatus(new HashSet<>(usernames)); + } catch (IOException e) { + throw new IOErrorException("Unable to check if users are registered: " + + e.getMessage() + + " (" + + e.getClass().getSimpleName() + + ")", e); + } // Output switch (outputWriter) { -- 2.50.1