Handle rate limit exception correctly when querying usernames

Fixes #1797
This commit is contained in:
AsamK 2025-07-12 11:03:28 +02:00
parent a96626c468
commit ca33249170
5 changed files with 34 additions and 14 deletions

View file

@ -58,7 +58,7 @@
}, },
{ {
"name":"java.lang.Throwable", "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", "name":"java.lang.UnsatisfiedLinkError",
@ -126,6 +126,10 @@
"name":"org.signal.libsignal.net.NetworkException", "name":"org.signal.libsignal.net.NetworkException",
"methods":[{"name":"<init>","parameterTypes":["java.lang.String"] }] "methods":[{"name":"<init>","parameterTypes":["java.lang.String"] }]
}, },
{
"name":"org.signal.libsignal.net.RetryLaterException",
"methods":[{"name":"<init>","parameterTypes":["long"] }]
},
{ {
"name":"org.signal.libsignal.protocol.DuplicateMessageException", "name":"org.signal.libsignal.protocol.DuplicateMessageException",
"methods":[{"name":"<init>","parameterTypes":["java.lang.String"] }] "methods":[{"name":"<init>","parameterTypes":["java.lang.String"] }]

View file

@ -96,7 +96,7 @@ public interface Manager extends Closeable {
*/ */
Map<String, UserStatus> getUserStatus(Set<String> numbers) throws IOException, RateLimitException; Map<String, UserStatus> getUserStatus(Set<String> numbers) throws IOException, RateLimitException;
Map<String, UsernameStatus> getUsernameStatus(Set<String> usernames); Map<String, UsernameStatus> getUsernameStatus(Set<String> usernames) throws IOException;
void updateAccountAttributes( void updateAccountAttributes(
String deviceName, String deviceName,

View file

@ -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.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.CdsiInvalidArgumentException; import org.whispersystems.signalservice.api.push.exceptions.CdsiInvalidArgumentException;
import org.whispersystems.signalservice.api.push.exceptions.CdsiInvalidTokenException; import org.whispersystems.signalservice.api.push.exceptions.CdsiInvalidTokenException;
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
@ -68,7 +69,7 @@ public class RecipientHelper {
.toSignalServiceAddress(); .toSignalServiceAddress();
} }
public Set<RecipientId> resolveRecipients(Collection<RecipientIdentifier.Single> recipients) throws UnregisteredRecipientException { public Set<RecipientId> resolveRecipients(Collection<RecipientIdentifier.Single> recipients) throws UnregisteredRecipientException, IOException {
final var recipientIds = new HashSet<RecipientId>(recipients.size()); final var recipientIds = new HashSet<RecipientId>(recipients.size());
for (var number : recipients) { for (var number : recipients) {
final var recipientId = resolveRecipient(number); final var recipientId = resolveRecipient(number);
@ -91,7 +92,11 @@ public class RecipientHelper {
} }
}); });
} else if (recipient instanceof RecipientIdentifier.Username(String username)) { } 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); throw new AssertionError("Unexpected RecipientIdentifier: " + recipient);
} }
@ -99,7 +104,7 @@ public class RecipientHelper {
public RecipientId resolveRecipientByUsernameOrLink( public RecipientId resolveRecipientByUsernameOrLink(
String username, String username,
boolean forceRefresh boolean forceRefresh
) throws UnregisteredRecipientException { ) throws UnregisteredRecipientException, IOException {
final Username finalUsername; final Username finalUsername;
try { try {
finalUsername = getUsernameFromUsernameOrLink(username); finalUsername = getUsernameFromUsernameOrLink(username);
@ -110,11 +115,15 @@ public class RecipientHelper {
try { try {
final var aci = handleResponseException(dependencies.getUsernameApi().getAciByUsername(finalUsername)); final var aci = handleResponseException(dependencies.getUsernameApi().getAciByUsername(finalUsername));
return account.getRecipientStore().resolveRecipientTrusted(aci, finalUsername.getUsername()); return account.getRecipientStore().resolveRecipientTrusted(aci, finalUsername.getUsername());
} catch (IOException e) { } catch (NonSuccessfulResponseCodeException e) {
throw new UnregisteredRecipientException(new org.asamk.signal.manager.api.RecipientAddress(null, if (e.code == 404) {
null, throw new UnregisteredRecipientException(new org.asamk.signal.manager.api.RecipientAddress(null,
null, null,
username)); null,
username));
}
logger.debug("Failed to get uuid for username: {}", username, e);
throw e;
} }
} }
return account.getRecipientStore().resolveRecipientByUsername(finalUsername.getUsername(), () -> { return account.getRecipientStore().resolveRecipientByUsername(finalUsername.getUsername(), () -> {

View file

@ -285,7 +285,7 @@ public class ManagerImpl implements Manager {
} }
@Override @Override
public Map<String, UsernameStatus> getUsernameStatus(Set<String> usernames) { public Map<String, UsernameStatus> getUsernameStatus(Set<String> usernames) throws IOException {
final var registeredUsers = new HashMap<String, RecipientAddress>(); final var registeredUsers = new HashMap<String, RecipientAddress>();
for (final var username : usernames) { for (final var username : usernames) {
try { try {

View file

@ -64,9 +64,16 @@ public class GetUserStatusCommand implements JsonRpcLocalCommand {
} }
final var usernames = ns.<String>getList("username"); final var usernames = ns.<String>getList("username");
final var registeredUsernames = usernames == null final Map<String, UsernameStatus> registeredUsernames;
? Map.<String, UsernameStatus>of() try {
: m.getUsernameStatus(new HashSet<>(usernames)); 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 // Output
switch (outputWriter) { switch (outputWriter) {