From: AsamK Date: Sat, 8 Oct 2022 12:06:36 +0000 (+0200) Subject: Refactor check for registered users X-Git-Tag: v0.11.4~19 X-Git-Url: https://git.nmode.ca/signal-cli/commitdiff_plain/f2b334b57adef638f5156e39b9cb7bb9542e6458 Refactor check for registered users --- diff --git a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java index fc38c92a..3e463edf 100644 --- a/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java +++ b/lib/src/main/java/org/asamk/signal/manager/ManagerImpl.java @@ -217,13 +217,14 @@ class ManagerImpl implements Manager { return numbers.stream().collect(Collectors.toMap(n -> n, n -> { final var number = canonicalizedNumbers.get(n); - final var aci = registeredUsers.get(number); - final var profile = aci == null + final var user = registeredUsers.get(number); + final var serviceId = user == null ? null : user.getServiceId(); + final var profile = serviceId == null ? null : context.getProfileHelper() - .getRecipientProfile(account.getRecipientResolver().resolveRecipient(aci)); + .getRecipientProfile(account.getRecipientResolver().resolveRecipient(serviceId)); return new UserStatus(number.isEmpty() ? null : number, - aci == null ? null : aci.uuid(), + serviceId == null ? null : serviceId.uuid(), profile != null && profile.getUnidentifiedAccessMode() == Profile.UnidentifiedAccessMode.UNRESTRICTED); })); 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 d87b2c53..3a82cf8a 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 @@ -11,6 +11,7 @@ import org.signal.libsignal.protocol.InvalidKeyException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.signalservice.api.push.ACI; +import org.whispersystems.signalservice.api.push.PNI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.services.CdsiV2Service; @@ -50,9 +51,9 @@ public class RecipientHelper { // Address in recipient store doesn't have a uuid, this shouldn't happen // Try to retrieve the uuid from the server final var number = address.number().get(); - final ACI aci; + final ServiceId serviceId; try { - aci = getRegisteredUser(number); + serviceId = getRegisteredUser(number); } catch (UnregisteredRecipientException e) { logger.warn("Failed to get uuid for e164 number: {}", number); // Return SignalServiceAddress with unknown UUID @@ -63,7 +64,7 @@ public class RecipientHelper { return address.toSignalServiceAddress(); } return account.getRecipientAddressResolver() - .resolveRecipientAddress(account.getRecipientResolver().resolveRecipient(aci)) + .resolveRecipientAddress(account.getRecipientResolver().resolveRecipient(serviceId)) .toSignalServiceAddress(); } @@ -101,12 +102,13 @@ public class RecipientHelper { return recipientId; } final var number = address.getNumber().get(); - final var uuid = getRegisteredUser(number); - return account.getRecipientTrustedResolver().resolveRecipientTrusted(new SignalServiceAddress(uuid, number)); + final var serviceId = getRegisteredUser(number); + return account.getRecipientTrustedResolver() + .resolveRecipientTrusted(new SignalServiceAddress(serviceId, number)); } - public Map getRegisteredUsers(final Set numbers) throws IOException { - Map registeredUsers; + public Map getRegisteredUsers(final Set numbers) throws IOException { + Map registeredUsers; try { registeredUsers = getRegisteredUsersV2(numbers, true); } catch (IOException e) { @@ -115,30 +117,30 @@ public class RecipientHelper { } // Store numbers as recipients, so we have the number/uuid association - registeredUsers.forEach((number, aci) -> account.getRecipientTrustedResolver() - .resolveRecipientTrusted(new SignalServiceAddress(aci, number))); + registeredUsers.forEach((number, u) -> account.getRecipientTrustedResolver() + .resolveRecipientTrusted(u.aci, u.pni, Optional.of(number))); return registeredUsers; } - private ACI getRegisteredUser(final String number) throws IOException, UnregisteredRecipientException { - final Map aciMap; + private ServiceId getRegisteredUser(final String number) throws IOException, UnregisteredRecipientException { + final Map aciMap; try { aciMap = getRegisteredUsers(Set.of(number)); } catch (NumberFormatException e) { throw new UnregisteredRecipientException(new org.asamk.signal.manager.api.RecipientAddress(null, number)); } - final var uuid = aciMap.get(number); - if (uuid == null) { + final var user = aciMap.get(number); + if (user == null) { throw new UnregisteredRecipientException(new org.asamk.signal.manager.api.RecipientAddress(null, number)); } - return uuid; + return user.getServiceId(); } - private Map getRegisteredUsersV1(final Set numbers) throws IOException { - final Map registeredUsers; + private Map getRegisteredUsersV1(final Set numbers) throws IOException { + final Map response; try { - registeredUsers = dependencies.getAccountManager() + response = dependencies.getAccountManager() .getRegisteredUsers(ServiceConfig.getIasKeyStore(), numbers, serviceEnvironmentConfig.getCdsMrenclave()); @@ -146,10 +148,15 @@ public class RecipientHelper { UnauthenticatedResponseException | InvalidKeyException | NumberFormatException e) { throw new IOException(e); } + final var registeredUsers = new HashMap(); + response.forEach((key, value) -> registeredUsers.put(key, + new RegisteredUser(Optional.of(value), Optional.empty()))); return registeredUsers; } - private Map getRegisteredUsersV2(final Set numbers, boolean useCompat) throws IOException { + private Map getRegisteredUsersV2( + final Set numbers, boolean useCompat + ) throws IOException { // Only partial refresh is implemented here final CdsiV2Service.Response response; try { @@ -168,16 +175,29 @@ public class RecipientHelper { } logger.debug("CDSI request successful, quota used by this request: {}", response.getQuotaUsedDebugOnly()); - final var registeredUsers = new HashMap(); - response.getResults().forEach((key, value) -> { - if (value.getAci().isPresent()) { - registeredUsers.put(key, value.getAci().get()); - } - }); + final var registeredUsers = new HashMap(); + response.getResults() + .forEach((key, value) -> registeredUsers.put(key, + new RegisteredUser(value.getAci(), Optional.of(value.getPni())))); return registeredUsers; } private ACI getRegisteredUserByUsername(String username) throws IOException { return dependencies.getAccountManager().getAciByUsername(username); } + + public record RegisteredUser(Optional aci, Optional pni) { + + public RegisteredUser { + aci = aci.isPresent() && aci.get().equals(ServiceId.UNKNOWN) ? Optional.empty() : aci; + pni = pni.isPresent() && pni.get().equals(ServiceId.UNKNOWN) ? Optional.empty() : pni; + if (aci.isEmpty() && pni.isEmpty()) { + throw new AssertionError("Must have either a ACI or PNI!"); + } + } + + public ServiceId getServiceId() { + return aci.map(a -> (ServiceId) a).or(this::pni).orElse(null); + } + } } diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java index 6c179b6d..547607b3 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java @@ -1200,6 +1200,13 @@ public class SignalAccount implements Closeable { public RecipientId resolveRecipientTrusted(final SignalServiceAddress address) { return getRecipientStore().resolveRecipientTrusted(address); } + + @Override + public RecipientId resolveRecipientTrusted( + final Optional aci, final Optional pni, final Optional number + ) { + return getRecipientStore().resolveRecipientTrusted(aci, pni, number); + } }; } diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java index 7b57f2c9..247a71eb 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientStore.java @@ -12,6 +12,7 @@ import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.signalservice.api.push.ACI; +import org.whispersystems.signalservice.api.push.PNI; import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.util.UuidUtil; @@ -154,7 +155,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re } public RecipientId resolveRecipient( - final String number, Supplier aciSupplier + final String number, Supplier serviceIdSupplier ) throws UnregisteredRecipientException { final Optional byNumber; try (final var connection = database.getConnection()) { @@ -163,12 +164,13 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re throw new RuntimeException("Failed read from recipient store", e); } if (byNumber.isEmpty() || byNumber.get().address().serviceId().isEmpty()) { - final var aci = aciSupplier.get(); - if (aci == null) { - throw new UnregisteredRecipientException(new org.asamk.signal.manager.api.RecipientAddress(null, number)); + final var serviceId = serviceIdSupplier.get(); + if (serviceId == null) { + throw new UnregisteredRecipientException(new org.asamk.signal.manager.api.RecipientAddress(null, + number)); } - return resolveRecipient(new RecipientAddress(aci, number), false, false); + return resolveRecipient(new RecipientAddress(serviceId, number), false, false); } return byNumber.get().id(); } @@ -191,6 +193,14 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re return resolveRecipient(new RecipientAddress(address), true, false); } + @Override + public RecipientId resolveRecipientTrusted( + final Optional aci, final Optional pni, final Optional number + ) { + final var serviceId = aci.map(a -> (ServiceId) a).or(() -> pni); + return resolveRecipient(new RecipientAddress(serviceId, number), true, false); + } + @Override public void storeContact(RecipientId recipientId, final Contact contact) { try (final var connection = database.getConnection()) { diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientTrustedResolver.java b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientTrustedResolver.java index 0bc522e3..5020caf3 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientTrustedResolver.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientTrustedResolver.java @@ -1,10 +1,16 @@ package org.asamk.signal.manager.storage.recipients; +import org.whispersystems.signalservice.api.push.ACI; +import org.whispersystems.signalservice.api.push.PNI; import org.whispersystems.signalservice.api.push.SignalServiceAddress; +import java.util.Optional; + public interface RecipientTrustedResolver { RecipientId resolveSelfRecipientTrusted(RecipientAddress address); RecipientId resolveRecipientTrusted(SignalServiceAddress address); + + RecipientId resolveRecipientTrusted(Optional aci, Optional pni, Optional number); }