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;
// 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
return address.toSignalServiceAddress();
}
return account.getRecipientAddressResolver()
- .resolveRecipientAddress(account.getRecipientResolver().resolveRecipient(aci))
+ .resolveRecipientAddress(account.getRecipientResolver().resolveRecipient(serviceId))
.toSignalServiceAddress();
}
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<String, ACI> getRegisteredUsers(final Set<String> numbers) throws IOException {
- Map<String, ACI> registeredUsers;
+ public Map<String, RegisteredUser> getRegisteredUsers(final Set<String> numbers) throws IOException {
+ Map<String, RegisteredUser> registeredUsers;
try {
registeredUsers = getRegisteredUsersV2(numbers, true);
} catch (IOException e) {
}
// 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<String, ACI> aciMap;
+ private ServiceId getRegisteredUser(final String number) throws IOException, UnregisteredRecipientException {
+ final Map<String, RegisteredUser> 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<String, ACI> getRegisteredUsersV1(final Set<String> numbers) throws IOException {
- final Map<String, ACI> registeredUsers;
+ private Map<String, RegisteredUser> getRegisteredUsersV1(final Set<String> numbers) throws IOException {
+ final Map<String, ACI> response;
try {
- registeredUsers = dependencies.getAccountManager()
+ response = dependencies.getAccountManager()
.getRegisteredUsers(ServiceConfig.getIasKeyStore(),
numbers,
serviceEnvironmentConfig.getCdsMrenclave());
UnauthenticatedResponseException | InvalidKeyException | NumberFormatException e) {
throw new IOException(e);
}
+ final var registeredUsers = new HashMap<String, RegisteredUser>();
+ response.forEach((key, value) -> registeredUsers.put(key,
+ new RegisteredUser(Optional.of(value), Optional.empty())));
return registeredUsers;
}
- private Map<String, ACI> getRegisteredUsersV2(final Set<String> numbers, boolean useCompat) throws IOException {
+ private Map<String, RegisteredUser> getRegisteredUsersV2(
+ final Set<String> numbers, boolean useCompat
+ ) throws IOException {
// Only partial refresh is implemented here
final CdsiV2Service.Response response;
try {
}
logger.debug("CDSI request successful, quota used by this request: {}", response.getQuotaUsedDebugOnly());
- final var registeredUsers = new HashMap<String, ACI>();
- response.getResults().forEach((key, value) -> {
- if (value.getAci().isPresent()) {
- registeredUsers.put(key, value.getAci().get());
- }
- });
+ final var registeredUsers = new HashMap<String, RegisteredUser>();
+ 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> aci, Optional<PNI> 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);
+ }
+ }
}
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;
}
public RecipientId resolveRecipient(
- final String number, Supplier<ACI> aciSupplier
+ final String number, Supplier<ServiceId> serviceIdSupplier
) throws UnregisteredRecipientException {
final Optional<RecipientWithAddress> byNumber;
try (final var connection = database.getConnection()) {
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();
}
return resolveRecipient(new RecipientAddress(address), true, false);
}
+ @Override
+ public RecipientId resolveRecipientTrusted(
+ final Optional<ACI> aci, final Optional<PNI> pni, final Optional<String> 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()) {