Strongly type UUIDs as ACIs.

This commit is contained in:
Greyson Parrelli
2021-10-28 15:39:36 -04:00
parent 6c7d837964
commit 5bb48caafd
120 changed files with 1020 additions and 947 deletions

View File

@@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.util.LRUCache;
import org.thoughtcrime.securesms.util.Stopwatch;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.concurrent.FilteredExecutor;
import org.whispersystems.signalservice.api.push.ACI;
import java.util.ArrayList;
import java.util.Collection;
@@ -160,11 +161,11 @@ public final class LiveRecipientCache {
}
if (selfId == null) {
UUID localUuid = TextSecurePreferences.getLocalUuid(context);
ACI localAci = TextSecurePreferences.getLocalAci(context);
String localE164 = TextSecurePreferences.getLocalNumber(context);
if (localUuid != null) {
selfId = recipientDatabase.getByUuid(localUuid).or(recipientDatabase.getByE164(localE164)).orNull();
if (localAci != null) {
selfId = recipientDatabase.getByAci(localAci).or(recipientDatabase.getByE164(localE164)).orNull();
} else if (localE164 != null) {
selfId = recipientDatabase.getByE164(localE164).orNull();
} else {

View File

@@ -33,6 +33,7 @@ import org.thoughtcrime.securesms.database.RecipientDatabase.MentionSetting;
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode;
import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState;
import org.whispersystems.signalservice.api.push.ACI;
import org.thoughtcrime.securesms.database.model.databaseprotos.RecipientExtras;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.GroupId;
@@ -77,7 +78,7 @@ public class Recipient {
private final RecipientId id;
private final boolean resolving;
private final UUID uuid;
private final ACI aci;
private final String username;
private final String e164;
private final String email;
@@ -163,8 +164,8 @@ public class Recipient {
* Returns a fully-populated {@link Recipient} and associates it with the provided username.
*/
@WorkerThread
public static @NonNull Recipient externalUsername(@NonNull Context context, @NonNull UUID uuid, @NonNull String username) {
Recipient recipient = externalPush(context, uuid, null, false);
public static @NonNull Recipient externalUsername(@NonNull Context context, @NonNull ACI aci, @NonNull String username) {
Recipient recipient = externalPush(context, aci, null, false);
DatabaseFactory.getRecipientDatabase(context).setUsername(recipient.getId(), username);
return recipient;
}
@@ -172,11 +173,11 @@ public class Recipient {
/**
* Returns a fully-populated {@link Recipient} based off of a {@link SignalServiceAddress},
* creating one in the database if necessary. Convenience overload of
* {@link #externalPush(Context, UUID, String, boolean)}
* {@link #externalPush(Context, ACI, String, boolean)}
*/
@WorkerThread
public static @NonNull Recipient externalPush(@NonNull Context context, @NonNull SignalServiceAddress signalServiceAddress) {
return externalPush(context, signalServiceAddress.getUuid(), signalServiceAddress.getNumber().orNull(), false);
return externalPush(context, signalServiceAddress.getAci(), signalServiceAddress.getNumber().orNull(), false);
}
/**
@@ -189,7 +190,7 @@ public class Recipient {
if (address.getNumber().isPresent()) {
return externalPush(context, null, address.getNumber().get(), false);
} else {
return externalPush(context, address.getUuid(), null, false);
return externalPush(context, address.getAci(), null, false);
}
}
@@ -204,7 +205,7 @@ public class Recipient {
*/
@WorkerThread
public static @NonNull Recipient externalHighTrustPush(@NonNull Context context, @NonNull SignalServiceAddress signalServiceAddress) {
return externalPush(context, signalServiceAddress.getUuid(), signalServiceAddress.getNumber().orNull(), true);
return externalPush(context, signalServiceAddress.getAci(), signalServiceAddress.getNumber().orNull(), true);
}
/**
@@ -220,19 +221,19 @@ public class Recipient {
* that can be trusted as accurate (like an envelope).
*/
@WorkerThread
public static @NonNull Recipient externalPush(@NonNull Context context, @Nullable UUID uuid, @Nullable String e164, boolean highTrust) {
if (UuidUtil.UNKNOWN_UUID.equals(uuid)) {
public static @NonNull Recipient externalPush(@NonNull Context context, @Nullable ACI aci, @Nullable String e164, boolean highTrust) {
if (UuidUtil.UNKNOWN_UUID.equals(aci)) {
throw new AssertionError();
}
RecipientDatabase db = DatabaseFactory.getRecipientDatabase(context);
RecipientId recipientId = db.getAndPossiblyMerge(uuid, e164, highTrust);
RecipientId recipientId = db.getAndPossiblyMerge(aci, e164, highTrust);
Recipient resolved = resolved(recipientId);
if (highTrust && !resolved.isRegistered() && uuid != null) {
if (highTrust && !resolved.isRegistered() && aci != null) {
Log.w(TAG, "External high-trust push was locally marked unregistered. Marking as registered.");
db.markRegistered(recipientId, uuid);
db.markRegistered(recipientId, aci);
} else if (highTrust && !resolved.isRegistered()) {
Log.w(TAG, "External high-trust push was locally marked unregistered, but we don't have a UUID, so we can't do anything.", new Throwable());
}
@@ -298,7 +299,7 @@ public class Recipient {
* or serialized groupId.
*
* If the identifier is a UUID of a Signal user, prefer using
* {@link #externalPush(Context, UUID, String, boolean)} or its overload, as this will let us associate
* {@link #externalPush(Context, ACI, String, boolean)} or its overload, as this will let us associate
* the phone number with the recipient.
*/
@WorkerThread
@@ -309,8 +310,8 @@ public class Recipient {
RecipientId id = null;
if (UuidUtil.isUuid(identifier)) {
UUID uuid = UuidUtil.parseOrThrow(identifier);
id = db.getOrInsertFromUuid(uuid);
ACI uuid = ACI.parseOrThrow(identifier);
id = db.getOrInsertFromAci(uuid);
} else if (GroupId.isEncodedGroup(identifier)) {
id = db.getOrInsertFromGroupId(GroupId.parseOrThrow(identifier));
} else if (NumberUtil.isValidEmail(identifier)) {
@@ -329,9 +330,9 @@ public class Recipient {
Recipient(@NonNull RecipientId id) {
this.id = id;
this.resolving = true;
this.uuid = null;
this.username = null;
this.resolving = true;
this.aci = null;
this.username = null;
this.e164 = null;
this.email = null;
this.groupId = null;
@@ -384,7 +385,7 @@ public class Recipient {
public Recipient(@NonNull RecipientId id, @NonNull RecipientDetails details, boolean resolved) {
this.id = id;
this.resolving = !resolved;
this.uuid = details.uuid;
this.aci = details.aci;
this.username = details.username;
this.e164 = details.e164;
this.email = details.email;
@@ -603,8 +604,8 @@ public class Recipient {
return StringUtil.isolateBidi(name);
}
public @NonNull Optional<UUID> getUuid() {
return Optional.fromNullable(uuid);
public @NonNull Optional<ACI> getAci() {
return Optional.fromNullable(aci);
}
public @NonNull Optional<String> getUsername() {
@@ -631,8 +632,8 @@ public class Recipient {
return Optional.fromNullable(e164).or(Optional.fromNullable(email));
}
public @NonNull UUID requireUuid() {
UUID resolved = resolving ? resolve().uuid : uuid;
public @NonNull ACI requireAci() {
ACI resolved = resolving ? resolve().aci : aci;
if (resolved == null) {
throw new MissingAddressError(id);
@@ -682,12 +683,12 @@ public class Recipient {
return getE164().isPresent();
}
public boolean hasUuid() {
return getUuid().isPresent();
public boolean hasAci() {
return getAci().isPresent();
}
public boolean isUuidOnly() {
return hasUuid() && !hasSmsAddress();
public boolean isAciOnly() {
return hasAci() && !hasSmsAddress();
}
public @NonNull GroupId requireGroupId() {
@@ -701,18 +702,18 @@ public class Recipient {
}
public boolean hasServiceIdentifier() {
return uuid != null || e164 != null;
return aci != null || e164 != null;
}
/**
* @return A string identifier able to be used with the Signal service. Prefers UUID, and if not
* @return A string identifier able to be used with the Signal service. Prefers ACI, and if not
* available, will return an E164 number.
*/
public @NonNull String requireServiceId() {
Recipient resolved = resolving ? resolve() : this;
if (resolved.getUuid().isPresent()) {
return resolved.getUuid().get().toString();
if (resolved.getAci().isPresent()) {
return resolved.requireAci().toString();
} else {
return getE164().get();
}
@@ -721,15 +722,15 @@ public class Recipient {
/**
* @return A single string to represent the recipient, in order of precedence:
*
* Group ID > UUID > Phone > Email
* Group ID > ACI > Phone > Email
*/
public @NonNull String requireStringId() {
Recipient resolved = resolving ? resolve() : this;
if (resolved.isGroup()) {
return resolved.requireGroupId().toString();
} else if (resolved.getUuid().isPresent()) {
return resolved.getUuid().get().toString();
} else if (resolved.getAci().isPresent()) {
return resolved.requireAci().toString();
}
return requireSmsAddress();
@@ -1183,7 +1184,7 @@ public class Recipient {
lastProfileFetch == other.lastProfileFetch &&
forceSmsSelection == other.forceSmsSelection &&
Objects.equals(id, other.id) &&
Objects.equals(uuid, other.uuid) &&
Objects.equals(aci, other.aci) &&
Objects.equals(username, other.username) &&
Objects.equals(e164, other.e164) &&
Objects.equals(email, other.email) &&

View File

@@ -22,15 +22,15 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.push.ACI;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
public class RecipientDetails {
final UUID uuid;
final ACI aci;
final String username;
final String e164;
final String email;
@@ -94,7 +94,7 @@ public class RecipientDetails {
this.systemContactPhoto = Util.uri(settings.getSystemContactPhotoUri());
this.customLabel = settings.getSystemPhoneLabel();
this.contactUri = Util.uri(settings.getSystemContactUri());
this.uuid = settings.getUuid();
this.aci = settings.getAci();
this.username = settings.getUsername();
this.e164 = settings.getE164();
this.email = settings.getEmail();
@@ -149,9 +149,9 @@ public class RecipientDetails {
this.groupAvatarId = null;
this.systemContactPhoto = null;
this.customLabel = null;
this.contactUri = null;
this.uuid = null;
this.username = null;
this.contactUri = null;
this.aci = null;
this.username = null;
this.e164 = null;
this.email = null;
this.groupId = null;
@@ -201,7 +201,7 @@ public class RecipientDetails {
public static @NonNull RecipientDetails forIndividual(@NonNull Context context, @NonNull RecipientSettings settings) {
boolean systemContact = !settings.getSystemProfileName().isEmpty();
boolean isSelf = (settings.getE164() != null && settings.getE164().equals(TextSecurePreferences.getLocalNumber(context))) ||
(settings.getUuid() != null && settings.getUuid().equals(TextSecurePreferences.getLocalUuid(context)));
(settings.getAci() != null && settings.getAci().equals(TextSecurePreferences.getLocalAci(context)));
RegisteredState registeredState = settings.getRegistered();

View File

@@ -14,6 +14,7 @@ import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.util.DelimiterUtil;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.util.UuidUtil;
@@ -54,7 +55,7 @@ public class RecipientId implements Parcelable, Comparable<RecipientId> {
@AnyThread
public static @NonNull RecipientId from(@NonNull SignalServiceAddress address) {
return from(address.getUuid(), address.getNumber().orNull(), false);
return from(address.getAci(), address.getNumber().orNull(), false);
}
/**
@@ -65,7 +66,7 @@ public class RecipientId implements Parcelable, Comparable<RecipientId> {
@AnyThread
public static @NonNull RecipientId fromExternalPush(@NonNull String identifier) {
if (UuidUtil.isUuid(identifier)) {
return from(UuidUtil.parseOrThrow(identifier), null);
return from(ACI.parseOrThrow(identifier), null);
} else {
return from(null, identifier);
}
@@ -77,7 +78,7 @@ public class RecipientId implements Parcelable, Comparable<RecipientId> {
*/
@AnyThread
public static @NonNull RecipientId fromHighTrust(@NonNull SignalServiceAddress address) {
return from(address.getUuid(), address.getNumber().orNull(), true);
return from(address.getAci(), address.getNumber().orNull(), true);
}
/**
@@ -85,17 +86,17 @@ public class RecipientId implements Parcelable, Comparable<RecipientId> {
*/
@AnyThread
@SuppressLint("WrongThread")
public static @NonNull RecipientId from(@Nullable UUID uuid, @Nullable String e164) {
return from(uuid, e164, false);
public static @NonNull RecipientId from(@Nullable ACI aci, @Nullable String e164) {
return from(aci, e164, false);
}
@AnyThread
@SuppressLint("WrongThread")
private static @NonNull RecipientId from(@Nullable UUID uuid, @Nullable String e164, boolean highTrust) {
RecipientId recipientId = RecipientIdCache.INSTANCE.get(uuid, e164);
private static @NonNull RecipientId from(@Nullable ACI aci, @Nullable String e164, boolean highTrust) {
RecipientId recipientId = RecipientIdCache.INSTANCE.get(aci, e164);
if (recipientId == null) {
Recipient recipient = Recipient.externalPush(ApplicationDependencies.getApplication(), uuid, e164, highTrust);
Recipient recipient = Recipient.externalPush(ApplicationDependencies.getApplication(), aci, e164, highTrust);
RecipientIdCache.INSTANCE.put(recipient);
recipientId = recipient.getId();
}

View File

@@ -5,6 +5,7 @@ import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.push.ACI;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -35,35 +36,35 @@ final class RecipientIdCache {
synchronized void put(@NonNull Recipient recipient) {
RecipientId recipientId = recipient.getId();
Optional<String> e164 = recipient.getE164();
Optional<UUID> uuid = recipient.getUuid();
Optional<ACI> aci = recipient.getAci();
if (e164.isPresent()) {
ids.put(e164.get(), recipientId);
}
if (uuid.isPresent()) {
ids.put(uuid.get(), recipientId);
if (aci.isPresent()) {
ids.put(aci.get(), recipientId);
}
}
synchronized @Nullable RecipientId get(@Nullable UUID uuid, @Nullable String e164) {
if (uuid != null && e164 != null) {
RecipientId recipientIdByUuid = ids.get(uuid);
if (recipientIdByUuid == null) return null;
synchronized @Nullable RecipientId get(@Nullable ACI aci, @Nullable String e164) {
if (aci != null && e164 != null) {
RecipientId recipientIdByAci = ids.get(aci);
if (recipientIdByAci == null) return null;
RecipientId recipientIdByE164 = ids.get(e164);
if (recipientIdByE164 == null) return null;
if (recipientIdByUuid.equals(recipientIdByE164)) {
return recipientIdByUuid;
if (recipientIdByAci.equals(recipientIdByE164)) {
return recipientIdByAci;
} else {
ids.remove(uuid);
ids.remove(aci);
ids.remove(e164);
Log.w(TAG, "Seen invalid RecipientIdCacheState");
return null;
}
} else if (uuid != null) {
return ids.get(uuid);
} else if (aci != null) {
return ids.get(aci);
} else if (e164 != null) {
return ids.get(e164);
}

View File

@@ -33,7 +33,6 @@ import org.whispersystems.signalservice.api.push.exceptions.NotFoundException;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
public class RecipientUtil {
@@ -50,11 +49,11 @@ public class RecipientUtil {
{
recipient = recipient.resolve();
if (!recipient.getUuid().isPresent() && !recipient.getE164().isPresent()) {
if (!recipient.getAci().isPresent() && !recipient.getE164().isPresent()) {
throw new AssertionError(recipient.getId() + " - No UUID or phone number!");
}
if (!recipient.getUuid().isPresent()) {
if (!recipient.getAci().isPresent()) {
Log.i(TAG, recipient.getId() + " is missing a UUID...");
RegisteredState state = DirectoryHelper.refreshDirectoryFor(context, recipient, false);
@@ -62,8 +61,8 @@ public class RecipientUtil {
Log.i(TAG, "Successfully performed a UUID fetch for " + recipient.getId() + ". Registered: " + state);
}
if (recipient.hasUuid()) {
return new SignalServiceAddress(recipient.requireUuid(), Optional.fromNullable(recipient.resolve().getE164().orNull()));
if (recipient.hasAci()) {
return new SignalServiceAddress(recipient.requireAci(), Optional.fromNullable(recipient.resolve().getE164().orNull()));
} else {
throw new NotFoundException(recipient.getId() + " is not registered!");
}
@@ -82,7 +81,7 @@ public class RecipientUtil {
return Stream.of(recipients)
.map(Recipient::resolve)
.map(r -> new SignalServiceAddress(r.requireUuid(), r.getE164().orNull()))
.map(r -> new SignalServiceAddress(r.requireAci(), r.getE164().orNull()))
.toList();
}
@@ -94,7 +93,7 @@ public class RecipientUtil {
{
List<Recipient> recipientsWithoutUuids = Stream.of(recipients)
.map(Recipient::resolve)
.filterNot(Recipient::hasUuid)
.filterNot(Recipient::hasAci)
.toList();
if (recipientsWithoutUuids.size() > 0) {