mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-27 20:24:32 +01:00
Fallback to profile fetches for unlisted contacts.
This commit is contained in:
@@ -25,20 +25,21 @@ import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
||||
import org.thoughtcrime.securesms.contacts.ContactsDatabase;
|
||||
import org.thoughtcrime.securesms.crypto.SessionUtil;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MessageDatabase;
|
||||
import org.thoughtcrime.securesms.database.MessageDatabase.InsertResult;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.BulkOperationsHandle;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
|
||||
import org.thoughtcrime.securesms.database.SessionDatabase;
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
|
||||
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
|
||||
import org.thoughtcrime.securesms.jobs.StorageSyncJob;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
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;
|
||||
@@ -50,10 +51,13 @@ import org.thoughtcrime.securesms.util.SetUtil;
|
||||
import org.thoughtcrime.securesms.util.Stopwatch;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.util.Pair;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.profiles.ProfileAndCredential;
|
||||
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.NotFoundException;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
import org.whispersystems.signalservice.internal.util.concurrent.ListenableFuture;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Calendar;
|
||||
@@ -179,6 +183,13 @@ public class DirectoryHelper {
|
||||
} else {
|
||||
recipientDatabase.markRegistered(recipient.getId());
|
||||
}
|
||||
} else if (recipient.hasUuid() && recipient.isRegistered() && hasCommunicatedWith(context, recipient)) {
|
||||
if (isUuidRegistered(context, recipient)) {
|
||||
recipientDatabase.markRegistered(recipient.getId(), recipient.requireUuid());
|
||||
} else {
|
||||
recipientDatabase.markUnregistered(recipient.getId());
|
||||
}
|
||||
stopwatch.split("e164-unlisted-network");
|
||||
} else {
|
||||
recipientDatabase.markUnregistered(recipient.getId());
|
||||
}
|
||||
@@ -244,6 +255,17 @@ public class DirectoryHelper {
|
||||
|
||||
stopwatch.split("process-cds");
|
||||
|
||||
UnlistedResult unlistedResult = filterForUnlistedUsers(context, inactiveIds);
|
||||
|
||||
inactiveIds.removeAll(unlistedResult.getPossiblyActive());
|
||||
|
||||
if (unlistedResult.getRetries().size() > 0) {
|
||||
Log.i(TAG, "Some profile fetches failed to resolve. Assuming not-inactive for now and scheduling a retry.");
|
||||
RetrieveProfileJob.enqueue(unlistedResult.getRetries());
|
||||
}
|
||||
|
||||
stopwatch.split("handle-unlisted");
|
||||
|
||||
recipientDatabase.bulkUpdatedRegisteredStatus(uuidMap, inactiveIds);
|
||||
|
||||
stopwatch.split("update-registered");
|
||||
@@ -275,16 +297,10 @@ public class DirectoryHelper {
|
||||
|
||||
private static boolean isUuidRegistered(@NonNull Context context, @NonNull Recipient recipient) throws IOException {
|
||||
try {
|
||||
ProfileUtil.retrieveProfile(context, recipient, SignalServiceProfile.RequestType.PROFILE).get(10, TimeUnit.SECONDS);
|
||||
ProfileUtil.retrieveProfileSync(context, recipient, SignalServiceProfile.RequestType.PROFILE);
|
||||
return true;
|
||||
} catch (ExecutionException e) {
|
||||
if (e.getCause() instanceof NotFoundException) {
|
||||
return false;
|
||||
} else {
|
||||
throw new IOException(e);
|
||||
}
|
||||
} catch (InterruptedException | TimeoutException e) {
|
||||
throw new IOException(e);
|
||||
} catch (NotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,6 +436,50 @@ public class DirectoryHelper {
|
||||
}).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Users can mark themselves as 'unlisted' in CDS, meaning that even if CDS says they're
|
||||
* unregistered, they might actually be registered. We need to double-check users who we already
|
||||
* have UUIDs for. Also, we only want to bother doing this for users we have conversations for,
|
||||
* so we will also only check for users that have a thread.
|
||||
*/
|
||||
private static UnlistedResult filterForUnlistedUsers(@NonNull Context context, @NonNull Set<RecipientId> inactiveIds) {
|
||||
List<Recipient> possiblyUnlisted = Stream.of(inactiveIds)
|
||||
.map(Recipient::resolved)
|
||||
.filter(Recipient::isRegistered)
|
||||
.filter(Recipient::hasUuid)
|
||||
.filter(r -> hasCommunicatedWith(context, r))
|
||||
.toList();
|
||||
|
||||
List<Pair<Recipient, ListenableFuture<ProfileAndCredential>>> futures = Stream.of(possiblyUnlisted)
|
||||
.map(r -> new Pair<>(r, ProfileUtil.retrieveProfile(context, r, SignalServiceProfile.RequestType.PROFILE)))
|
||||
.toList();
|
||||
Set<RecipientId> potentiallyActiveIds = new HashSet<>();
|
||||
Set<RecipientId> retries = new HashSet<>();
|
||||
|
||||
Stream.of(futures)
|
||||
.forEach(pair -> {
|
||||
try {
|
||||
pair.second().get(5, TimeUnit.SECONDS);
|
||||
potentiallyActiveIds.add(pair.first().getId());
|
||||
} catch (InterruptedException | TimeoutException e) {
|
||||
retries.add(pair.first().getId());
|
||||
potentiallyActiveIds.add(pair.first().getId());
|
||||
} catch (ExecutionException e) {
|
||||
if (!(e.getCause() instanceof NotFoundException)) {
|
||||
retries.add(pair.first().getId());
|
||||
potentiallyActiveIds.add(pair.first().getId());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return new UnlistedResult(potentiallyActiveIds, retries);
|
||||
}
|
||||
|
||||
private static boolean hasCommunicatedWith(@NonNull Context context, @NonNull Recipient recipient) {
|
||||
return DatabaseFactory.getThreadDatabase(context).hasThread(recipient.getId()) ||
|
||||
DatabaseFactory.getSessionDatabase(context).hasSessionFor(recipient.getId());
|
||||
}
|
||||
|
||||
static class DirectoryResult {
|
||||
private final Map<String, UUID> registeredNumbers;
|
||||
private final Map<String, String> numberRewrites;
|
||||
@@ -441,6 +501,24 @@ public class DirectoryHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private static class UnlistedResult {
|
||||
private final Set<RecipientId> possiblyActive;
|
||||
private final Set<RecipientId> retries;
|
||||
|
||||
private UnlistedResult(@NonNull Set<RecipientId> possiblyActive, @NonNull Set<RecipientId> retries) {
|
||||
this.possiblyActive = possiblyActive;
|
||||
this.retries = retries;
|
||||
}
|
||||
|
||||
@NonNull Set<RecipientId> getPossiblyActive() {
|
||||
return possiblyActive;
|
||||
}
|
||||
|
||||
@NonNull Set<RecipientId> getRetries() {
|
||||
return retries;
|
||||
}
|
||||
}
|
||||
|
||||
private static class AccountHolder {
|
||||
private final boolean fresh;
|
||||
private final Account account;
|
||||
|
||||
Reference in New Issue
Block a user