import org.whispersystems.signalservice.api.util.UptimeSleepTimer;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration;
+import org.whispersystems.signalservice.internal.contacts.crypto.Quote;
+import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedQuoteException;
+import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedResponseException;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
import org.whispersystems.signalservice.internal.push.UnsupportedDataMessageException;
import org.whispersystems.signalservice.internal.push.VerifyAccountResponse;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
+import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
+import static org.asamk.signal.manager.ServiceConfig.CDS_MRENCLAVE;
import static org.asamk.signal.manager.ServiceConfig.capabilities;
+import static org.asamk.signal.manager.ServiceConfig.getIasKeyStore;
public class Manager implements Closeable {
private Collection<SignalServiceAddress> getSignalServiceAddresses(Collection<String> numbers) throws InvalidNumberException {
final Set<SignalServiceAddress> signalServiceAddresses = new HashSet<>(numbers.size());
+ final Set<SignalServiceAddress> missingUuids = new HashSet<>();
for (String number : numbers) {
- signalServiceAddresses.add(canonicalizeAndResolveSignalServiceAddress(number));
+ final SignalServiceAddress resolvedAddress = canonicalizeAndResolveSignalServiceAddress(number);
+ if (resolvedAddress.getUuid().isPresent()) {
+ signalServiceAddresses.add(resolvedAddress);
+ } else {
+ missingUuids.add(resolvedAddress);
+ }
+ }
+
+ Map<String, UUID> registeredUsers;
+ try {
+ registeredUsers = accountManager.getRegisteredUsers(getIasKeyStore(),
+ missingUuids.stream().map(a -> a.getNumber().get()).collect(Collectors.toSet()),
+ CDS_MRENCLAVE);
+ } catch (IOException | Quote.InvalidQuoteFormatException | UnauthenticatedQuoteException | SignatureException | UnauthenticatedResponseException e) {
+ System.err.println("Failed to resolve uuids from server: " + e.getMessage());
+ registeredUsers = new HashMap<>();
+ }
+
+ for (SignalServiceAddress address : missingUuids) {
+ final String number = address.getNumber().get();
+ if (registeredUsers.containsKey(number)) {
+ final SignalServiceAddress newAddress = resolveSignalServiceAddress(new SignalServiceAddress(
+ registeredUsers.get(number),
+ number));
+ signalServiceAddresses.add(newAddress);
+ } else {
+ signalServiceAddresses.add(address);
+ }
}
+
return signalServiceAddresses;
}
import org.whispersystems.util.Base64;
import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
final static int MAX_ENVELOPE_SIZE = 0;
final static long AVATAR_DOWNLOAD_FAILSAFE_MAX_SIZE = 10 * 1024 * 1024;
+ final static String CDS_MRENCLAVE = "c98e00a4e3ff977a56afefe7362a27e4961e4f19e211febfbb19b897e6b80b15";
+
private final static String URL = "https://textsecure-service.whispersystems.org";
private final static String CDN_URL = "https://cdn.signal.org";
private final static String CDN2_URL = "https://cdn2.signal.org";
+ private final static String SIGNAL_CONTACT_DISCOVERY_URL = "https://api.directory.signal.org";
private final static String SIGNAL_KEY_BACKUP_URL = "https://api.backup.signal.org";
private final static String STORAGE_URL = "https://storage.signal.org";
private final static TrustStore TRUST_STORE = new WhisperTrustStore();
+ private final static TrustStore IAS_TRUST_STORE = new IasTrustStore();
private final static Optional<Dns> dns = Optional.absent();
return new SignalServiceConfiguration(new SignalServiceUrl[]{new SignalServiceUrl(URL, TRUST_STORE)},
makeSignalCdnUrlMapFor(new SignalCdnUrl[]{new SignalCdnUrl(CDN_URL, TRUST_STORE)},
new SignalCdnUrl[]{new SignalCdnUrl(CDN2_URL, TRUST_STORE)}),
- new SignalContactDiscoveryUrl[0],
+ new SignalContactDiscoveryUrl[]{new SignalContactDiscoveryUrl(SIGNAL_CONTACT_DISCOVERY_URL,
+ TRUST_STORE)},
new SignalKeyBackupServiceUrl[]{new SignalKeyBackupServiceUrl(SIGNAL_KEY_BACKUP_URL, TRUST_STORE)},
new SignalStorageUrl[]{new SignalStorageUrl(STORAGE_URL, TRUST_STORE)},
interceptors,
zkGroupServerPublicParams);
}
+ static KeyStore getIasKeyStore() {
+ try {
+ TrustStore contactTrustStore = IAS_TRUST_STORE;
+
+ KeyStore keyStore = KeyStore.getInstance("BKS");
+ keyStore.load(contactTrustStore.getKeyStoreInputStream(),
+ contactTrustStore.getKeyStorePassword().toCharArray());
+
+ return keyStore;
+ } catch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException e) {
+ throw new AssertionError(e);
+ }
+ }
+
private static Map<Integer, SignalCdnUrl[]> makeSignalCdnUrlMapFor(
SignalCdnUrl[] cdn0Urls, SignalCdnUrl[] cdn2Urls
) {