Extend getUserStatus command for usernames

This commit is contained in:
AsamK 2024-03-22 10:54:42 +01:00
parent 8b4f377cf1
commit d356d92b5e
8 changed files with 126 additions and 30 deletions

View file

@ -44,6 +44,7 @@ import org.asamk.signal.manager.api.UpdateGroup;
import org.asamk.signal.manager.api.UpdateProfile;
import org.asamk.signal.manager.api.UserStatus;
import org.asamk.signal.manager.api.UsernameLinkUrl;
import org.asamk.signal.manager.api.UsernameStatus;
import org.asamk.signal.manager.api.VerificationMethodNotAvailableException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -92,6 +93,8 @@ public interface Manager extends Closeable {
*/
Map<String, UserStatus> getUserStatus(Set<String> numbers) throws IOException, RateLimitException;
Map<String, UsernameStatus> getUsernameStatus(Set<String> usernames);
void updateAccountAttributes(
String deviceName,
Boolean unrestrictedUnidentifiedSender,

View file

@ -0,0 +1,5 @@
package org.asamk.signal.manager.api;
import java.util.UUID;
public record UsernameStatus(String username, UUID uuid, boolean unrestrictedUnidentifiedAccess) {}

View file

@ -91,30 +91,53 @@ public class RecipientHelper {
});
} else if (recipient instanceof RecipientIdentifier.Username usernameRecipient) {
var username = usernameRecipient.username();
try {
UsernameLinkUrl usernameLinkUrl = UsernameLinkUrl.fromUri(username);
final var components = usernameLinkUrl.getComponents();
final var encryptedUsername = dependencies.getAccountManager()
.getEncryptedUsernameFromLinkServerId(components.getServerId());
final var link = new Username.UsernameLink(components.getEntropy(), encryptedUsername);
username = Username.fromLink(link).getUsername();
} catch (UsernameLinkUrl.InvalidUsernameLinkException e) {
} catch (IOException | BaseUsernameException e) {
throw new RuntimeException(e);
}
final String finalUsername = username;
return account.getRecipientStore().resolveRecipientByUsername(finalUsername, () -> {
try {
return getRegisteredUserByUsername(finalUsername);
} catch (Exception e) {
return null;
}
});
return resolveRecipientByUsernameOrLink(username, false);
}
throw new AssertionError("Unexpected RecipientIdentifier: " + recipient);
}
public RecipientId resolveRecipientByUsernameOrLink(
String username, boolean forceRefresh
) throws UnregisteredRecipientException {
final Username finalUsername;
try {
finalUsername = getUsernameFromUsernameOrLink(username);
} catch (IOException | BaseUsernameException e) {
throw new RuntimeException(e);
}
if (forceRefresh) {
try {
final var aci = dependencies.getAccountManager().getAciByUsername(finalUsername);
return account.getRecipientStore().resolveRecipientTrusted(aci, finalUsername.getUsername());
} catch (IOException e) {
throw new UnregisteredRecipientException(new org.asamk.signal.manager.api.RecipientAddress(null,
null,
username));
}
}
return account.getRecipientStore().resolveRecipientByUsername(finalUsername.getUsername(), () -> {
try {
return dependencies.getAccountManager().getAciByUsername(finalUsername);
} catch (Exception e) {
return null;
}
});
}
private Username getUsernameFromUsernameOrLink(String username) throws BaseUsernameException, IOException {
try {
final var usernameLinkUrl = UsernameLinkUrl.fromUri(username);
final var components = usernameLinkUrl.getComponents();
final var encryptedUsername = dependencies.getAccountManager()
.getEncryptedUsernameFromLinkServerId(components.getServerId());
final var link = new Username.UsernameLink(components.getEntropy(), encryptedUsername);
return Username.fromLink(link);
} catch (UsernameLinkUrl.InvalidUsernameLinkException e) {
return new Username(username);
}
}
public Optional<RecipientId> resolveRecipientOptional(final RecipientIdentifier.Single recipient) {
try {
return Optional.of(resolveRecipient(recipient));
@ -246,10 +269,6 @@ public class RecipientHelper {
return registeredUsers;
}
private ACI getRegisteredUserByUsername(String username) throws IOException, BaseUsernameException {
return dependencies.getAccountManager().getAciByUsername(new Username(username));
}
public record RegisteredUser(Optional<ACI> aci, Optional<PNI> pni) {
public RegisteredUser {

View file

@ -65,6 +65,7 @@ import org.asamk.signal.manager.api.UpdateGroup;
import org.asamk.signal.manager.api.UpdateProfile;
import org.asamk.signal.manager.api.UserStatus;
import org.asamk.signal.manager.api.UsernameLinkUrl;
import org.asamk.signal.manager.api.UsernameStatus;
import org.asamk.signal.manager.api.VerificationMethodNotAvailableException;
import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
import org.asamk.signal.manager.helper.AccountFileUpdater;
@ -280,6 +281,33 @@ public class ManagerImpl implements Manager {
}));
}
@Override
public Map<String, UsernameStatus> getUsernameStatus(Set<String> usernames) {
final var registeredUsers = new HashMap<String, RecipientAddress>();
for (final var username : usernames) {
try {
final var recipientId = context.getRecipientHelper().resolveRecipientByUsernameOrLink(username, true);
final var address = account.getRecipientAddressResolver().resolveRecipientAddress(recipientId);
registeredUsers.put(username, address);
} catch (UnregisteredRecipientException e) {
// ignore
}
}
return usernames.stream().collect(Collectors.toMap(n -> n, username -> {
final var user = registeredUsers.get(username);
final var serviceId = user == null ? null : user.serviceId().orElse(null);
final var profile = serviceId == null
? null
: context.getProfileHelper()
.getRecipientProfile(account.getRecipientResolver().resolveRecipient(serviceId));
return new UsernameStatus(username,
serviceId == null ? null : serviceId.getRawUuid(),
profile != null
&& profile.getUnidentifiedAccessMode() == Profile.UnidentifiedAccessMode.UNRESTRICTED);
}));
}
@Override
public void updateAccountAttributes(
String deviceName,