From 4714895c5944842f596d5f1b1d23117b6f12a02d Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Mon, 31 Aug 2020 11:33:35 -0400 Subject: [PATCH] Do not attempt to send to unregistered users when using CDS flag. CDS is slow, and unregistered users will always trigger a CDS lookup on send (since we can't get their UUID). This starts skipping sends to unregistered users and shortens the time window to do a full CDS lookup from every 12 hours to every 6 hours. --- .../contacts/sync/DirectoryHelper.java | 126 +++++++++++------- .../securesms/jobs/ProfileKeySendJob.java | 2 +- .../securesms/jobs/PushGroupSendJob.java | 19 ++- .../jobs/PushGroupSilentUpdateSendJob.java | 12 +- .../securesms/jobs/ReactionSendJob.java | 2 +- .../securesms/jobs/RemoteDeleteSendJob.java | 2 +- .../securesms/jobs/TypingSendJob.java | 6 +- .../securesms/recipients/RecipientUtil.java | 41 ++++-- .../service/DirectoryRefreshListener.java | 2 +- .../securesms/util/FeatureFlags.java | 8 +- .../api/SignalServiceAccountManager.java | 4 + 11 files changed, 149 insertions(+), 75 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/DirectoryHelper.java b/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/DirectoryHelper.java index b9b1c855e..e03e970d9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/DirectoryHelper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/DirectoryHelper.java @@ -38,6 +38,7 @@ import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.notifications.NotificationChannels; import org.thoughtcrime.securesms.permissions.Permissions; import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter; +import org.thoughtcrime.securesms.recipients.RecipientDetails; import org.thoughtcrime.securesms.registration.RegistrationUtil; import org.thoughtcrime.securesms.storage.StorageSyncHelper; import org.thoughtcrime.securesms.recipients.Recipient; @@ -92,61 +93,35 @@ public class DirectoryHelper { return; } - Stopwatch stopwatch = new Stopwatch("full"); RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context); Set databaseNumbers = sanitizeNumbers(recipientDatabase.getAllPhoneNumbers()); Set systemNumbers = sanitizeNumbers(ContactAccessor.getInstance().getAllContactsWithNumbers(context)); - Set allNumbers = SetUtil.union(databaseNumbers, systemNumbers); - DirectoryResult result; - - if (FeatureFlags.cds()) { - result = ContactDiscoveryV2.getDirectoryResult(context, databaseNumbers, systemNumbers); - } else { - result = ContactDiscoveryV1.getDirectoryResult(databaseNumbers, systemNumbers); - } - - stopwatch.split("network"); - - if (result.getNumberRewrites().size() > 0) { - Log.i(TAG, "[getDirectoryResult] Need to rewrite some numbers."); - recipientDatabase.updatePhoneNumbers(result.getNumberRewrites()); - } - - Map uuidMap = recipientDatabase.bulkProcessCdsResult(result.getRegisteredNumbers()); - Set activeNumbers = result.getRegisteredNumbers().keySet(); - Set activeIds = uuidMap.keySet(); - Set inactiveIds = Stream.of(allNumbers) - .filterNot(activeNumbers::contains) - .filterNot(n -> result.getNumberRewrites().containsKey(n)) - .map(recipientDatabase::getOrInsertFromE164) - .collect(Collectors.toSet()); - - recipientDatabase.bulkUpdatedRegisteredStatus(uuidMap, inactiveIds); - - updateContactsDatabase(context, activeIds, true, result.getNumberRewrites()); - - if (TextSecurePreferences.isMultiDevice(context)) { - ApplicationDependencies.getJobManager().add(new MultiDeviceContactUpdateJob()); - } - - if (TextSecurePreferences.hasSuccessfullyRetrievedDirectory(context) && notifyOfNewUsers) { - Set existingSignalIds = new HashSet<>(recipientDatabase.getRegistered()); - Set existingSystemIds = new HashSet<>(recipientDatabase.getSystemContacts()); - Set newlyActiveIds = new HashSet<>(activeIds); - - newlyActiveIds.removeAll(existingSignalIds); - newlyActiveIds.retainAll(existingSystemIds); - - notifyNewUsers(context, newlyActiveIds); - } else { - TextSecurePreferences.setHasSuccessfullyRetrievedDirectory(context, true); - } + refreshNumbers(context, databaseNumbers, systemNumbers, notifyOfNewUsers); StorageSyncHelper.scheduleSyncForDataChange(); + } - stopwatch.split("disk"); - stopwatch.stop(TAG); + @WorkerThread + public static void refreshDirectoryFor(@NonNull Context context, @NonNull List recipients, boolean notifyOfNewUsers) throws IOException { + RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context); + + for (Recipient recipient : recipients) { + if (recipient.hasUuid() && !recipient.hasE164()) { + if (isUuidRegistered(context, recipient)) { + recipientDatabase.markRegistered(recipient.getId(), recipient.requireUuid()); + } else { + recipientDatabase.markUnregistered(recipient.getId()); + } + } + } + + Set numbers = Stream.of(recipients) + .filter(Recipient::hasE164) + .map(Recipient::requireE164) + .collect(Collectors.toSet()); + + refreshNumbers(context, numbers, numbers, notifyOfNewUsers); } @WorkerThread @@ -231,6 +206,61 @@ public class DirectoryHelper { return newRegisteredState; } + @WorkerThread + private static void refreshNumbers(@NonNull Context context, @NonNull Set databaseNumbers, @NonNull Set systemNumbers, boolean notifyOfNewUsers) throws IOException { + RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context); + Set allNumbers = SetUtil.union(databaseNumbers, systemNumbers); + + if (allNumbers.isEmpty()) { + Log.w(TAG, "No numbers to refresh!"); + return; + } + + DirectoryResult result; + + if (FeatureFlags.cds()) { + result = ContactDiscoveryV2.getDirectoryResult(context, databaseNumbers, systemNumbers); + } else { + result = ContactDiscoveryV1.getDirectoryResult(databaseNumbers, systemNumbers); + } + + if (result.getNumberRewrites().size() > 0) { + Log.i(TAG, "[getDirectoryResult] Need to rewrite some numbers."); + recipientDatabase.updatePhoneNumbers(result.getNumberRewrites()); + } + + Map uuidMap = recipientDatabase.bulkProcessCdsResult(result.getRegisteredNumbers()); + Set activeNumbers = result.getRegisteredNumbers().keySet(); + Set activeIds = uuidMap.keySet(); + Set inactiveIds = Stream.of(allNumbers) + .filterNot(activeNumbers::contains) + .filterNot(n -> result.getNumberRewrites().containsKey(n)) + .map(recipientDatabase::getOrInsertFromE164) + .collect(Collectors.toSet()); + + recipientDatabase.bulkUpdatedRegisteredStatus(uuidMap, inactiveIds); + + updateContactsDatabase(context, activeIds, true, result.getNumberRewrites()); + + if (TextSecurePreferences.isMultiDevice(context)) { + ApplicationDependencies.getJobManager().add(new MultiDeviceContactUpdateJob()); + } + + if (TextSecurePreferences.hasSuccessfullyRetrievedDirectory(context) && notifyOfNewUsers) { + Set existingSignalIds = new HashSet<>(recipientDatabase.getRegistered()); + Set existingSystemIds = new HashSet<>(recipientDatabase.getSystemContacts()); + Set newlyActiveIds = new HashSet<>(activeIds); + + newlyActiveIds.removeAll(existingSignalIds); + newlyActiveIds.retainAll(existingSystemIds); + + notifyNewUsers(context, newlyActiveIds); + } else { + TextSecurePreferences.setHasSuccessfullyRetrievedDirectory(context, true); + } + } + + private static boolean isUuidRegistered(@NonNull Context context, @NonNull Recipient recipient) throws IOException { try { ProfileUtil.retrieveProfile(context, recipient, SignalServiceProfile.RequestType.PROFILE).get(10, TimeUnit.SECONDS); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/ProfileKeySendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/ProfileKeySendJob.java index 3c0eb6e9a..66fa83e7d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/ProfileKeySendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/ProfileKeySendJob.java @@ -56,7 +56,7 @@ public class ProfileKeySendJob extends BaseJob { throw new AssertionError("Do not send profile keys directly for GV2"); } - List recipients = conversationRecipient.isGroup() ? Stream.of(conversationRecipient.getParticipants()).map(Recipient::getId).toList() + List recipients = conversationRecipient.isGroup() ? Stream.of(RecipientUtil.getEligibleForSending(conversationRecipient.getParticipants())).map(Recipient::getId).toList() : Stream.of(conversationRecipient.getId()).toList(); recipients.remove(Recipient.self().getId()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java index 8279d28a8..fd5ed5644 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java @@ -19,6 +19,7 @@ import org.thoughtcrime.securesms.database.GroupReceiptDatabase.GroupReceiptInfo import org.thoughtcrime.securesms.database.MessageDatabase; import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.database.NoSuchMessageException; +import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch; import org.thoughtcrime.securesms.database.documents.NetworkFailure; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; @@ -38,6 +39,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientUtil; import org.thoughtcrime.securesms.transport.RetryLaterException; import org.thoughtcrime.securesms.transport.UndeliverableMessageException; +import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.GroupUtil; import org.whispersystems.libsignal.util.Pair; import org.whispersystems.libsignal.util.guava.Optional; @@ -195,7 +197,13 @@ public final class PushGroupSendJob extends PushSendJob { List> successUnidentifiedStatus = Stream.of(successes).map(result -> new Pair<>(findId(result.getAddress(), idByE164, idByUuid), result.getSuccess().isUnidentified())).toList(); Set successIds = Stream.of(successUnidentifiedStatus).map(Pair::first).collect(Collectors.toSet()); List resolvedNetworkFailures = Stream.of(existingNetworkFailures).filter(failure -> successIds.contains(failure.getRecipientId(context))).toList(); - List resolvedIdentityFailures = Stream.of(existingIdentityMismatches).filter(failure -> successIds.contains(failure.getRecipientId(context))).toList(); + List resolvedIdentityFailures = Stream.of(existingIdentityMismatches).filter(failure -> successIds.contains(failure.getRecipientId(context))).toList(); + List unregisteredRecipients = Stream.of(results).filter(SendMessageResult::isUnregisteredFailure).map(result -> Recipient.externalPush(context, result.getAddress())).toList(); + + RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context); + for (Recipient unregistered : unregisteredRecipients) { + recipientDatabase.markUnregistered(unregistered.getId()); + } for (NetworkFailure resolvedFailure : resolvedNetworkFailures) { database.removeFailure(messageId, resolvedFailure); @@ -366,7 +374,10 @@ public final class PushGroupSendJob extends PushSendJob { List destinations = DatabaseFactory.getGroupReceiptDatabase(context).getGroupReceiptInfo(messageId); if (!destinations.isEmpty()) { - return Stream.of(destinations).map(GroupReceiptInfo::getRecipientId).map(Recipient::resolved).toList(); + return RecipientUtil.getEligibleForSending(Stream.of(destinations) + .map(GroupReceiptInfo::getRecipientId) + .map(Recipient::resolved) + .toList()); } List members = Stream.of(DatabaseFactory.getGroupDatabase(context) @@ -377,8 +388,8 @@ public final class PushGroupSendJob extends PushSendJob { if (members.size() > 0) { Log.w(TAG, "No destinations found for group message " + groupId + " using current group membership"); } - - return members; + + return RecipientUtil.getEligibleForSending(members); } public static class Factory implements Job.Factory { diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSilentUpdateSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSilentUpdateSendJob.java index da12bb1f1..111131035 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSilentUpdateSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSilentUpdateSendJob.java @@ -11,6 +11,7 @@ import com.google.protobuf.InvalidProtocolBufferException; import org.signal.storageservice.protos.groups.local.DecryptedGroup; import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil; +import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.groups.GroupId; import org.thoughtcrime.securesms.jobmanager.Data; @@ -23,6 +24,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientUtil; import org.thoughtcrime.securesms.transport.RetryLaterException; import org.thoughtcrime.securesms.util.Base64; +import org.thoughtcrime.securesms.util.FeatureFlags; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair; @@ -75,7 +77,15 @@ public final class PushGroupSilentUpdateSendJob extends BaseJob { Set recipients = Stream.concat(Stream.of(memberUuids), Stream.of(pendingUuids)) .filter(uuid -> !UuidUtil.UNKNOWN_UUID.equals(uuid)) .filter(uuid -> !Recipient.self().getUuid().get().equals(uuid)) - .map(uuid -> RecipientId.from(uuid, null)) + .map(uuid -> Recipient.externalPush(context, uuid, null, false)) + .filter(recipient -> { + if (FeatureFlags.cds()) { + return recipient.getRegistered() != RecipientDatabase.RegisteredState.NOT_REGISTERED; + } else { + return true; + } + }) + .map(Recipient::getId) .collect(Collectors.toSet()); MessageGroupContext.GroupV2Properties properties = groupMessage.requireGroupV2Properties(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/ReactionSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/ReactionSendJob.java index a17ab49e2..54edd286b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/ReactionSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/ReactionSendJob.java @@ -75,7 +75,7 @@ public class ReactionSendJob extends BaseJob { throw new AssertionError("We have a message, but couldn't find the thread!"); } - List recipients = conversationRecipient.isGroup() ? Stream.of(conversationRecipient.getParticipants()).map(Recipient::getId).toList() + List recipients = conversationRecipient.isGroup() ? Stream.of(RecipientUtil.getEligibleForSending(conversationRecipient.getParticipants())).map(Recipient::getId).toList() : Stream.of(conversationRecipient.getId()).toList(); recipients.remove(Recipient.self().getId()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java index 25b9077bf..48da0f282 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java @@ -65,7 +65,7 @@ public class RemoteDeleteSendJob extends BaseJob { throw new AssertionError("We have a message, but couldn't find the thread!"); } - List recipients = conversationRecipient.isGroup() ? Stream.of(conversationRecipient.getParticipants()).map(Recipient::getId).toList() + List recipients = conversationRecipient.isGroup() ? Stream.of(RecipientUtil.getEligibleForSending(conversationRecipient.getParticipants())).map(Recipient::getId).toList() : Stream.of(conversationRecipient.getId()).toList(); recipients.remove(Recipient.self().getId()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/TypingSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/TypingSendJob.java index 8896cfc81..b36e86aa1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/TypingSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/TypingSendJob.java @@ -9,6 +9,7 @@ import com.annimon.stream.Stream; import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.GroupDatabase; +import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.jobmanager.Data; import org.thoughtcrime.securesms.jobmanager.Job; @@ -16,6 +17,7 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientUtil; +import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.CancelationException; @@ -104,7 +106,9 @@ public class TypingSendJob extends BaseJob { groupId = Optional.of(recipient.requireGroupId().getDecodedId()); } - recipients = Stream.of(recipients).map(Recipient::resolve).toList(); + recipients = RecipientUtil.getEligibleForSending(Stream.of(recipients) + .map(Recipient::resolve) + .toList()); SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender(); List addresses = RecipientUtil.toSignalServiceAddressesFromResolved(context, recipients); diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientUtil.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientUtil.java index f2189929d..1baf640dd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientUtil.java @@ -7,6 +7,7 @@ import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; import com.annimon.stream.Stream; +import com.google.android.gms.common.Feature; import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper; import org.thoughtcrime.securesms.database.DatabaseFactory; @@ -29,6 +30,7 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.List; public class RecipientUtil { @@ -38,7 +40,8 @@ public class RecipientUtil { /** * This method will do it's best to craft a fully-populated {@link SignalServiceAddress} based on * the provided recipient. This includes performing a possible network request if no UUID is - * available. + * available. If the request to get a UUID fails, the exception is swallowed an an E164-only + * recipient is returned. */ @WorkerThread public static @NonNull SignalServiceAddress toSignalServiceAddressBestEffort(@NonNull Context context, @NonNull Recipient recipient) { @@ -53,7 +56,7 @@ public class RecipientUtil { /** * This method will do it's best to craft a fully-populated {@link SignalServiceAddress} based on * the provided recipient. This includes performing a possible network request if no UUID is - * available. + * available. If the request to get a UUID fails, an IOException is thrown. */ @WorkerThread public static @NonNull SignalServiceAddress toSignalServiceAddress(@NonNull Context context, @NonNull Recipient recipient) @@ -79,25 +82,27 @@ public class RecipientUtil { public static @NonNull List toSignalServiceAddresses(@NonNull Context context, @NonNull List recipients) throws IOException { - List addresses = new ArrayList<>(recipients.size()); - - for (RecipientId id : recipients) { - addresses.add(toSignalServiceAddress(context, Recipient.resolved(id))); - } - - return addresses; + return toSignalServiceAddressesFromResolved(context, Recipient.resolvedList(recipients)); } public static @NonNull List toSignalServiceAddressesFromResolved(@NonNull Context context, @NonNull List recipients) throws IOException { - List addresses = new ArrayList<>(recipients.size()); + if (FeatureFlags.cds()) { + List recipientsWithoutUuids = Stream.of(recipients) + .map(Recipient::resolve) + .filterNot(Recipient::hasUuid) + .toList(); - for (Recipient recipient : recipients) { - addresses.add(toSignalServiceAddress(context, recipient)); + if (recipientsWithoutUuids.size() > 0) { + DirectoryHelper.refreshDirectoryFor(context, recipientsWithoutUuids, false); + } } - return addresses; + return Stream.of(recipients) + .map(Recipient::resolve) + .map(r -> new SignalServiceAddress(r.getUuid().orNull(), r.getE164().orNull())) + .toList(); } public static boolean isBlockable(@NonNull Recipient recipient) { @@ -105,6 +110,16 @@ public class RecipientUtil { return resolved.isPushGroup() || resolved.hasServiceIdentifier(); } + public static List getEligibleForSending(@NonNull List recipients) { + if (FeatureFlags.cds()) { + return Stream.of(recipients) + .filter(r -> r.getRegistered() != RegisteredState.NOT_REGISTERED) + .toList(); + } else { + return recipients; + } + } + /** * You can call this for non-groups and not have to handle any network errors. */ diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/DirectoryRefreshListener.java b/app/src/main/java/org/thoughtcrime/securesms/service/DirectoryRefreshListener.java index 45f8ef197..7f8bf1ff6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/DirectoryRefreshListener.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/DirectoryRefreshListener.java @@ -13,7 +13,7 @@ import java.util.concurrent.TimeUnit; public class DirectoryRefreshListener extends PersistentAlarmManagerListener { - private static final long INTERVAL = TimeUnit.HOURS.toMillis(12); + private static final long INTERVAL = TimeUnit.HOURS.toMillis(6); @Override protected long getNextScheduledExecutionTime(Context context) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java b/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java index afdde5f5d..e92d0c03a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java @@ -59,7 +59,7 @@ public final class FeatureFlags { private static final String GROUPS_V2_JOIN_VERSION = "android.groupsv2.joinVersion"; private static final String GROUPS_V2_LINKS_VERSION = "android.groupsv2.manageGroupLinksVersion"; private static final String GROUPS_V2_CAPACITY = "global.groupsv2.maxGroupSize"; - private static final String CDS = "android.cds.4"; + private static final String CDS_VERSION = "android.cdsVersion"; private static final String INTERNAL_USER = "android.internalUser"; private static final String MENTIONS = "android.mentions"; private static final String VERIFY_V2 = "android.verifyV2"; @@ -77,7 +77,7 @@ public final class FeatureFlags { GROUPS_V2_CAPACITY, GROUPS_V2_JOIN_VERSION, GROUPS_V2_LINKS_VERSION, - CDS, + CDS_VERSION, INTERNAL_USER, USERNAMES, MENTIONS, @@ -106,7 +106,7 @@ public final class FeatureFlags { GROUPS_V2_CREATE, GROUPS_V2_JOIN_VERSION, VERIFY_V2, - CDS + CDS_VERSION ); /** @@ -266,7 +266,7 @@ public final class FeatureFlags { /** Whether or not to use the new contact discovery service endpoint, which supports UUIDs. */ public static boolean cds() { - return getBoolean(CDS, false); + return getVersionFlag(CDS_VERSION) == VersionFlag.ON; } /** Whether or not we allow mentions send support in groups. */ diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java index 31e71cb16..3cc0ec4e4 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java @@ -368,6 +368,10 @@ public class SignalServiceAccountManager { public Map getRegisteredUsers(KeyStore iasKeyStore, Set e164numbers, String mrenclave) throws IOException, Quote.InvalidQuoteFormatException, UnauthenticatedQuoteException, SignatureException, UnauthenticatedResponseException { + if (e164numbers.isEmpty()) { + return Collections.emptyMap(); + } + try { String authorization = this.pushServiceSocket.getContactDiscoveryAuthorization(); Map attestations = RemoteAttestationUtil.getAndVerifyMultiRemoteAttestation(pushServiceSocket,