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
@@ -26,7 +26,6 @@ import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -572,7 +571,7 @@ public final class ContactSelectionListFragment extends LoggingFragment
AlertDialog loadingDialog = SimpleProgressDialog.show(requireContext());
SimpleTask.run(getViewLifecycleOwner().getLifecycle(), () -> {
return UsernameUtil.fetchUuidForUsername(requireContext(), contact.getNumber());
return UsernameUtil.fetchAciForUsername(requireContext(), contact.getNumber());
}, uuid -> {
loadingDialog.dismiss();
if (uuid.isPresent()) {
@@ -75,7 +75,7 @@ public class NewConversationActivity extends ContactSelectionActivity
SimpleTask.run(getLifecycle(), () -> {
Recipient resolved = Recipient.external(this, number);
if (!resolved.isRegistered() || !resolved.hasUuid()) {
if (!resolved.isRegistered() || !resolved.hasAci()) {
Log.i(TAG, "[onContactSelected] Not registered or no UUID. Doing a directory refresh.");
try {
DirectoryHelper.refreshDirectoryFor(this, resolved, false);
@@ -56,7 +56,6 @@ import android.widget.Toast;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.OneShotPreDrawListener;
@@ -64,6 +63,8 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.signal.core.util.ThreadUtil;
import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log;
@@ -322,23 +323,26 @@ public class VerifyIdentityActivity extends PassphraseRequiredActivity implement
//noinspection WrongThread
Recipient resolved = recipient.resolve();
if (FeatureFlags.verifyV2() && resolved.getUuid().isPresent()) {
if (FeatureFlags.verifyV2() && resolved.getAci().isPresent()) {
Log.i(TAG, "Using UUID (version 2).");
version = 2;
localId = UuidUtil.toByteArray(TextSecurePreferences.getLocalUuid(requireContext()));
remoteId = UuidUtil.toByteArray(resolved.getUuid().get());
localId = TextSecurePreferences.getLocalAci(requireContext()).toByteArray();
remoteId = resolved.requireAci().toByteArray();
} else if (!FeatureFlags.verifyV2() && resolved.getE164().isPresent()) {
Log.i(TAG, "Using E164 (version 1).");
version = 1;
localId = TextSecurePreferences.getLocalNumber(requireContext()).getBytes();
remoteId = resolved.requireE164().getBytes();
} else {
Log.w(TAG, String.format(Locale.ENGLISH, "Could not show proper verification! verifyV2: %s, hasUuid: %s, hasE164: %s", FeatureFlags.verifyV2(), resolved.getUuid().isPresent(), resolved.getE164().isPresent()));
new AlertDialog.Builder(requireContext())
.setMessage(getString(R.string.VerifyIdentityActivity_you_must_first_exchange_messages_in_order_to_view, resolved.getDisplayName(requireContext())))
.setPositiveButton(android.R.string.ok, (dialog, which) -> requireActivity().finish())
.setOnDismissListener(dialog -> requireActivity().finish())
.show();
Log.w(TAG, String.format(Locale.ENGLISH, "Could not show proper verification! verifyV2: %s, hasUuid: %s, hasE164: %s", FeatureFlags.verifyV2(), resolved.getAci().isPresent(), resolved.getE164().isPresent()));
new MaterialAlertDialogBuilder(requireContext())
.setMessage(getString(R.string.VerifyIdentityActivity_you_must_first_exchange_messages_in_order_to_view, resolved.getDisplayName(requireContext())))
.setPositiveButton(android.R.string.ok, (dialog, which) -> requireActivity().finish())
.setOnDismissListener(dialog -> {
requireActivity().finish();
dialog.dismiss();
})
.show();
return;
}
@@ -26,8 +26,8 @@ import org.thoughtcrime.securesms.util.Hex
import org.thoughtcrime.securesms.util.SpanUtil
import org.thoughtcrime.securesms.util.Util
import org.thoughtcrime.securesms.util.livedata.Store
import org.whispersystems.signalservice.api.push.ACI
import java.util.Objects
import java.util.UUID
/**
* Shows internal details about a recipient that you can view from the conversation settings.
@@ -60,7 +60,7 @@ class InternalConversationSettingsFragment : DSLSettingsFragment(
)
if (!recipient.isGroup) {
val uuid = recipient.uuid.transform(UUID::toString).or("null")
val uuid = recipient.aci.transform(ACI::toString).or("null")
longClickPref(
title = DSLSettingsText.from("UUID"),
summary = DSLSettingsText.from(uuid),
@@ -145,8 +145,8 @@ class InternalConversationSettingsFragment : DSLSettingsFragment(
.setTitle("Are you sure?")
.setNegativeButton(android.R.string.cancel) { d, _ -> d.dismiss() }
.setPositiveButton(android.R.string.ok) { _, _ ->
if (recipient.hasUuid()) {
DatabaseFactory.getSessionDatabase(context).deleteAllFor(recipient.requireUuid().toString())
if (recipient.hasAci()) {
DatabaseFactory.getSessionDatabase(context).deleteAllFor(recipient.requireAci().toString())
}
if (recipient.hasE164()) {
DatabaseFactory.getSessionDatabase(context).deleteAllFor(recipient.requireE164())
@@ -127,10 +127,10 @@ data class CallParticipantsState(
fun getIncomingRingingGroupDescription(context: Context): String? {
if (callState == WebRtcViewModel.State.CALL_INCOMING &&
groupCallState == WebRtcViewModel.GroupCallState.RINGING &&
ringerRecipient.hasUuid()
ringerRecipient.hasAci()
) {
val ringerName = ringerRecipient.getShortDisplayName(context)
val membersWithoutYouOrRinger: List<GroupMemberEntry.FullMember> = groupMembers.filterNot { it.member.isSelf || ringerRecipient.requireUuid() == it.member.uuid.orNull() }
val membersWithoutYouOrRinger: List<GroupMemberEntry.FullMember> = groupMembers.filterNot { it.member.isSelf || ringerRecipient.requireAci() == it.member.aci.orNull() }
return when (membersWithoutYouOrRinger.size) {
0 -> context.getString(R.string.WebRtcCallView__s_is_calling_you, ringerName)
@@ -16,6 +16,7 @@ import org.thoughtcrime.securesms.push.IasTrustStore;
import org.thoughtcrime.securesms.util.SetUtil;
import org.whispersystems.libsignal.InvalidKeyException;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.TrustStore;
import org.whispersystems.signalservice.internal.contacts.crypto.Quote;
import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedQuoteException;
@@ -66,7 +67,7 @@ class ContactDiscoveryV2 {
KeyStore iasKeyStore = getIasKeyStore(context);
try {
Map<String, UUID> results = accountManager.getRegisteredUsers(iasKeyStore, sanitizedNumbers, BuildConfig.CDS_MRENCLAVE);
Map<String, ACI> results = accountManager.getRegisteredUsers(iasKeyStore, sanitizedNumbers, BuildConfig.CDS_MRENCLAVE);
FuzzyPhoneNumberHelper.OutputResult outputResult = FuzzyPhoneNumberHelper.generateOutput(results, inputResult);
return new DirectoryResult(outputResult.getNumbers(), outputResult.getRewrites(), ignoredNumbers);
@@ -9,6 +9,7 @@ import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper.DirectoryResult;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.util.SetUtil;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.ACI;
import java.io.IOException;
import java.util.ArrayList;
@@ -46,7 +47,7 @@ class ContactDiscoveryV3 {
SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager();
try {
Map<String, UUID> results = accountManager.getRegisteredUsersWithCdsh(sanitizedNumbers, BuildConfig.CDSH_PUBLIC_KEY, BuildConfig.CDSH_CODE_HASH);
Map<String, ACI> results = accountManager.getRegisteredUsersWithCdsh(sanitizedNumbers, BuildConfig.CDSH_PUBLIC_KEY, BuildConfig.CDSH_CODE_HASH);
FuzzyPhoneNumberHelper.OutputResult outputResult = FuzzyPhoneNumberHelper.generateOutput(results, inputResult);
return new DirectoryResult(outputResult.getNumbers(), outputResult.getRewrites(), ignoredNumbers);
@@ -29,6 +29,7 @@ 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.whispersystems.signalservice.api.push.ACI;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
@@ -67,7 +68,6 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import io.reactivex.rxjava3.core.Observable;
@@ -112,9 +112,9 @@ public class DirectoryHelper {
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
for (Recipient recipient : recipients) {
if (recipient.hasUuid() && !recipient.hasE164()) {
if (isUuidRegistered(context, recipient)) {
recipientDatabase.markRegistered(recipient.getId(), recipient.requireUuid());
if (recipient.hasAci() && !recipient.hasE164()) {
if (isAciRegistered(context, recipient)) {
recipientDatabase.markRegistered(recipient.getId(), recipient.requireAci());
} else {
recipientDatabase.markUnregistered(recipient.getId());
}
@@ -136,11 +136,11 @@ public class DirectoryHelper {
RegisteredState originalRegisteredState = recipient.resolve().getRegistered();
RegisteredState newRegisteredState;
if (recipient.hasUuid() && !recipient.hasE164()) {
boolean isRegistered = isUuidRegistered(context, recipient);
if (recipient.hasAci() && !recipient.hasE164()) {
boolean isRegistered = isAciRegistered(context, recipient);
stopwatch.split("uuid-network");
if (isRegistered) {
boolean idChanged = recipientDatabase.markRegistered(recipient.getId(), recipient.getUuid().get());
boolean idChanged = recipientDatabase.markRegistered(recipient.getId(), recipient.requireAci());
if (idChanged) {
Log.w(TAG, "ID changed during refresh by UUID.");
}
@@ -169,18 +169,18 @@ public class DirectoryHelper {
}
if (result.getRegisteredNumbers().size() > 0) {
UUID uuid = result.getRegisteredNumbers().values().iterator().next();
if (uuid != null) {
boolean idChanged = recipientDatabase.markRegistered(recipient.getId(), uuid);
ACI aci = result.getRegisteredNumbers().values().iterator().next();
if (aci != null) {
boolean idChanged = recipientDatabase.markRegistered(recipient.getId(), aci);
if (idChanged) {
recipient = Recipient.resolved(recipientDatabase.getByUuid(uuid).get());
recipient = Recipient.resolved(recipientDatabase.getByAci(aci).get());
}
} else {
Log.w(TAG, "Registered number set had a null UUID!");
}
} else if (recipient.hasUuid() && recipient.isRegistered() && hasCommunicatedWith(context, recipient)) {
if (isUuidRegistered(context, recipient)) {
recipientDatabase.markRegistered(recipient.getId(), recipient.requireUuid());
} else if (recipient.hasAci() && recipient.isRegistered() && hasCommunicatedWith(context, recipient)) {
if (isAciRegistered(context, recipient)) {
recipientDatabase.markRegistered(recipient.getId(), recipient.requireAci());
} else {
recipientDatabase.markUnregistered(recipient.getId());
}
@@ -245,10 +245,10 @@ public class DirectoryHelper {
recipientDatabase.updatePhoneNumbers(result.getNumberRewrites());
}
Map<RecipientId, String> uuidMap = recipientDatabase.bulkProcessCdsResult(result.getRegisteredNumbers());
Set<String> activeNumbers = result.getRegisteredNumbers().keySet();
Set<RecipientId> activeIds = uuidMap.keySet();
Set<RecipientId> inactiveIds = Stream.of(allNumbers)
Map<RecipientId, ACI> aciMap = recipientDatabase.bulkProcessCdsResult(result.getRegisteredNumbers());
Set<String> activeNumbers = result.getRegisteredNumbers().keySet();
Set<RecipientId> activeIds = aciMap.keySet();
Set<RecipientId> inactiveIds = Stream.of(allNumbers)
.filterNot(activeNumbers::contains)
.filterNot(n -> result.getNumberRewrites().containsKey(n))
.filterNot(n -> result.getIgnoredNumbers().contains(n))
@@ -270,7 +270,7 @@ public class DirectoryHelper {
Set<RecipientId> preExistingRegisteredUsers = new HashSet<>(recipientDatabase.getRegistered());
recipientDatabase.bulkUpdatedRegisteredStatus(uuidMap, inactiveIds);
recipientDatabase.bulkUpdatedRegisteredStatus(aciMap, inactiveIds);
stopwatch.split("update-registered");
@@ -298,7 +298,7 @@ public class DirectoryHelper {
}
private static boolean isUuidRegistered(@NonNull Context context, @NonNull Recipient recipient) throws IOException {
private static boolean isAciRegistered(@NonNull Context context, @NonNull Recipient recipient) throws IOException {
try {
ProfileUtil.retrieveProfileSync(context, recipient, SignalServiceProfile.RequestType.PROFILE);
return true;
@@ -514,7 +514,7 @@ public class DirectoryHelper {
List<Recipient> possiblyUnlisted = Stream.of(inactiveIds)
.map(Recipient::resolved)
.filter(Recipient::isRegistered)
.filter(Recipient::hasUuid)
.filter(Recipient::hasAci)
.filter(r -> hasCommunicatedWith(context, r))
.toList();
@@ -549,17 +549,17 @@ public class DirectoryHelper {
}
private static boolean hasCommunicatedWith(@NonNull Context context, @NonNull Recipient recipient) {
return DatabaseFactory.getThreadDatabase(context).hasThread(recipient.getId()) ||
(recipient.hasUuid() && DatabaseFactory.getSessionDatabase(context).hasSessionFor(recipient.requireUuid().toString())) ||
return DatabaseFactory.getThreadDatabase(context).hasThread(recipient.getId()) ||
(recipient.hasAci() && DatabaseFactory.getSessionDatabase(context).hasSessionFor(recipient.requireAci().toString())) ||
(recipient.hasE164() && DatabaseFactory.getSessionDatabase(context).hasSessionFor(recipient.requireE164()));
}
static class DirectoryResult {
private final Map<String, UUID> registeredNumbers;
private final Map<String, ACI> registeredNumbers;
private final Map<String, String> numberRewrites;
private final Set<String> ignoredNumbers;
DirectoryResult(@NonNull Map<String, UUID> registeredNumbers,
DirectoryResult(@NonNull Map<String, ACI> registeredNumbers,
@NonNull Map<String, String> numberRewrites,
@NonNull Set<String> ignoredNumbers)
{
@@ -569,7 +569,7 @@ public class DirectoryHelper {
}
@NonNull Map<String, UUID> getRegisteredNumbers() {
@NonNull Map<String, ACI> getRegisteredNumbers() {
return registeredNumbers;
}
@@ -4,6 +4,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import org.whispersystems.signalservice.api.push.ACI;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
@@ -50,8 +52,8 @@ class FuzzyPhoneNumberHelper {
* these results and our initial input set, we can decide if we need to rewrite which number we
* have stored locally.
*/
static @NonNull OutputResult generateOutput(@NonNull Map<String, UUID> registeredNumbers, @NonNull InputResult inputResult) {
Map<String, UUID> allNumbers = new HashMap<>(registeredNumbers);
static @NonNull OutputResult generateOutput(@NonNull Map<String, ACI> registeredNumbers, @NonNull InputResult inputResult) {
Map<String, ACI> allNumbers = new HashMap<>(registeredNumbers);
Map<String, String> rewrites = new HashMap<>();
for (Map.Entry<String, String> entry : inputResult.getMapOfOriginalToVariant().entrySet()) {
@@ -170,15 +172,15 @@ class FuzzyPhoneNumberHelper {
}
public static class OutputResult {
private final Map<String, UUID> numbers;
private final Map<String, ACI> numbers;
private final Map<String, String> rewrites;
private OutputResult(@NonNull Map<String, UUID> numbers, @NonNull Map<String, String> rewrites) {
private OutputResult(@NonNull Map<String, ACI> numbers, @NonNull Map<String, String> rewrites) {
this.numbers = numbers;
this.rewrites = rewrites;
}
public @NonNull Map<String, UUID> getNumbers() {
public @NonNull Map<String, ACI> getNumbers() {
return numbers;
}
@@ -249,7 +249,6 @@ import org.thoughtcrime.securesms.search.MessageResult;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage;
import org.thoughtcrime.securesms.sms.OutgoingEndSessionMessage;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.stickers.StickerEventListener;
import org.thoughtcrime.securesms.stickers.StickerLocator;
@@ -1521,7 +1520,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
sendButton.resetAvailableTransports(isMediaMessage);
if (!isSecureText && !isPushGroupConversation() && !recipient.get().isUuidOnly()) {
if (!isSecureText && !isPushGroupConversation() && !recipient.get().isAciOnly()) {
sendButton.disableTransport(Type.TEXTSECURE);
}
@@ -1532,7 +1531,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
if (!recipient.get().isPushGroup() && recipient.get().isForceSmsSelection()) {
sendButton.setDefaultTransport(Type.SMS);
} else {
if (isSecureText || isPushGroupConversation() || recipient.get().isUuidOnly()) {
if (isSecureText || isPushGroupConversation() || recipient.get().isAciOnly()) {
sendButton.setDefaultTransport(Type.TEXTSECURE);
} else {
sendButton.setDefaultTransport(Type.SMS);
@@ -2942,7 +2941,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
return new SettableFuture<>(null);
}
final boolean sendPush = (isSecureText && !forceSms) || recipient.get().isUuidOnly();
final boolean sendPush = (isSecureText && !forceSms) || recipient.get().isAciOnly();
final long thread = this.threadId;
if (sendPush) {
@@ -3005,7 +3004,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
final long thread = this.threadId;
final Context context = getApplicationContext();
final String messageBody = getMessage();
final boolean sendPush = (isSecureText && !forceSms) || recipient.get().isUuidOnly();
final boolean sendPush = (isSecureText && !forceSms) || recipient.get().isAciOnly();
OutgoingTextMessage message;
@@ -47,10 +47,9 @@ import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.push.ACI;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
@@ -343,11 +342,11 @@ public final class ConversationUpdateItem extends FrameLayout
});
} else if (conversationMessage.getMessageRecord().isGroupCall()) {
UpdateDescription updateDescription = MessageRecord.getGroupCallUpdateDescription(getContext(), conversationMessage.getMessageRecord().getBody(), true);
Collection<UUID> uuids = updateDescription.getMentioned();
Collection<ACI> acis = updateDescription.getMentioned();
int text = 0;
if (Util.hasItems(uuids)) {
if (uuids.contains(TextSecurePreferences.getLocalUuid(getContext()))) {
if (Util.hasItems(acis)) {
if (acis.contains(TextSecurePreferences.getLocalAci(getContext()))) {
text = R.string.ConversationUpdateItem_return_to_call;
} else if (GroupCallUpdateDetailsUtil.parse(conversationMessage.getMessageRecord().getBody()).getIsCallFull()) {
text = R.string.ConversationUpdateItem_call_is_full;
@@ -5,8 +5,6 @@ import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.SessionUtil;
@@ -124,7 +122,7 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
@Override
public boolean isTrustedIdentity(SignalProtocolAddress address, IdentityKey identityKey, Direction direction) {
boolean isSelf = address.getName().equals(TextSecurePreferences.getLocalUuid(context).toString()) ||
boolean isSelf = address.getName().equals(TextSecurePreferences.getLocalAci(context).toString()) ||
address.getName().equals(TextSecurePreferences.getLocalNumber(context));
if (isSelf) {
@@ -134,8 +134,8 @@ public class TextSecureSessionStore implements SignalServiceSessionStore {
synchronized (LOCK) {
Recipient recipient = Recipient.resolved(recipientId);
if (recipient.hasUuid()) {
archiveSession(new SignalProtocolAddress(recipient.requireUuid().toString(), deviceId));
if (recipient.hasAci()) {
archiveSession(new SignalProtocolAddress(recipient.requireAci().toString(), deviceId));
}
if (recipient.hasE164()) {
@@ -26,6 +26,7 @@ import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.v2.processing.GroupsV2StateProcessor;
import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.DistributionId;
import org.thoughtcrime.securesms.groups.GroupAccessControl;
import org.thoughtcrime.securesms.groups.GroupId;
@@ -804,10 +805,10 @@ private static final String[] GROUP_PROJECTION = {
}
private static boolean gv2GroupActive(@NonNull DecryptedGroup decryptedGroup) {
UUID uuid = Recipient.self().getUuid().get();
ACI aci = Recipient.self().requireAci();
return DecryptedGroupUtil.findMemberByUuid(decryptedGroup.getMembersList(), uuid).isPresent() ||
DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), uuid).isPresent();
return DecryptedGroupUtil.findMemberByUuid(decryptedGroup.getMembersList(), aci.uuid()).isPresent() ||
DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), aci.uuid()).isPresent();
}
private List<RecipientId> getCurrentMembers(@NonNull GroupId groupId) {
@@ -868,7 +869,7 @@ private static final String[] GROUP_PROJECTION = {
if (UuidUtil.UNKNOWN_UUID.equals(uuid)) {
Log.w(TAG, "Seen unknown UUID in members list");
} else {
groupMembers.add(RecipientId.from(uuid, null));
groupMembers.add(RecipientId.from(ACI.from(uuid), null));
}
}
@@ -1186,9 +1187,9 @@ private static final String[] GROUP_PROJECTION = {
*/
public boolean isPendingMember(@NonNull Recipient recipient) {
if (isV2Group()) {
Optional<UUID> uuid = recipient.getUuid();
if (uuid.isPresent()) {
return DecryptedGroupUtil.findPendingByUuid(requireV2GroupProperties().getDecryptedGroup().getPendingMembersList(), uuid.get())
Optional<ACI> aci = recipient.getAci();
if (aci.isPresent()) {
return DecryptedGroupUtil.findPendingByUuid(requireV2GroupProperties().getDecryptedGroup().getPendingMembersList(), aci.get().uuid())
.isPresent();
}
}
@@ -1229,13 +1230,13 @@ private static final String[] GROUP_PROJECTION = {
}
public boolean isAdmin(@NonNull Recipient recipient) {
Optional<UUID> uuid = recipient.getUuid();
Optional<ACI> aci = recipient.getAci();
if (!uuid.isPresent()) {
if (!aci.isPresent()) {
return false;
}
return DecryptedGroupUtil.findMemberByUuid(getDecryptedGroup().getMembersList(), uuid.get())
return DecryptedGroupUtil.findMemberByUuid(getDecryptedGroup().getMembersList(), aci.get().uuid())
.transform(t -> t.getRole() == Member.Role.ADMINISTRATOR)
.or(false);
}
@@ -1245,21 +1246,21 @@ private static final String[] GROUP_PROJECTION = {
}
public MemberLevel memberLevel(@NonNull Recipient recipient) {
Optional<UUID> uuid = recipient.getUuid();
Optional<ACI> aci = recipient.getAci();
if (!uuid.isPresent()) {
if (!aci.isPresent()) {
return MemberLevel.NOT_A_MEMBER;
}
DecryptedGroup decryptedGroup = getDecryptedGroup();
return DecryptedGroupUtil.findMemberByUuid(decryptedGroup.getMembersList(), uuid.get())
return DecryptedGroupUtil.findMemberByUuid(decryptedGroup.getMembersList(), aci.get().uuid())
.transform(member -> member.getRole() == Member.Role.ADMINISTRATOR
? MemberLevel.ADMINISTRATOR
: MemberLevel.FULL_MEMBER)
.or(() -> DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), uuid.get())
.or(() -> DecryptedGroupUtil.findPendingByUuid(decryptedGroup.getPendingMembersList(), aci.get().uuid())
.transform(m -> MemberLevel.PENDING_MEMBER)
.or(() -> DecryptedGroupUtil.findRequestingByUuid(decryptedGroup.getRequestingMembersList(), uuid.get())
.or(() -> DecryptedGroupUtil.findRequestingByUuid(decryptedGroup.getRequestingMembersList(), aci.get().uuid())
.transform(m -> MemberLevel.REQUESTING_MEMBER)
.or(MemberLevel.NOT_A_MEMBER)));
}
@@ -1271,7 +1272,7 @@ private static final String[] GROUP_PROJECTION = {
public List<RecipientId> getMemberRecipientIds(@NonNull MemberSet memberSet) {
boolean includeSelf = memberSet.includeSelf;
DecryptedGroup groupV2 = getDecryptedGroup();
UUID selfUuid = Recipient.self().getUuid().get();
UUID selfUuid = Recipient.self().requireAci().uuid();
List<RecipientId> recipients = new ArrayList<>(groupV2.getMembersCount() + groupV2.getPendingMembersCount());
int unknownMembers = 0;
int unknownPending = 0;
@@ -1280,7 +1281,7 @@ private static final String[] GROUP_PROJECTION = {
if (UuidUtil.UNKNOWN_UUID.equals(uuid)) {
unknownMembers++;
} else if (includeSelf || !selfUuid.equals(uuid)) {
recipients.add(RecipientId.from(uuid, null));
recipients.add(RecipientId.from(ACI.from(uuid), null));
}
}
if (memberSet.includePending) {
@@ -1288,7 +1289,7 @@ private static final String[] GROUP_PROJECTION = {
if (UuidUtil.UNKNOWN_UUID.equals(uuid)) {
unknownPending++;
} else if (includeSelf || !selfUuid.equals(uuid)) {
recipients.add(RecipientId.from(uuid, null));
recipients.add(RecipientId.from(ACI.from(uuid), null));
}
}
}
@@ -18,6 +18,7 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.util.ArrayList;
@@ -105,7 +106,7 @@ public final class MentionUtil {
BodyRangeList.Builder builder = BodyRangeList.newBuilder();
for (Mention mention : mentions) {
String uuid = Recipient.resolved(mention.getRecipientId()).requireUuid().toString();
String uuid = Recipient.resolved(mention.getRecipientId()).requireAci().toString();
builder.addRanges(BodyRangeList.BodyRange.newBuilder()
.setMentionUuid(uuid)
.setStart(mention.getStart())
@@ -121,7 +122,7 @@ public final class MentionUtil {
return Stream.of(BodyRangeList.parseFrom(data).getRangesList())
.filter(bodyRange -> bodyRange.getAssociatedValueCase() == BodyRangeList.BodyRange.AssociatedValueCase.MENTIONUUID)
.map(mention -> {
RecipientId id = Recipient.externalPush(context, UuidUtil.parseOrThrow(mention.getMentionUuid()), null, false).getId();
RecipientId id = Recipient.externalPush(context, ACI.parseOrThrow(mention.getMentionUuid()), null, false).getId();
return new Mention(id, mention.getStart(), mention.getLength());
})
.toList();
@@ -81,6 +81,7 @@ 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.push.ACI;
import java.io.IOException;
import java.security.SecureRandom;
@@ -1559,7 +1560,7 @@ public class MmsDatabase extends MessageDatabase {
MessageGroupContext.GroupV2Properties groupV2Properties = outgoingGroupUpdateMessage.requireGroupV2Properties();
members.addAll(Stream.of(groupV2Properties.getAllActivePendingAndRemovedMembers())
.distinct()
.map(uuid -> RecipientId.from(uuid, null))
.map(uuid -> RecipientId.from(ACI.from(uuid), null))
.toList());
members.remove(Recipient.self().getId());
} else {
@@ -33,6 +33,7 @@ import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.whispersystems.signalservice.api.push.ACI;
import org.thoughtcrime.securesms.database.model.IdentityRecord;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.database.model.databaseprotos.BadgeList;
@@ -80,7 +81,6 @@ import org.whispersystems.signalservice.api.storage.SignalContactRecord;
import org.whispersystems.signalservice.api.storage.SignalGroupV1Record;
import org.whispersystems.signalservice.api.storage.SignalGroupV2Record;
import org.whispersystems.signalservice.api.storage.StorageId;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.io.Closeable;
import java.io.IOException;
@@ -107,7 +107,7 @@ public class RecipientDatabase extends Database {
static final String TABLE_NAME = "recipient";
public static final String ID = "_id";
private static final String UUID = "uuid";
private static final String ACI_COLUMN = "uuid";
private static final String USERNAME = "username";
public static final String PHONE = "phone";
public static final String EMAIL = "email";
@@ -178,7 +178,7 @@ public class RecipientDatabase extends Database {
}
private static final String[] RECIPIENT_PROJECTION = new String[] {
ID, UUID, USERNAME, PHONE, EMAIL, GROUP_ID, GROUP_TYPE,
ID, ACI_COLUMN, USERNAME, PHONE, EMAIL, GROUP_ID, GROUP_TYPE,
BLOCKED, MESSAGE_RINGTONE, CALL_RINGTONE, MESSAGE_VIBRATE, CALL_VIBRATE, MUTE_UNTIL, AVATAR_COLOR, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, MESSAGE_EXPIRATION_TIME, REGISTERED,
PROFILE_KEY, PROFILE_KEY_CREDENTIAL,
SYSTEM_JOINED_NAME, SYSTEM_GIVEN_NAME, SYSTEM_FAMILY_NAME, SYSTEM_PHOTO_URI, SYSTEM_PHONE_LABEL, SYSTEM_PHONE_TYPE, SYSTEM_CONTACT_URI,
@@ -329,7 +329,7 @@ public class RecipientDatabase extends Database {
public static final String CREATE_TABLE =
"CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
UUID + " TEXT UNIQUE DEFAULT NULL, " +
ACI_COLUMN + " TEXT UNIQUE DEFAULT NULL, " +
USERNAME + " TEXT UNIQUE DEFAULT NULL, " +
PHONE + " TEXT UNIQUE DEFAULT NULL, " +
EMAIL + " TEXT UNIQUE DEFAULT NULL, " +
@@ -398,7 +398,7 @@ public class RecipientDatabase extends Database {
public @NonNull boolean containsPhoneOrUuid(@NonNull String id) {
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
String query = UUID + " = ? OR " + PHONE + " = ?";
String query = ACI_COLUMN + " = ? OR " + PHONE + " = ?";
String[] args = new String[]{id, id};
try (Cursor cursor = db.query(TABLE_NAME, new String[] { ID }, query, args, null, null, null)) {
@@ -421,8 +421,8 @@ public class RecipientDatabase extends Database {
}
public @NonNull
Optional<RecipientId> getByUuid(@NonNull UUID uuid) {
return getByColumn(UUID, uuid.toString());
Optional<RecipientId> getByAci(@NonNull ACI uuid) {
return getByColumn(ACI_COLUMN, uuid.toString());
}
public @NonNull
@@ -430,12 +430,12 @@ public class RecipientDatabase extends Database {
return getByColumn(USERNAME, username);
}
public @NonNull RecipientId getAndPossiblyMerge(@Nullable UUID uuid, @Nullable String e164, boolean highTrust) {
return getAndPossiblyMerge(uuid, e164, highTrust, false);
public @NonNull RecipientId getAndPossiblyMerge(@Nullable ACI aci, @Nullable String e164, boolean highTrust) {
return getAndPossiblyMerge(aci, e164, highTrust, false);
}
public @NonNull RecipientId getAndPossiblyMerge(@Nullable UUID uuid, @Nullable String e164, boolean highTrust, boolean changeSelf) {
if (uuid == null && e164 == null) {
public @NonNull RecipientId getAndPossiblyMerge(@Nullable ACI aci, @Nullable String e164, boolean highTrust, boolean changeSelf) {
if (aci == null && e164 == null) {
throw new IllegalArgumentException("Must provide a UUID or E164!");
}
@@ -449,115 +449,115 @@ public class RecipientDatabase extends Database {
try {
Optional<RecipientId> byE164 = e164 != null ? getByE164(e164) : Optional.absent();
Optional<RecipientId> byUuid = uuid != null ? getByUuid(uuid) : Optional.absent();
Optional<RecipientId> byAci = aci != null ? getByAci(aci) : Optional.absent();
RecipientId finalId;
if (!byE164.isPresent() && !byUuid.isPresent()) {
if (!byE164.isPresent() && !byAci.isPresent()) {
Log.i(TAG, "Discovered a completely new user. Inserting.", true);
if (highTrust) {
long id = db.insert(TABLE_NAME, null, buildContentValuesForNewUser(e164, uuid));
long id = db.insert(TABLE_NAME, null, buildContentValuesForNewUser(e164, aci));
finalId = RecipientId.from(id);
} else {
long id = db.insert(TABLE_NAME, null, buildContentValuesForNewUser(uuid == null ? e164 : null, uuid));
long id = db.insert(TABLE_NAME, null, buildContentValuesForNewUser(aci == null ? e164 : null, aci));
finalId = RecipientId.from(id);
}
} else if (byE164.isPresent() && !byUuid.isPresent()) {
if (uuid != null) {
} else if (byE164.isPresent() && !byAci.isPresent()) {
if (aci != null) {
RecipientSettings e164Settings = getRecipientSettings(byE164.get());
if (e164Settings.uuid != null) {
if (e164Settings.aci != null) {
if (highTrust) {
Log.w(TAG, String.format(Locale.US, "Found out about a UUID (%s) for a known E164 user (%s), but that user already has a UUID (%s). Likely a case of re-registration. High-trust, so stripping the E164 from the existing account and assigning it to a new entry.", uuid, byE164.get(), e164Settings.uuid), true);
Log.w(TAG, String.format(Locale.US, "Found out about an ACI (%s) for a known E164 user (%s), but that user already has an ACI (%s). Likely a case of re-registration. High-trust, so stripping the E164 from the existing account and assigning it to a new entry.", aci, byE164.get(), e164Settings.aci), true);
removePhoneNumber(byE164.get(), db);
recipientNeedingRefresh = byE164.get();
ContentValues insertValues = buildContentValuesForNewUser(e164, uuid);
ContentValues insertValues = buildContentValuesForNewUser(e164, aci);
insertValues.put(BLOCKED, e164Settings.blocked ? 1 : 0);
long id = db.insert(TABLE_NAME, null, insertValues);
finalId = RecipientId.from(id);
} else {
Log.w(TAG, String.format(Locale.US, "Found out about a UUID (%s) for a known E164 user (%s), but that user already has a UUID (%s). Likely a case of re-registration. Low-trust, so making a new user for the UUID.", uuid, byE164.get(), e164Settings.uuid), true);
Log.w(TAG, String.format(Locale.US, "Found out about an ACI (%s) for a known E164 user (%s), but that user already has an ACI (%s). Likely a case of re-registration. Low-trust, so making a new user for the UUID.", aci, byE164.get(), e164Settings.aci), true);
long id = db.insert(TABLE_NAME, null, buildContentValuesForNewUser(null, uuid));
long id = db.insert(TABLE_NAME, null, buildContentValuesForNewUser(null, aci));
finalId = RecipientId.from(id);
}
} else {
if (highTrust) {
Log.i(TAG, String.format(Locale.US, "Found out about a UUID (%s) for a known E164 user (%s). High-trust, so updating.", uuid, byE164.get()), true);
markRegisteredOrThrow(byE164.get(), uuid);
Log.i(TAG, String.format(Locale.US, "Found out about an ACI (%s) for a known E164 user (%s). High-trust, so updating.", aci, byE164.get()), true);
markRegisteredOrThrow(byE164.get(), aci);
finalId = byE164.get();
} else {
Log.i(TAG, String.format(Locale.US, "Found out about a UUID (%s) for a known E164 user (%s). Low-trust, so making a new user for the UUID.", uuid, byE164.get()), true);
long id = db.insert(TABLE_NAME, null, buildContentValuesForNewUser(null, uuid));
Log.i(TAG, String.format(Locale.US, "Found out about an ACI (%s) for a known E164 user (%s). Low-trust, so making a new user for the ACI.", aci, byE164.get()), true);
long id = db.insert(TABLE_NAME, null, buildContentValuesForNewUser(null, aci));
finalId = RecipientId.from(id);
}
}
} else {
finalId = byE164.get();
}
} else if (!byE164.isPresent() && byUuid.isPresent()) {
} else if (!byE164.isPresent() && byAci.isPresent()) {
if (e164 != null) {
if (highTrust) {
if (Objects.equals(uuid, TextSecurePreferences.getLocalUuid(context)) && !changeSelf) {
Log.w(TAG, String.format(Locale.US, "Found out about an E164 (%s) for our own UUID user (%s). High-trust but not change self, doing nothing.", e164, byUuid.get()), true);
finalId = byUuid.get();
if (Objects.equals(aci, TextSecurePreferences.getLocalAci(context)) && !changeSelf) {
Log.w(TAG, String.format(Locale.US, "Found out about an E164 (%s) for our own ACI user (%s). High-trust but not change self, doing nothing.", e164, byAci.get()), true);
finalId = byAci.get();
} else {
Log.i(TAG, String.format(Locale.US, "Found out about an E164 (%s) for a known UUID user (%s). High-trust, so updating.", e164, byUuid.get()), true);
Log.i(TAG, String.format(Locale.US, "Found out about an E164 (%s) for a known ACI user (%s). High-trust, so updating.", e164, byAci.get()), true);
RecipientSettings byUuidSettings = getRecipientSettings(byUuid.get());
RecipientSettings byUuidSettings = getRecipientSettings(byAci.get());
setPhoneNumberOrThrow(byUuid.get(), e164);
finalId = byUuid.get();
setPhoneNumberOrThrow(byAci.get(), e164);
finalId = byAci.get();
if (!Util.isEmpty(byUuidSettings.e164) && !byUuidSettings.e164.equals(e164)) {
recipientChangedNumber = finalId;
}
}
} else {
Log.i(TAG, String.format(Locale.US, "Found out about an E164 (%s) for a known UUID user (%s). Low-trust, so doing nothing.", e164, byUuid.get()), true);
finalId = byUuid.get();
Log.i(TAG, String.format(Locale.US, "Found out about an E164 (%s) for a known ACI user (%s). Low-trust, so doing nothing.", e164, byAci.get()), true);
finalId = byAci.get();
}
} else {
finalId = byUuid.get();
finalId = byAci.get();
}
} else {
if (byE164.equals(byUuid)) {
finalId = byUuid.get();
if (byE164.equals(byAci)) {
finalId = byAci.get();
} else {
Log.w(TAG, String.format(Locale.US, "Hit a conflict between %s (E164 of %s) and %s (UUID %s). They map to different recipients.", byE164.get(), e164, byUuid.get(), uuid), new Throwable(), true);
Log.w(TAG, String.format(Locale.US, "Hit a conflict between %s (E164 of %s) and %s (ACI %s). They map to different recipients.", byE164.get(), e164, byAci.get(), aci), new Throwable(), true);
RecipientSettings e164Settings = getRecipientSettings(byE164.get());
if (e164Settings.getUuid() != null) {
if (e164Settings.getAci() != null) {
if (highTrust) {
Log.w(TAG, "The E164 contact has a different UUID. Likely a case of re-registration. High-trust, so stripping the E164 from the existing account and assigning it to the UUID entry.", true);
Log.w(TAG, "The E164 contact has a different ACI. Likely a case of re-registration. High-trust, so stripping the E164 from the existing account and assigning it to the ACI entry.", true);
removePhoneNumber(byE164.get(), db);
recipientNeedingRefresh = byE164.get();
RecipientSettings byUuidSettings = getRecipientSettings(byUuid.get());
RecipientSettings byUuidSettings = getRecipientSettings(byAci.get());
setPhoneNumberOrThrow(byUuid.get(), Objects.requireNonNull(e164));
finalId = byUuid.get();
setPhoneNumberOrThrow(byAci.get(), Objects.requireNonNull(e164));
finalId = byAci.get();
if (!Util.isEmpty(byUuidSettings.e164) && !byUuidSettings.e164.equals(e164)) {
recipientChangedNumber = finalId;
}
} else {
Log.w(TAG, "The E164 contact has a different UUID. Likely a case of re-registration. Low-trust, so doing nothing.", true);
finalId = byUuid.get();
Log.w(TAG, "The E164 contact has a different ACI. Likely a case of re-registration. Low-trust, so doing nothing.", true);
finalId = byAci.get();
}
} else {
if (highTrust) {
Log.w(TAG, "We have one contact with just an E164, and another with UUID. High-trust, so merging the two rows together.", true);
finalId = merge(byUuid.get(), byE164.get());
recipientNeedingRefresh = byUuid.get();
remapped = new Pair<>(byE164.get(), byUuid.get());
Log.w(TAG, "We have one contact with just an E164, and another with just an ACI. High-trust, so merging the two rows together.", true);
finalId = merge(byAci.get(), byE164.get());
recipientNeedingRefresh = byAci.get();
remapped = new Pair<>(byE164.get(), byAci.get());
} else {
Log.w(TAG, "We have one contact with just an E164, and another with UUID. Low-trust, so doing nothing.", true);
finalId = byUuid.get();
Log.w(TAG, "We have one contact with just an E164, and another with just an ACI. Low-trust, so doing nothing.", true);
finalId = byAci.get();
}
}
}
@@ -592,13 +592,13 @@ public class RecipientDatabase extends Database {
}
}
private static ContentValues buildContentValuesForNewUser(@Nullable String e164, @Nullable UUID uuid) {
private static ContentValues buildContentValuesForNewUser(@Nullable String e164, @Nullable ACI aci) {
ContentValues values = new ContentValues();
values.put(PHONE, e164);
if (uuid != null) {
values.put(UUID, uuid.toString().toLowerCase());
if (aci != null) {
values.put(ACI_COLUMN, aci.toString().toLowerCase());
values.put(REGISTERED, RegisteredState.REGISTERED.getId());
values.put(STORAGE_SERVICE_ID, Base64.encodeBytes(StorageSyncHelper.generateKey()));
values.put(AVATAR_COLOR, AvatarColor.random().serialize());
@@ -608,8 +608,8 @@ public class RecipientDatabase extends Database {
}
public @NonNull RecipientId getOrInsertFromUuid(@NonNull UUID uuid) {
return getOrInsertByColumn(UUID, uuid.toString()).recipientId;
public @NonNull RecipientId getOrInsertFromAci(@NonNull ACI aci) {
return getOrInsertByColumn(ACI_COLUMN, aci.toString()).recipientId;
}
public @NonNull RecipientId getOrInsertFromE164(@NonNull String e164) {
@@ -829,13 +829,13 @@ public class RecipientDatabase extends Database {
if (id < 0) {
Log.w(TAG, "[applyStorageSyncContactInsert] Failed to insert. Possibly merging.");
recipientId = getAndPossiblyMerge(insert.getAddress().hasValidUuid() ? insert.getAddress().getUuid() : null, insert.getAddress().getNumber().get(), true);
recipientId = getAndPossiblyMerge(insert.getAddress().hasValidAci() ? insert.getAddress().getAci() : null, insert.getAddress().getNumber().get(), true);
db.update(TABLE_NAME, values, ID_WHERE, SqlUtil.buildArgs(recipientId));
} else {
recipientId = RecipientId.from(id);
}
if (insert.getIdentityKey().isPresent() && insert.getAddress().hasValidUuid()) {
if (insert.getIdentityKey().isPresent() && insert.getAddress().hasValidAci()) {
try {
IdentityKey identityKey = new IdentityKey(insert.getIdentityKey().get(), 0);
@@ -864,7 +864,7 @@ public class RecipientDatabase extends Database {
RecipientId recipientId = getByColumn(STORAGE_SERVICE_ID, Base64.encodeBytes(update.getOld().getId().getRaw())).get();
Log.w(TAG, "[applyStorageSyncContactUpdate] Found user " + recipientId + ". Possibly merging.");
recipientId = getAndPossiblyMerge(update.getNew().getAddress().hasValidUuid() ? update.getNew().getAddress().getUuid() : null, update.getNew().getAddress().getNumber().orNull(), true);
recipientId = getAndPossiblyMerge(update.getNew().getAddress().hasValidAci() ? update.getNew().getAddress().getAci() : null, update.getNew().getAddress().getNumber().orNull(), true);
Log.w(TAG, "[applyStorageSyncContactUpdate] Merged into " + recipientId);
db.update(TABLE_NAME, values, ID_WHERE, SqlUtil.buildArgs(recipientId));
@@ -881,7 +881,7 @@ public class RecipientDatabase extends Database {
try {
Optional<IdentityRecord> oldIdentityRecord = identityStore.getIdentityRecord(recipientId);
if (update.getNew().getIdentityKey().isPresent() && update.getNew().getAddress().hasValidUuid()) {
if (update.getNew().getIdentityKey().isPresent() && update.getNew().getAddress().hasValidAci()) {
IdentityKey identityKey = new IdentityKey(update.getNew().getIdentityKey().get(), 0);
DatabaseFactory.getIdentityDatabase(context).updateIdentityAfterSync(update.getNew().getAddress().getIdentifier(), recipientId, identityKey, StorageSyncModels.remoteToLocalIdentityStatus(update.getNew().getIdentityState()));
}
@@ -1059,8 +1059,8 @@ public class RecipientDatabase extends Database {
ProfileName profileName = ProfileName.fromParts(contact.getGivenName().orNull(), contact.getFamilyName().orNull());
String username = contact.getUsername().orNull();
if (contact.getAddress().hasValidUuid()) {
values.put(UUID, contact.getAddress().getUuid().toString());
if (contact.getAddress().hasValidAci()) {
values.put(ACI_COLUMN, contact.getAddress().getAci().toString());
}
values.put(PHONE, contact.getAddress().getNumber().orNull());
@@ -1133,9 +1133,9 @@ public class RecipientDatabase extends Database {
private List<RecipientSettings> getRecipientSettingsForSync(@Nullable String query, @Nullable String[] args) {
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
String table = TABLE_NAME + " LEFT OUTER JOIN " + IdentityDatabase.TABLE_NAME + " ON " + TABLE_NAME + "." + UUID + " = " + IdentityDatabase.TABLE_NAME + "." + IdentityDatabase.ADDRESS
+ " LEFT OUTER JOIN " + GroupDatabase.TABLE_NAME + " ON " + TABLE_NAME + "." + GROUP_ID + " = " + GroupDatabase.TABLE_NAME + "." + GroupDatabase.GROUP_ID
+ " LEFT OUTER JOIN " + ThreadDatabase.TABLE_NAME + " ON " + TABLE_NAME + "." + ID + " = " + ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.RECIPIENT_ID;
String table = TABLE_NAME + " LEFT OUTER JOIN " + IdentityDatabase.TABLE_NAME + " ON " + TABLE_NAME + "." + ACI_COLUMN + " = " + IdentityDatabase.TABLE_NAME + "." + IdentityDatabase.ADDRESS
+ " LEFT OUTER JOIN " + GroupDatabase.TABLE_NAME + " ON " + TABLE_NAME + "." + GROUP_ID + " = " + GroupDatabase.TABLE_NAME + "." + GroupDatabase.GROUP_ID
+ " LEFT OUTER JOIN " + ThreadDatabase.TABLE_NAME + " ON " + TABLE_NAME + "." + ID + " = " + ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.RECIPIENT_ID;
List<RecipientSettings> out = new ArrayList<>();
String[] columns = Stream.of(TYPED_RECIPIENT_PROJECTION,
@@ -1169,7 +1169,7 @@ public class RecipientDatabase extends Database {
*/
public @NonNull Map<RecipientId, StorageId> getContactStorageSyncIdsMap() {
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
String query = STORAGE_SERVICE_ID + " NOT NULL AND " + UUID + " NOT NULL AND " + ID + " != ? AND " + GROUP_TYPE + " != ?";
String query = STORAGE_SERVICE_ID + " NOT NULL AND " + ACI_COLUMN + " NOT NULL AND " + ID + " != ? AND " + GROUP_TYPE + " != ?";
String[] args = SqlUtil.buildArgs(Recipient.self().getId(), String.valueOf(GroupType.SIGNAL_V2.getId()));
Map<RecipientId, StorageId> out = new HashMap<>();
@@ -1215,7 +1215,7 @@ public class RecipientDatabase extends Database {
static @NonNull RecipientSettings getRecipientSettings(@NonNull Context context, @NonNull Cursor cursor, @NonNull String idColumnName) {
long id = CursorUtil.requireLong(cursor, idColumnName);
UUID uuid = UuidUtil.parseOrNull(CursorUtil.requireString(cursor, UUID));
ACI uuid = ACI.parseOrNull(CursorUtil.requireString(cursor, ACI_COLUMN));
String username = CursorUtil.requireString(cursor, USERNAME);
String e164 = CursorUtil.requireString(cursor, PHONE);
String email = CursorUtil.requireString(cursor, EMAIL);
@@ -1840,9 +1840,9 @@ public class RecipientDatabase extends Database {
* database if missing.
*/
public Set<RecipientId> persistProfileKeySet(@NonNull ProfileKeySet profileKeySet) {
Map<UUID, ProfileKey> profileKeys = profileKeySet.getProfileKeys();
Map<UUID, ProfileKey> authoritativeProfileKeys = profileKeySet.getAuthoritativeProfileKeys();
int totalKeys = profileKeys.size() + authoritativeProfileKeys.size();
Map<ACI, ProfileKey> profileKeys = profileKeySet.getProfileKeys();
Map<ACI, ProfileKey> authoritativeProfileKeys = profileKeySet.getAuthoritativeProfileKeys();
int totalKeys = profileKeys.size() + authoritativeProfileKeys.size();
if (totalKeys == 0) {
return Collections.emptySet();
@@ -1853,8 +1853,8 @@ public class RecipientDatabase extends Database {
HashSet<RecipientId> updated = new HashSet<>(totalKeys);
RecipientId selfId = Recipient.self().getId();
for (Map.Entry<UUID, ProfileKey> entry : profileKeys.entrySet()) {
RecipientId recipientId = getOrInsertFromUuid(entry.getKey());
for (Map.Entry<ACI, ProfileKey> entry : profileKeys.entrySet()) {
RecipientId recipientId = getOrInsertFromAci(entry.getKey());
if (setProfileKeyIfAbsent(recipientId, entry.getValue())) {
Log.i(TAG, "Learned new profile key");
@@ -1862,8 +1862,8 @@ public class RecipientDatabase extends Database {
}
}
for (Map.Entry<UUID, ProfileKey> entry : authoritativeProfileKeys.entrySet()) {
RecipientId recipientId = getOrInsertFromUuid(entry.getKey());
for (Map.Entry<ACI, ProfileKey> entry : authoritativeProfileKeys.entrySet()) {
RecipientId recipientId = getOrInsertFromAci(entry.getKey());
if (selfId.equals(recipientId)) {
Log.i(TAG, "Seen authoritative update for self");
@@ -2111,7 +2111,7 @@ public class RecipientDatabase extends Database {
Log.w(TAG, "[setPhoneNumber] Hit a conflict when trying to update " + id + ". Possibly merging.");
RecipientSettings existing = getRecipientSettings(id);
RecipientId newId = getAndPossiblyMerge(existing.getUuid(), e164, true);
RecipientId newId = getAndPossiblyMerge(existing.getAci(), e164, true);
Log.w(TAG, "[setPhoneNumber] Resulting id: " + newId);
db.setTransactionSuccessful();
@@ -2147,7 +2147,7 @@ public class RecipientDatabase extends Database {
try {
RecipientId id = Recipient.self().getId();
RecipientId newId = getAndPossiblyMerge(Recipient.self().requireUuid(), e164, true, true);
RecipientId newId = getAndPossiblyMerge(Recipient.self().requireAci(), e164, true, true);
if (id.equals(newId)) {
Log.i(TAG, "[updateSelfPhone] Phone updated for self");
@@ -2206,19 +2206,19 @@ public class RecipientDatabase extends Database {
/**
* @return True if setting the UUID resulted in changed recipientId, otherwise false.
*/
public boolean markRegistered(@NonNull RecipientId id, @NonNull UUID uuid) {
public boolean markRegistered(@NonNull RecipientId id, @NonNull ACI aci) {
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
db.beginTransaction();
try {
markRegisteredOrThrow(id, uuid);
markRegisteredOrThrow(id, aci);
db.setTransactionSuccessful();
return false;
} catch (SQLiteConstraintException e) {
Log.w(TAG, "[markRegistered] Hit a conflict when trying to update " + id + ". Possibly merging.");
RecipientSettings existing = getRecipientSettings(id);
RecipientId newId = getAndPossiblyMerge(uuid, existing.getE164(), true);
RecipientId newId = getAndPossiblyMerge(aci, existing.getE164(), true);
Log.w(TAG, "[markRegistered] Merged into " + newId);
db.setTransactionSuccessful();
@@ -2231,10 +2231,10 @@ public class RecipientDatabase extends Database {
/**
* Should only use if you are confident that this shouldn't result in any contact merging.
*/
public void markRegisteredOrThrow(@NonNull RecipientId id, @NonNull UUID uuid) {
public void markRegisteredOrThrow(@NonNull RecipientId id, @NonNull ACI aci) {
ContentValues contentValues = new ContentValues(2);
contentValues.put(REGISTERED, RegisteredState.REGISTERED.getId());
contentValues.put(UUID, uuid.toString().toLowerCase());
contentValues.put(ACI_COLUMN, aci.toString().toLowerCase());
if (update(id, contentValues)) {
setStorageIdIfNotSet(id);
@@ -2252,28 +2252,31 @@ public class RecipientDatabase extends Database {
}
}
public void bulkUpdatedRegisteredStatus(@NonNull Map<RecipientId, String> registered, Collection<RecipientId> unregistered) {
public void bulkUpdatedRegisteredStatus(@NonNull Map<RecipientId, ACI> registered, Collection<RecipientId> unregistered) {
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
db.beginTransaction();
try {
for (Map.Entry<RecipientId, String> entry : registered.entrySet()) {
for (Map.Entry<RecipientId, ACI> entry : registered.entrySet()) {
RecipientId recipientId = entry.getKey();
ACI aci = entry.getValue();
ContentValues values = new ContentValues(2);
values.put(REGISTERED, RegisteredState.REGISTERED.getId());
if (entry.getValue() != null) {
values.put(UUID, entry.getValue().toLowerCase());
if (aci != null) {
values.put(ACI_COLUMN, aci.toString().toLowerCase());
}
try {
if (update(entry.getKey(), values)) {
setStorageIdIfNotSet(entry.getKey());
if (update(recipientId, values)) {
setStorageIdIfNotSet(recipientId);
}
} catch (SQLiteConstraintException e) {
Log.w(TAG, "[bulkUpdateRegisteredStatus] Hit a conflict when trying to update " + entry.getKey() + ". Possibly merging.");
Log.w(TAG, "[bulkUpdateRegisteredStatus] Hit a conflict when trying to update " + recipientId + ". Possibly merging.");
RecipientSettings existing = getRecipientSettings(entry.getKey());
RecipientId newId = getAndPossiblyMerge(UuidUtil.parseOrThrow(entry.getValue()), existing.getE164(), true);
RecipientId newId = getAndPossiblyMerge(aci, existing.getE164(), true);
Log.w(TAG, "[bulkUpdateRegisteredStatus] Merged into " + newId);
}
}
@@ -2298,27 +2301,27 @@ public class RecipientDatabase extends Database {
*
* @return A mapping of (RecipientId, UUID)
*/
public @NonNull Map<RecipientId, String> bulkProcessCdsResult(@NonNull Map<String, UUID> mapping) {
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
HashMap<RecipientId, String> uuidMap = new HashMap<>();
public @NonNull Map<RecipientId, ACI> bulkProcessCdsResult(@NonNull Map<String, ACI> mapping) {
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
HashMap<RecipientId, ACI> aciMap = new HashMap<>();
db.beginTransaction();
try {
for (Map.Entry<String, UUID> entry : mapping.entrySet()) {
for (Map.Entry<String, ACI> entry : mapping.entrySet()) {
String e164 = entry.getKey();
UUID uuid = entry.getValue();
Optional<RecipientId> uuidEntry = uuid != null ? getByUuid(uuid) : Optional.absent();
ACI aci = entry.getValue();
Optional<RecipientId> aciEntry = aci != null ? getByAci(aci) : Optional.absent();
if (uuidEntry.isPresent()) {
boolean idChanged = setPhoneNumber(uuidEntry.get(), e164);
if (aciEntry.isPresent()) {
boolean idChanged = setPhoneNumber(aciEntry.get(), e164);
if (idChanged) {
uuidEntry = getByUuid(Objects.requireNonNull(uuid));
aciEntry = getByAci(Objects.requireNonNull(aci));
}
}
RecipientId id = uuidEntry.isPresent() ? uuidEntry.get() : getOrInsertFromE164(e164);
RecipientId id = aciEntry.isPresent() ? aciEntry.get() : getOrInsertFromE164(e164);
uuidMap.put(id, uuid != null ? uuid.toString() : null);
aciMap.put(id, aci);
}
db.setTransactionSuccessful();
@@ -2326,7 +2329,7 @@ public class RecipientDatabase extends Database {
db.endTransaction();
}
return uuidMap;
return aciMap;
}
public @NonNull List<RecipientId> getUninvitedRecipientsForInsights() {
@@ -2730,7 +2733,7 @@ public class RecipientDatabase extends Database {
.map(b -> b.getNumber().get())
.toList();
List<String> blockedUuid = Stream.of(blocked)
.map(b -> b.getUuid().toString().toLowerCase())
.map(b -> b.getAci().toString().toLowerCase())
.toList();
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
@@ -2750,7 +2753,7 @@ public class RecipientDatabase extends Database {
}
for (String uuid : blockedUuid) {
db.update(TABLE_NAME, setBlocked, UUID + " = ?", new String[] { uuid });
db.update(TABLE_NAME, setBlocked, ACI_COLUMN + " = ?", new String[] { uuid });
}
List<GroupId.V1> groupIdStrings = new ArrayList<>(groupIds.size());
@@ -3106,7 +3109,7 @@ public class RecipientDatabase extends Database {
SessionDatabase sessionDatabase = DatabaseFactory.getSessionDatabase(context);
boolean hasE164Session = sessionDatabase.getAllFor(e164Settings.e164).size() > 0;
boolean hasUuidSession = sessionDatabase.getAllFor(uuidSettings.uuid.toString()).size() > 0;
boolean hasUuidSession = sessionDatabase.getAllFor(uuidSettings.aci.toString()).size() > 0;
if (hasE164Session && hasUuidSession) {
Log.w(TAG, "Had a session for both users. Deleting the E164.", true);
@@ -3114,7 +3117,7 @@ public class RecipientDatabase extends Database {
} else if (hasE164Session && !hasUuidSession) {
Log.w(TAG, "Had a session for E164, but not UUID. Re-assigning to the UUID.", true);
ContentValues values = new ContentValues();
values.put(SessionDatabase.ADDRESS, uuidSettings.uuid.toString());
values.put(SessionDatabase.ADDRESS, uuidSettings.aci.toString());
db.update(SessionDatabase.TABLE_NAME, values, SessionDatabase.ADDRESS + " = ?", SqlUtil.buildArgs(e164Settings.e164));
} else if (!hasE164Session && hasUuidSession) {
Log.w(TAG, "Had a session for UUID, but not E164. No action necessary.", true);
@@ -3260,7 +3263,7 @@ public class RecipientDatabase extends Database {
public static class RecipientSettings {
private final RecipientId id;
private final UUID uuid;
private final ACI aci;
private final String username;
private final String e164;
private final String email;
@@ -3310,7 +3313,7 @@ public class RecipientDatabase extends Database {
private final List<Badge> badges;
RecipientSettings(@NonNull RecipientId id,
@Nullable UUID uuid,
@Nullable ACI uuid,
@Nullable String username,
@Nullable String e164,
@Nullable String email,
@@ -3355,7 +3358,7 @@ public class RecipientDatabase extends Database {
@NonNull List<Badge> badges)
{
this.id = id;
this.uuid = uuid;
this.aci = uuid;
this.username = username;
this.e164 = e164;
this.email = email;
@@ -3409,8 +3412,8 @@ public class RecipientDatabase extends Database {
return id;
}
public @Nullable UUID getUuid() {
return uuid;
public @Nullable ACI getAci() {
return aci;
}
public @Nullable String getUsername() {
@@ -143,8 +143,8 @@ public class SenderKeySharedDatabase extends Database {
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
Recipient recipient = Recipient.resolved(recipientId);
if (recipient.hasUuid()) {
db.delete(TABLE_NAME, ADDRESS + " = ?", SqlUtil.buildArgs(recipient.getUuid().get().toString()));
if (recipient.hasAci()) {
db.delete(TABLE_NAME, ADDRESS + " = ?", SqlUtil.buildArgs(recipient.requireAci().toString()));
} else {
Log.w(TAG, "Recipient doesn't have a UUID! " + recipientId);
}
@@ -723,11 +723,11 @@ public class SmsDatabase extends MessageDatabase {
if (!peerEraIdSameAsPrevious && !Util.isEmpty(peekGroupCallEraId)) {
Recipient self = Recipient.self();
boolean markRead = peekJoinedUuids.contains(self.requireUuid()) || self.getId().equals(sender);
boolean markRead = peekJoinedUuids.contains(self.requireAci().uuid()) || self.getId().equals(sender);
byte[] updateDetails = GroupCallUpdateDetails.newBuilder()
.setEraId(Util.emptyIfNull(peekGroupCallEraId))
.setStartedCallUuid(Recipient.resolved(sender).requireUuid().toString())
.setStartedCallUuid(Recipient.resolved(sender).requireAci().toString())
.setStartedCallTimestamp(timestamp)
.addAllInCallUuids(Stream.of(peekJoinedUuids).map(UUID::toString).toList())
.setIsCallFull(isCallFull)
@@ -804,7 +804,7 @@ public class SmsDatabase extends MessageDatabase {
if (!sameEraId && !Util.isEmpty(messageGroupCallEraId)) {
byte[] updateDetails = GroupCallUpdateDetails.newBuilder()
.setEraId(Util.emptyIfNull(messageGroupCallEraId))
.setStartedCallUuid(Recipient.resolved(sender).requireUuid().toString())
.setStartedCallUuid(Recipient.resolved(sender).requireAci().toString())
.setStartedCallTimestamp(timestamp)
.addAllInCallUuids(Collections.emptyList())
.setIsCallFull(false)
@@ -853,7 +853,7 @@ public class SmsDatabase extends MessageDatabase {
}
GroupCallUpdateDetails groupCallUpdateDetails = GroupCallUpdateDetailsUtil.parse(record.getBody());
boolean containsSelf = peekJoinedUuids.contains(Recipient.self().requireUuid());
boolean containsSelf = peekJoinedUuids.contains(Recipient.self().requireAci().uuid());
sameEraId = groupCallUpdateDetails.getEraId().equals(peekGroupCallEraId) && !Util.isEmpty(peekGroupCallEraId);
@@ -58,6 +58,7 @@ import org.thoughtcrime.securesms.util.SqlUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.storage.SignalAccountRecord;
import org.whispersystems.signalservice.api.storage.SignalContactRecord;
import org.whispersystems.signalservice.api.storage.SignalGroupV1Record;
@@ -1446,7 +1447,7 @@ public class ThreadDatabase extends Database {
if (threadRecipient.isPushV2Group()) {
MessageRecord.InviteAddState inviteAddState = record.getGv2AddInviteState();
if (inviteAddState != null) {
RecipientId from = RecipientId.from(inviteAddState.getAddedOrInvitedBy(), null);
RecipientId from = RecipientId.from(ACI.from(inviteAddState.getAddedOrInvitedBy()), null);
if (inviteAddState.isInvited()) {
Log.i(TAG, "GV2 invite message request from " + from);
return Extra.forGroupV2invite(from, individualRecipientId);
@@ -10,26 +10,25 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.api.push.ACI;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.UUID;
/**
* Create a group call update message based on time and joined members.
*/
public class GroupCallUpdateMessageFactory implements UpdateDescription.StringFactory {
private final Context context;
private final List<UUID> joinedMembers;
private final List<ACI> joinedMembers;
private final boolean withTime;
private final GroupCallUpdateDetails groupCallUpdateDetails;
private final UUID selfUuid;
private final ACI selfAci;
public GroupCallUpdateMessageFactory(@NonNull Context context,
@NonNull List<UUID> joinedMembers,
@NonNull List<ACI> joinedMembers,
boolean withTime,
@NonNull GroupCallUpdateDetails groupCallUpdateDetails)
{
@@ -37,11 +36,11 @@ public class GroupCallUpdateMessageFactory implements UpdateDescription.StringFa
this.joinedMembers = new ArrayList<>(joinedMembers);
this.withTime = withTime;
this.groupCallUpdateDetails = groupCallUpdateDetails;
this.selfUuid = TextSecurePreferences.getLocalUuid(context);
this.selfAci = TextSecurePreferences.getLocalAci(context);
boolean removed = this.joinedMembers.remove(selfUuid);
boolean removed = this.joinedMembers.remove(selfAci);
if (removed) {
this.joinedMembers.add(selfUuid);
this.joinedMembers.add(selfAci);
}
}
@@ -57,7 +56,7 @@ public class GroupCallUpdateMessageFactory implements UpdateDescription.StringFa
if (joinedMembers.get(0).toString().equals(groupCallUpdateDetails.getStartedCallUuid())) {
return withTime ? context.getString(R.string.MessageRecord_s_started_a_group_call_s, describe(joinedMembers.get(0)), time)
: context.getString(R.string.MessageRecord_s_started_a_group_call, describe(joinedMembers.get(0)));
} else if (Objects.equals(joinedMembers.get(0), selfUuid)) {
} else if (Objects.equals(joinedMembers.get(0), selfAci)) {
return withTime ? context.getString(R.string.MessageRecord_you_are_in_the_group_call_s1, time)
: context.getString(R.string.MessageRecord_you_are_in_the_group_call);
} else {
@@ -88,12 +87,12 @@ public class GroupCallUpdateMessageFactory implements UpdateDescription.StringFa
}
}
private @NonNull String describe(@NonNull UUID uuid) {
if (UuidUtil.UNKNOWN_UUID.equals(uuid)) {
private @NonNull String describe(@NonNull ACI aci) {
if (aci.isUnknown()) {
return context.getString(R.string.MessageRecord_unknown);
}
Recipient recipient = Recipient.resolved(RecipientId.from(uuid, null));
Recipient recipient = Recipient.resolved(RecipientId.from(aci, null));
if (recipient.isSelf()) {
return context.getString(R.string.MessageRecord_you);
@@ -26,6 +26,7 @@ import org.thoughtcrime.securesms.util.ExpirationUtil;
import org.thoughtcrime.securesms.util.StringUtil;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.util.Arrays;
@@ -744,11 +745,12 @@ final class GroupsV2UpdateMessageProducer {
interface DescribeMemberStrategy {
/**
* Map a UUID to a string that describes the group member.
* Map an ACI to a string that describes the group member.
* @param aci
*/
@NonNull
@WorkerThread
String describe(@NonNull UUID uuid);
String describe(@NonNull ACI aci);
}
private interface StringFactory1Arg {
@@ -769,9 +771,9 @@ final class GroupsV2UpdateMessageProducer {
@NonNull StringFactory1Arg stringFactory,
@DrawableRes int iconResource)
{
UUID uuid1 = UuidUtil.fromByteStringOrUnknown(uuid1Bytes);
ACI aci1 = ACI.fromByteStringOrUnknown(uuid1Bytes);
return UpdateDescription.mentioning(Collections.singletonList(uuid1), () -> stringFactory.create(descriptionStrategy.describe(uuid1)), iconResource);
return UpdateDescription.mentioning(Collections.singletonList(aci1), () -> stringFactory.create(descriptionStrategy.describe(aci1)), iconResource);
}
private UpdateDescription updateDescription(@NonNull ByteString uuid1Bytes,
@@ -779,9 +781,9 @@ final class GroupsV2UpdateMessageProducer {
@NonNull StringFactory2Args stringFactory,
@DrawableRes int iconResource)
{
UUID uuid1 = UuidUtil.fromByteStringOrUnknown(uuid1Bytes);
UUID uuid2 = UuidUtil.fromByteStringOrUnknown(uuid2Bytes);
ACI aci1 = ACI.fromByteStringOrUnknown(uuid1Bytes);
ACI aci2 = ACI.fromByteStringOrUnknown(uuid2Bytes);
return UpdateDescription.mentioning(Arrays.asList(uuid1, uuid2), () -> stringFactory.create(descriptionStrategy.describe(uuid1), descriptionStrategy.describe(uuid2)), iconResource);
return UpdateDescription.mentioning(Arrays.asList(aci1, aci2), () -> stringFactory.create(descriptionStrategy.describe(aci1), descriptionStrategy.describe(aci2)), iconResource);
}
}
@@ -54,6 +54,7 @@ import org.thoughtcrime.securesms.util.StringUtil;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.guava.Function;
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.io.IOException;
@@ -240,7 +241,7 @@ public abstract class MessageRecord extends DisplayRecord {
private static boolean selfCreatedGroup(@NonNull DecryptedGroupChange change) {
return change.getRevision() == 0 &&
change.getEditor().equals(UuidUtil.toByteString(Recipient.self().requireUuid()));
change.getEditor().equals(UuidUtil.toByteString(Recipient.self().requireAci().uuid()));
}
public static @NonNull UpdateDescription getGv2ChangeDescription(@NonNull Context context, @NonNull String body) {
@@ -248,7 +249,7 @@ public abstract class MessageRecord extends DisplayRecord {
ShortStringDescriptionStrategy descriptionStrategy = new ShortStringDescriptionStrategy(context);
byte[] decoded = Base64.decode(body);
DecryptedGroupV2Context decryptedGroupV2Context = DecryptedGroupV2Context.parseFrom(decoded);
GroupsV2UpdateMessageProducer updateMessageProducer = new GroupsV2UpdateMessageProducer(context, descriptionStrategy, Recipient.self().getUuid().get());
GroupsV2UpdateMessageProducer updateMessageProducer = new GroupsV2UpdateMessageProducer(context, descriptionStrategy, Recipient.self().requireAci().uuid());
if (decryptedGroupV2Context.hasChange() && (decryptedGroupV2Context.getGroupState().getRevision() != 0 || decryptedGroupV2Context.hasPreviousGroupState())) {
return UpdateDescription.concatWithNewLines(updateMessageProducer.describeChanges(decryptedGroupV2Context.getPreviousGroupState(), decryptedGroupV2Context.getChange()));
@@ -279,7 +280,7 @@ public abstract class MessageRecord extends DisplayRecord {
}
DecryptedGroup groupState = decryptedGroupV2Context.getGroupState();
boolean invited = DecryptedGroupUtil.findPendingByUuid(groupState.getPendingMembersList(), Recipient.self().requireUuid()).isPresent();
boolean invited = DecryptedGroupUtil.findPendingByUuid(groupState.getPendingMembersList(), Recipient.self().requireAci().uuid()).isPresent();
if (decryptedGroupV2Context.hasChange()) {
UUID changeEditor = UuidUtil.fromByteStringOrNull(decryptedGroupV2Context.getChange().getEditor());
@@ -301,7 +302,7 @@ public abstract class MessageRecord extends DisplayRecord {
@NonNull Function<Recipient, String> stringGenerator,
@DrawableRes int iconResource)
{
return UpdateDescription.mentioning(Collections.singletonList(recipient.getUuid().or(UuidUtil.UNKNOWN_UUID)),
return UpdateDescription.mentioning(Collections.singletonList(recipient.getAci().or(ACI.UNKNOWN)),
() -> stringGenerator.apply(recipient.resolve()),
iconResource);
}
@@ -369,10 +370,11 @@ public abstract class MessageRecord extends DisplayRecord {
public static @NonNull UpdateDescription getGroupCallUpdateDescription(@NonNull Context context, @NonNull String body, boolean withTime) {
GroupCallUpdateDetails groupCallUpdateDetails = GroupCallUpdateDetailsUtil.parse(body);
List<UUID> joinedMembers = Stream.of(groupCallUpdateDetails.getInCallUuidsList())
.map(UuidUtil::parseOrNull)
.withoutNulls()
.toList();
List<ACI> joinedMembers = Stream.of(groupCallUpdateDetails.getInCallUuidsList())
.map(UuidUtil::parseOrNull)
.withoutNulls()
.map(ACI::from)
.toList();
UpdateDescription.StringFactory stringFactory = new GroupCallUpdateMessageFactory(context, joinedMembers, withTime, groupCallUpdateDetails);
@@ -407,11 +409,11 @@ public abstract class MessageRecord extends DisplayRecord {
}
@Override
public @NonNull String describe(@NonNull UUID uuid) {
if (UuidUtil.UNKNOWN_UUID.equals(uuid)) {
public @NonNull String describe(@NonNull ACI aci) {
if (aci.isUnknown()) {
return context.getString(R.string.MessageRecord_unknown);
}
return Recipient.resolved(RecipientId.from(uuid, null)).getDisplayName(context);
return Recipient.resolved(RecipientId.from(aci, null)).getDisplayName(context);
}
}
@@ -8,6 +8,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import org.signal.core.util.ThreadUtil;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.util.Collection;
@@ -27,14 +28,14 @@ public final class UpdateDescription {
String create();
}
private final Collection<UUID> mentioned;
private final StringFactory stringFactory;
private final String staticString;
private final int lightIconResource;
private final int lightTint;
private final int darkTint;
private final Collection<ACI> mentioned;
private final StringFactory stringFactory;
private final String staticString;
private final int lightIconResource;
private final int lightTint;
private final int darkTint;
private UpdateDescription(@NonNull Collection<UUID> mentioned,
private UpdateDescription(@NonNull Collection<ACI> mentioned,
@Nullable StringFactory stringFactory,
@Nullable String staticString,
@DrawableRes int iconResource,
@@ -59,11 +60,11 @@ public final class UpdateDescription {
* @param mentioned UUIDs of recipients that are mentioned in the string.
* @param stringFactory The background method for generating the string.
*/
public static UpdateDescription mentioning(@NonNull Collection<UUID> mentioned,
public static UpdateDescription mentioning(@NonNull Collection<ACI> mentioned,
@NonNull StringFactory stringFactory,
@DrawableRes int iconResource)
{
return new UpdateDescription(UuidUtil.filterKnown(mentioned),
return new UpdateDescription(ACI.filterKnown(mentioned),
stringFactory,
null,
iconResource,
@@ -117,7 +118,7 @@ public final class UpdateDescription {
}
@AnyThread
public Collection<UUID> getMentioned() {
public Collection<ACI> getMentioned() {
return mentioned;
}
@@ -148,7 +149,7 @@ public final class UpdateDescription {
);
}
Set<UUID> allMentioned = new HashSet<>();
Set<ACI> allMentioned = new HashSet<>();
for (UpdateDescription updateDescription : updateDescriptions) {
allMentioned.addAll(updateDescription.getMentioned());
@@ -72,6 +72,7 @@ import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.SignalWebSocket;
import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.services.DonationsService;
import org.whispersystems.signalservice.api.util.CredentialsProvider;
import org.whispersystems.signalservice.api.util.SleepTimer;
@@ -79,7 +80,6 @@ import org.whispersystems.signalservice.api.util.UptimeSleepTimer;
import org.whispersystems.signalservice.api.websocket.WebSocketFactory;
import org.whispersystems.signalservice.internal.websocket.WebSocketConnection;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
@@ -359,8 +359,8 @@ public class ApplicationDependencyProvider implements ApplicationDependencies.Pr
}
@Override
public UUID getUuid() {
return TextSecurePreferences.getLocalUuid(context);
public ACI getAci() {
return TextSecurePreferences.getLocalAci(context);
}
@Override
@@ -60,6 +60,7 @@ import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
import org.whispersystems.signalservice.api.groupsv2.InvalidGroupStateException;
import org.whispersystems.signalservice.api.groupsv2.NotAbleToApplyGroupV2ChangeException;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
import org.whispersystems.signalservice.api.push.exceptions.ConflictException;
import org.whispersystems.signalservice.api.util.UuidUtil;
@@ -92,7 +93,7 @@ final class GroupManagerV2 {
private final GroupsV2Operations groupsV2Operations;
private final GroupsV2Authorization authorization;
private final GroupsV2StateProcessor groupsV2StateProcessor;
private final UUID selfUuid;
private final ACI selfAci;
private final GroupCandidateHelper groupCandidateHelper;
GroupManagerV2(@NonNull Context context) {
@@ -102,7 +103,7 @@ final class GroupManagerV2 {
this.groupsV2Operations = ApplicationDependencies.getGroupsV2Operations();
this.authorization = ApplicationDependencies.getGroupsV2Authorization();
this.groupsV2StateProcessor = ApplicationDependencies.getGroupsV2StateProcessor();
this.selfUuid = Recipient.self().getUuid().get();
this.selfAci = Recipient.self().requireAci();
this.groupCandidateHelper = new GroupCandidateHelper(context);
}
@@ -113,7 +114,7 @@ final class GroupManagerV2 {
return groupsV2Api.getGroupJoinInfo(groupSecretParams,
Optional.fromNullable(password).transform(GroupLinkPassword::serialize),
authorization.getAuthorizationForToday(Recipient.self().requireUuid(), groupSecretParams));
authorization.getAuthorizationForToday(selfAci, groupSecretParams));
}
@WorkerThread
@@ -127,7 +128,7 @@ final class GroupManagerV2 {
GroupSecretParams groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupMasterKey);
return groupsV2Api.getGroupExternalCredential(authorization.getAuthorizationForToday(Recipient.self().requireUuid(), groupSecretParams));
return groupsV2Api.getGroupExternalCredential(authorization.getAuthorizationForToday(selfAci, groupSecretParams));
}
@WorkerThread
@@ -140,7 +141,7 @@ final class GroupManagerV2 {
Map<UUID, UuidCiphertext> uuidCipherTexts = new HashMap<>();
for (Recipient recipient : recipients) {
uuidCipherTexts.put(recipient.requireUuid(), clientZkGroupCipher.encryptUuid(recipient.requireUuid()));
uuidCipherTexts.put(recipient.requireAci().uuid(), clientZkGroupCipher.encryptUuid(recipient.requireAci().uuid()));
}
return uuidCipherTexts;
@@ -195,7 +196,7 @@ final class GroupManagerV2 {
return latest;
}
Optional<DecryptedMember> selfInFullMemberList = DecryptedGroupUtil.findMemberByUuid(latest.getMembersList(), Recipient.self().requireUuid());
Optional<DecryptedMember> selfInFullMemberList = DecryptedGroupUtil.findMemberByUuid(latest.getMembersList(), selfAci.uuid());
if (!selfInFullMemberList.isPresent()) {
return latest;
@@ -267,7 +268,7 @@ final class GroupManagerV2 {
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(groupRecipient.getId(), true);
DecryptedGroupChange groupChange = DecryptedGroupChange.newBuilder(GroupChangeReconstruct.reconstructGroupChange(DecryptedGroup.newBuilder().build(), decryptedGroup))
.setEditor(UuidUtil.toByteString(selfUuid))
.setEditor(selfAci.toByteString())
.build();
RecipientAndThread recipientAndThread = sendGroupUpdate(masterKey, new GroupMutation(null, groupChange, decryptedGroup), null);
@@ -312,7 +313,7 @@ final class GroupManagerV2 {
groupCandidates = GroupCandidate.withoutProfileKeyCredentials(groupCandidates);
}
return commitChangeWithConflictResolution(groupOperations.createModifyGroupMembershipChange(groupCandidates, selfUuid));
return commitChangeWithConflictResolution(groupOperations.createModifyGroupMembershipChange(groupCandidates, selfAci.uuid()));
}
@WorkerThread
@@ -356,7 +357,7 @@ final class GroupManagerV2 {
}
if (avatarChanged) {
String cdnKey = avatarBytes != null ? groupsV2Api.uploadAvatar(avatarBytes, groupSecretParams, authorization.getAuthorizationForToday(selfUuid, groupSecretParams))
String cdnKey = avatarBytes != null ? groupsV2Api.uploadAvatar(avatarBytes, groupSecretParams, authorization.getAuthorizationForToday(selfAci, groupSecretParams))
: "";
change.setModifyAvatar(GroupChange.Actions.ModifyAvatarAction.newBuilder()
.setAvatar(cdnKey));
@@ -387,7 +388,7 @@ final class GroupManagerV2 {
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
{
Set<UUID> uuids = Stream.of(recipientIds)
.map(r -> Recipient.resolved(r).getUuid().get())
.map(r -> Recipient.resolved(r).requireAci().uuid())
.collect(Collectors.toSet());
return commitChangeWithConflictResolution(groupOperations.createApproveGroupJoinRequest(uuids));
@@ -398,7 +399,7 @@ final class GroupManagerV2 {
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
{
Set<UUID> uuids = Stream.of(recipientIds)
.map(r -> Recipient.resolved(r).getUuid().get())
.map(r -> Recipient.resolved(r).requireAci().uuid())
.collect(Collectors.toSet());
return commitChangeWithConflictResolution(groupOperations.createRefuseGroupJoinRequest(uuids));
@@ -410,7 +411,7 @@ final class GroupManagerV2 {
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
{
Recipient recipient = Recipient.resolved(recipientId);
return commitChangeWithConflictResolution(groupOperations.createChangeMemberRole(recipient.getUuid().get(), admin ? Member.Role.ADMINISTRATOR : Member.Role.DEFAULT));
return commitChangeWithConflictResolution(groupOperations.createChangeMemberRole(recipient.requireAci().uuid(), admin ? Member.Role.ADMINISTRATOR : Member.Role.DEFAULT));
}
@WorkerThread
@@ -420,7 +421,7 @@ final class GroupManagerV2 {
Recipient self = Recipient.self();
GroupDatabase.GroupRecord groupRecord = groupDatabase.getGroup(groupId).get();
List<DecryptedPendingMember> pendingMembersList = groupRecord.requireV2GroupProperties().getDecryptedGroup().getPendingMembersList();
Optional<DecryptedPendingMember> selfPendingMember = DecryptedGroupUtil.findPendingByUuid(pendingMembersList, selfUuid);
Optional<DecryptedPendingMember> selfPendingMember = DecryptedGroupUtil.findPendingByUuid(pendingMembersList, selfAci.uuid());
if (selfPendingMember.isPresent()) {
try {
@@ -439,7 +440,7 @@ final class GroupManagerV2 {
{
Recipient recipient = Recipient.resolved(recipientId);
return commitChangeWithConflictResolution(groupOperations.createRemoveMembersChange(Collections.singleton(recipient.getUuid().get())));
return commitChangeWithConflictResolution(groupOperations.createRemoveMembersChange(Collections.singleton(recipient.requireAci().uuid())));
}
@WorkerThread
@@ -447,9 +448,9 @@ final class GroupManagerV2 {
throws GroupChangeFailedException, GroupNotAMemberException, GroupInsufficientRightsException, IOException
{
Recipient self = Recipient.self();
List<UUID> newAdminRecipients = Stream.of(newAdmins).map(id -> Recipient.resolved(id).getUuid().get()).toList();
List<UUID> newAdminRecipients = Stream.of(newAdmins).map(id -> Recipient.resolved(id).requireAci().uuid()).toList();
return commitChangeWithConflictResolution(groupOperations.createLeaveAndPromoteMembersToAdmin(self.getUuid().get(),
return commitChangeWithConflictResolution(groupOperations.createLeaveAndPromoteMembersToAdmin(selfAci.uuid(),
newAdminRecipients));
}
@@ -459,7 +460,7 @@ final class GroupManagerV2 {
{
ProfileKey profileKey = ProfileKeyUtil.getSelfProfileKey();
DecryptedGroup group = groupDatabase.requireGroup(groupId).requireV2GroupProperties().getDecryptedGroup();
Optional<DecryptedMember> selfInGroup = DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), selfUuid);
Optional<DecryptedMember> selfInGroup = DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), selfAci.uuid());
if (!selfInGroup.isPresent()) {
Log.w(TAG, "Self not in group " + groupId);
@@ -489,7 +490,7 @@ final class GroupManagerV2 {
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
{
DecryptedGroup group = groupDatabase.requireGroup(groupId).requireV2GroupProperties().getDecryptedGroup();
Optional<DecryptedMember> selfInGroup = DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), Recipient.self().getUuid().get());
Optional<DecryptedMember> selfInGroup = DecryptedGroupUtil.findMemberByUuid(group.getMembersList(), selfAci.uuid());
if (selfInGroup.isPresent()) {
Log.w(TAG, "Self already in group");
@@ -553,7 +554,7 @@ final class GroupManagerV2 {
private @NonNull GroupManager.GroupActionResult commitChangeWithConflictResolution(@NonNull GroupChange.Actions.Builder change)
throws GroupChangeFailedException, GroupNotAMemberException, GroupInsufficientRightsException, IOException
{
change.setSourceUuid(UuidUtil.toByteString(Recipient.self().getUuid().get()));
change.setSourceUuid(UuidUtil.toByteString(selfAci.uuid()));
for (int attempt = 0; attempt < 5; attempt++) {
try {
@@ -602,7 +603,7 @@ final class GroupManagerV2 {
GroupChange.Actions changeActions = change.build();
return GroupChangeUtil.resolveConflict(groupUpdateResult.getLatestServer(),
groupOperations.decryptChange(changeActions, selfUuid),
groupOperations.decryptChange(changeActions, selfAci.uuid()),
changeActions);
} catch (VerificationFailedException | InvalidGroupStateException ex) {
throw new GroupChangeFailedException(ex);
@@ -622,7 +623,7 @@ final class GroupManagerV2 {
try {
previousGroupState = v2GroupProperties.getDecryptedGroup();
decryptedChange = groupOperations.decryptChange(changeActions, selfUuid);
decryptedChange = groupOperations.decryptChange(changeActions, selfAci.uuid());
decryptedGroupState = DecryptedGroupUtil.apply(previousGroupState, decryptedChange);
} catch (VerificationFailedException | InvalidGroupStateException | NotAbleToApplyGroupV2ChangeException e) {
Log.w(TAG, e);
@@ -644,7 +645,7 @@ final class GroupManagerV2 {
throws GroupNotAMemberException, GroupChangeFailedException, IOException, GroupInsufficientRightsException
{
try {
return groupsV2Api.patchGroup(change, authorization.getAuthorizationForToday(selfUuid, groupSecretParams), Optional.absent());
return groupsV2Api.patchGroup(change, authorization.getAuthorizationForToday(selfAci, groupSecretParams), Optional.absent());
} catch (NotInGroupException e) {
Log.w(TAG, e);
throw new GroupNotAMemberException(e);
@@ -727,9 +728,9 @@ final class GroupManagerV2 {
disappearingMessageTimerSeconds);
try {
groupsV2Api.putNewGroup(newGroup, authorization.getAuthorizationForToday(Recipient.self().requireUuid(), groupSecretParams));
groupsV2Api.putNewGroup(newGroup, authorization.getAuthorizationForToday(selfAci, groupSecretParams));
DecryptedGroup decryptedGroup = groupsV2Api.getGroup(groupSecretParams, ApplicationDependencies.getGroupsV2Authorization().getAuthorizationForToday(Recipient.self().requireUuid(), groupSecretParams));
DecryptedGroup decryptedGroup = groupsV2Api.getGroup(groupSecretParams, ApplicationDependencies.getGroupsV2Authorization().getAuthorizationForToday(selfAci, groupSecretParams));
if (decryptedGroup == null) {
throw new GroupChangeFailedException();
}
@@ -922,7 +923,7 @@ final class GroupManagerV2 {
.setRevision(GroupsV2StateProcessor.PLACEHOLDER_REVISION);
Recipient self = Recipient.self();
ByteString selfUuid = UuidUtil.toByteString(self.requireUuid());
ByteString selfUuid = selfAci.toByteString();
ByteString profileKey = ByteString.copyFrom(Objects.requireNonNull(self.getProfileKey()));
if (requestToJoin) {
@@ -956,7 +957,7 @@ final class GroupManagerV2 {
GroupChange.Actions.Builder change = requestToJoin ? groupOperations.createGroupJoinRequest(profileKeyCredential)
: groupOperations.createGroupJoinDirect(profileKeyCredential);
change.setSourceUuid(UuidUtil.toByteString(Recipient.self().getUuid().get()));
change.setSourceUuid(selfAci.toByteString());
return commitJoinChangeWithConflictResolution(currentRevision, change);
}
@@ -1000,7 +1001,7 @@ final class GroupManagerV2 {
throws GroupChangeFailedException, IOException, GroupLinkNotActiveException
{
try {
return groupsV2Api.patchGroup(change, authorization.getAuthorizationForToday(selfUuid, groupSecretParams), Optional.fromNullable(password).transform(GroupLinkPassword::serialize));
return groupsV2Api.patchGroup(change, authorization.getAuthorizationForToday(selfAci, groupSecretParams), Optional.fromNullable(password).transform(GroupLinkPassword::serialize));
} catch (NotInGroupException | VerificationFailedException e) {
Log.w(TAG, e);
throw new GroupChangeFailedException(e);
@@ -1044,7 +1045,7 @@ final class GroupManagerV2 {
throws IOException, VerificationFailedException, InvalidGroupStateException
{
try {
groupsV2Api.getGroup(groupSecretParams, authorization.getAuthorizationForToday(Recipient.self().requireUuid(), groupSecretParams));
groupsV2Api.getGroup(groupSecretParams, authorization.getAuthorizationForToday(selfAci, groupSecretParams));
return true;
} catch (NotInGroupException ex) {
return false;
@@ -1055,7 +1056,7 @@ final class GroupManagerV2 {
void cancelJoinRequest()
throws GroupChangeFailedException, IOException
{
Set<UUID> uuids = Collections.singleton(Recipient.self().getUuid().get());
Set<UUID> uuids = Collections.singleton(selfAci.uuid());
GroupChange signedGroupChange;
try {
@@ -1158,7 +1159,7 @@ final class GroupManagerV2 {
private static @NonNull List<RecipientId> getPendingMemberRecipientIds(@NonNull List<DecryptedPendingMember> newPendingMembersList) {
return Stream.of(DecryptedGroupUtil.pendingToUuidList(newPendingMembersList))
.map(uuid-> RecipientId.from(uuid,null))
.map(uuid -> RecipientId.from(ACI.from(uuid), null))
.toList();
}
@@ -19,6 +19,7 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
@@ -85,27 +86,26 @@ public final class GroupProtoUtil {
@WorkerThread
public static Recipient uuidByteStringToRecipient(@NonNull Context context, @NonNull ByteString uuidByteString) {
UUID uuid = UUIDUtil.deserialize(uuidByteString.toByteArray());
ACI aci = ACI.fromByteString(uuidByteString);
if (uuid.equals(GroupsV2Operations.UNKNOWN_UUID)) {
if (aci.isUnknown()) {
return Recipient.UNKNOWN;
}
return Recipient.externalPush(context, uuid, null, false);
return Recipient.externalPush(context, aci, null, false);
}
@WorkerThread
public static @NonNull RecipientId uuidByteStringToRecipientId(@NonNull ByteString uuidByteString) {
UUID uuid = UUIDUtil.deserialize(uuidByteString.toByteArray());
ACI aci = ACI.fromByteString(uuidByteString);
if (uuid.equals(GroupsV2Operations.UNKNOWN_UUID)) {
if (aci.isUnknown()) {
return RecipientId.UNKNOWN;
}
return RecipientId.from(uuid, null);
return RecipientId.from(aci, null);
}
public static boolean isMember(@NonNull UUID uuid, @NonNull List<DecryptedMember> membersList) {
ByteString uuidBytes = UuidUtil.toByteString(uuid);
@@ -232,10 +232,10 @@ public final class GroupsV1MigrationUtil {
* True if the user meets all the requirements to be auto-migrated, otherwise false.
*/
public static boolean isAutoMigratable(@NonNull Recipient recipient) {
return recipient.hasUuid() &&
recipient.getGroupsV2Capability() == Recipient.Capability.SUPPORTED &&
return recipient.hasAci() &&
recipient.getGroupsV2Capability() == Recipient.Capability.SUPPORTED &&
recipient.getGroupsV1MigrationCapability() == Recipient.Capability.SUPPORTED &&
recipient.getRegistered() == RecipientDatabase.RegisteredState.REGISTERED &&
recipient.getRegistered() == RecipientDatabase.RegisteredState.REGISTERED &&
recipient.getProfileKey() != null;
}
@@ -9,6 +9,7 @@ import org.signal.zkgroup.groups.GroupSecretParams;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2AuthorizationString;
import org.whispersystems.signalservice.api.groupsv2.NoCredentialForRedemptionTimeException;
import org.whispersystems.signalservice.api.push.ACI;
import java.io.IOException;
import java.util.Map;
@@ -27,7 +28,7 @@ public final class GroupsV2Authorization {
this.cache = cache;
}
public GroupsV2AuthorizationString getAuthorizationForToday(@NonNull UUID self,
public GroupsV2AuthorizationString getAuthorizationForToday(@NonNull ACI self,
@NonNull GroupSecretParams groupSecretParams)
throws IOException, VerificationFailedException
{
@@ -65,7 +66,7 @@ public final class GroupsV2Authorization {
return (int) TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis());
}
private GroupsV2AuthorizationString getAuthorization(UUID self,
private GroupsV2AuthorizationString getAuthorization(ACI self,
GroupSecretParams groupSecretParams,
Map<Integer, AuthCredentialResponse> credentials,
int today)
@@ -86,7 +86,7 @@ public final class GroupsV2CapabilityChecker {
}
}
if (!member.hasUuid()) {
if (!member.hasAci()) {
noUuidCount++;
}
}
@@ -27,6 +27,7 @@ import org.thoughtcrime.securesms.recipients.LiveRecipient;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.util.Collections;
@@ -108,7 +109,7 @@ public final class LiveGroup {
return Stream.of(requestingMembersList)
.map(requestingMember -> {
Recipient recipient = Recipient.externalPush(ApplicationDependencies.getApplication(), UuidUtil.fromByteString(requestingMember.getUuid()), null, false);
Recipient recipient = Recipient.externalPush(ApplicationDependencies.getApplication(), ACI.fromByteString(requestingMember.getUuid()), null, false);
return new GroupMemberEntry.RequestingMember(recipient, selfAdmin);
})
.toList();
@@ -55,7 +55,7 @@ final class PendingMemberInvitesRepository {
List<DecryptedPendingMember> pendingMembersList = decryptedGroup.getPendingMembersList();
List<SinglePendingMemberInvitedByYou> byMe = new ArrayList<>(pendingMembersList.size());
List<MultiplePendingMembersInvitedByAnother> byOthers = new ArrayList<>(pendingMembersList.size());
ByteString self = ByteString.copyFrom(UUIDUtil.serialize(Recipient.self().getUuid().get()));
ByteString self = Recipient.self().requireAci().toByteString();
boolean selfIsAdmin = v2GroupProperties.isAdmin(Recipient.self());
Stream.of(pendingMembersList)
@@ -20,7 +20,6 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.transport.RetryLaterException;
import org.thoughtcrime.securesms.util.Util;
import java.io.IOException;
import java.util.Collections;
@@ -96,8 +95,8 @@ final class GroupsV1MigrationRepository {
group = group.fresh();
List<Recipient> ineligible = Stream.of(group.getParticipants())
.filter(r -> !r.hasUuid() ||
r.getGroupsV2Capability() != Recipient.Capability.SUPPORTED ||
.filter(r -> !r.hasAci() ||
r.getGroupsV2Capability() != Recipient.Capability.SUPPORTED ||
r.getGroupsV1MigrationCapability() != Recipient.Capability.SUPPORTED ||
r.getRegistered() != RecipientDatabase.RegisteredState.REGISTERED)
.toList();
@@ -17,6 +17,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.groupsv2.GroupCandidate;
import org.whispersystems.signalservice.api.push.ACI;
import java.io.IOException;
import java.util.Collection;
@@ -47,13 +48,13 @@ public final class GroupCandidateHelper {
{
final Recipient recipient = Recipient.resolved(recipientId);
UUID uuid = recipient.getUuid().orNull();
if (uuid == null) {
ACI aci = recipient.getAci().orNull();
if (aci == null) {
throw new AssertionError("Non UUID members should have need detected by now");
}
Optional<ProfileKeyCredential> profileKeyCredential = Optional.fromNullable(recipient.getProfileKeyCredential());
GroupCandidate candidate = new GroupCandidate(uuid, profileKeyCredential);
GroupCandidate candidate = new GroupCandidate(aci.uuid(), profileKeyCredential);
if (!candidate.hasProfileKeyCredential()) {
ProfileKey profileKey = ProfileKeyUtil.profileKeyOrNull(recipient.getProfileKey());
@@ -61,7 +62,7 @@ public final class GroupCandidateHelper {
if (profileKey != null) {
Log.i(TAG, String.format("No profile key credential on recipient %s, fetching", recipient.getId()));
Optional<ProfileKeyCredential> profileKeyCredentialOptional = signalServiceAccountManager.resolveProfileKeyCredential(uuid, profileKey, Locale.getDefault());
Optional<ProfileKeyCredential> profileKeyCredentialOptional = signalServiceAccountManager.resolveProfileKeyCredential(aci, profileKey, Locale.getDefault());
if (profileKeyCredentialOptional.isPresent()) {
boolean updatedProfileKey = recipientDatabase.setProfileKeyCredential(recipient.getId(), profileKey, profileKeyCredentialOptional.get());
@@ -12,6 +12,7 @@ import org.signal.storageservice.protos.groups.local.DecryptedMember;
import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember;
import org.signal.zkgroup.InvalidInputException;
import org.signal.zkgroup.profiles.ProfileKey;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.util.LinkedHashMap;
@@ -30,8 +31,8 @@ public final class ProfileKeySet {
private static final String TAG = Log.tag(ProfileKeySet.class);
private final Map<UUID, ProfileKey> profileKeys = new LinkedHashMap<>();
private final Map<UUID, ProfileKey> authoritativeProfileKeys = new LinkedHashMap<>();
private final Map<ACI, ProfileKey> profileKeys = new LinkedHashMap<>();
private final Map<ACI, ProfileKey> authoritativeProfileKeys = new LinkedHashMap<>();
/**
* Add new profile keys from a group change.
@@ -96,20 +97,20 @@ public final class ProfileKeySet {
}
if (memberUuid.equals(changeSource)) {
authoritativeProfileKeys.put(memberUuid, profileKey);
profileKeys.remove(memberUuid);
authoritativeProfileKeys.put(ACI.from(memberUuid), profileKey);
profileKeys.remove(ACI.from(memberUuid));
} else {
if (!authoritativeProfileKeys.containsKey(memberUuid)) {
profileKeys.put(memberUuid, profileKey);
if (!authoritativeProfileKeys.containsKey(ACI.from(memberUuid))) {
profileKeys.put(ACI.from(memberUuid), profileKey);
}
}
}
public Map<UUID, ProfileKey> getProfileKeys() {
public Map<ACI, ProfileKey> getProfileKeys() {
return profileKeys;
}
public Map<UUID, ProfileKey> getAuthoritativeProfileKeys() {
public Map<ACI, ProfileKey> getAuthoritativeProfileKeys() {
return authoritativeProfileKeys;
}
}
@@ -49,6 +49,7 @@ import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api;
import org.whispersystems.signalservice.api.groupsv2.InvalidGroupStateException;
import org.whispersystems.signalservice.api.groupsv2.NotAbleToApplyGroupV2ChangeException;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.push.exceptions.GroupNotFoundException;
import org.whispersystems.signalservice.internal.push.exceptions.NotInGroupException;
@@ -206,7 +207,7 @@ public final class GroupsV2StateProcessor {
}
if (inputGroupState == null) {
if (localState != null && DecryptedGroupUtil.isPendingOrRequesting(localState, Recipient.self().getUuid().get())) {
if (localState != null && DecryptedGroupUtil.isPendingOrRequesting(localState, Recipient.self().requireAci().uuid())) {
Log.w(TAG, "Unable to query server for group " + groupId + " server says we're not in group, but we think we are a pending or requesting member");
} else {
Log.w(TAG, "Unable to query server for group " + groupId + " server says we're not in group, inserting leave message");
@@ -250,7 +251,7 @@ public final class GroupsV2StateProcessor {
throws IOException, GroupNotAMemberException, GroupDoesNotExistException
{
try {
return groupsV2Api.getGroup(groupSecretParams, groupsV2Authorization.getAuthorizationForToday(Recipient.self().requireUuid(), groupSecretParams));
return groupsV2Api.getGroup(groupSecretParams, groupsV2Authorization.getAuthorizationForToday(Recipient.self().requireAci(), groupSecretParams));
} catch (GroupNotFoundException e) {
throw new GroupDoesNotExistException(e);
} catch (NotInGroupException e) {
@@ -265,7 +266,7 @@ public final class GroupsV2StateProcessor {
throws IOException, GroupNotAMemberException, GroupDoesNotExistException
{
try {
return groupsV2Api.getGroupHistory(groupSecretParams, revision, groupsV2Authorization.getAuthorizationForToday(Recipient.self().requireUuid(), groupSecretParams))
return groupsV2Api.getGroupHistory(groupSecretParams, revision, groupsV2Authorization.getAuthorizationForToday(Recipient.self().requireAci(), groupSecretParams))
.get(0)
.getGroup()
.orNull();
@@ -285,7 +286,7 @@ public final class GroupsV2StateProcessor {
}
Recipient groupRecipient = Recipient.externalGroupExact(context, groupId);
UUID selfUuid = Recipient.self().getUuid().get();
UUID selfUuid = Recipient.self().requireAci().uuid();
DecryptedGroup decryptedGroup = groupDatabase.requireGroup(groupId)
.requireV2GroupProperties()
.getDecryptedGroup();
@@ -359,7 +360,7 @@ public final class GroupsV2StateProcessor {
@NonNull DecryptedGroup newLocalState)
{
if (inputGroupState.getLocalState() != null) {
boolean wasAMemberAlready = DecryptedGroupUtil.findMemberByUuid(inputGroupState.getLocalState().getMembersList(), Recipient.self().getUuid().get()).isPresent();
boolean wasAMemberAlready = DecryptedGroupUtil.findMemberByUuid(inputGroupState.getLocalState().getMembersList(), Recipient.self().requireAci().uuid()).isPresent();
if (wasAMemberAlready) {
Log.i(TAG, "Skipping profile sharing detection as was already a full member before update");
@@ -367,7 +368,7 @@ public final class GroupsV2StateProcessor {
}
}
Optional<DecryptedMember> selfAsMemberOptional = DecryptedGroupUtil.findMemberByUuid(newLocalState.getMembersList(), Recipient.self().getUuid().get());
Optional<DecryptedMember> selfAsMemberOptional = DecryptedGroupUtil.findMemberByUuid(newLocalState.getMembersList(), Recipient.self().requireAci().uuid());
if (selfAsMemberOptional.isPresent()) {
DecryptedMember selfAsMember = selfAsMemberOptional.get();
@@ -378,7 +379,7 @@ public final class GroupsV2StateProcessor {
.filter(c -> c != null && c.getRevision() == revisionJoinedAt)
.findFirst()
.map(c -> Optional.fromNullable(UuidUtil.fromByteStringOrNull(c.getEditor()))
.transform(a -> Recipient.externalPush(context, UuidUtil.fromByteStringOrNull(c.getEditor()), null, false)))
.transform(a -> Recipient.externalPush(context, ACI.fromByteStringOrNull(c.getEditor()), null, false)))
.orElse(Optional.absent());
if (addedByOptional.isPresent()) {
@@ -446,33 +447,33 @@ public final class GroupsV2StateProcessor {
private @NonNull GlobalGroupState queryServer(@Nullable DecryptedGroup localState, boolean latestOnly)
throws IOException, GroupNotAMemberException
{
UUID selfUuid = Recipient.self().getUuid().get();
ACI selfAci = Recipient.self().requireAci();
DecryptedGroup latestServerGroup;
List<ServerGroupLogEntry> history;
try {
latestServerGroup = groupsV2Api.getGroup(groupSecretParams, groupsV2Authorization.getAuthorizationForToday(selfUuid, groupSecretParams));
latestServerGroup = groupsV2Api.getGroup(groupSecretParams, groupsV2Authorization.getAuthorizationForToday(selfAci, groupSecretParams));
} catch (NotInGroupException | GroupNotFoundException e) {
throw new GroupNotAMemberException(e);
} catch (VerificationFailedException | InvalidGroupStateException e) {
throw new IOException(e);
}
if (latestOnly || !GroupProtoUtil.isMember(selfUuid, latestServerGroup.getMembersList())) {
if (latestOnly || !GroupProtoUtil.isMember(selfAci.uuid(), latestServerGroup.getMembersList())) {
history = Collections.singletonList(new ServerGroupLogEntry(latestServerGroup, null));
} else {
int revisionWeWereAdded = GroupProtoUtil.findRevisionWeWereAdded(latestServerGroup, selfUuid);
int revisionWeWereAdded = GroupProtoUtil.findRevisionWeWereAdded(latestServerGroup, selfAci.uuid());
int logsNeededFrom = localState != null ? Math.max(localState.getRevision(), revisionWeWereAdded) : revisionWeWereAdded;
history = getFullMemberHistory(selfUuid, logsNeededFrom);
history = getFullMemberHistory(selfAci, logsNeededFrom);
}
return new GlobalGroupState(localState, history);
}
private List<ServerGroupLogEntry> getFullMemberHistory(@NonNull UUID selfUuid, int logsNeededFromRevision) throws IOException {
private List<ServerGroupLogEntry> getFullMemberHistory(@NonNull ACI selfAci, int logsNeededFromRevision) throws IOException {
try {
Collection<DecryptedGroupHistoryEntry> groupStatesFromRevision = groupsV2Api.getGroupHistory(groupSecretParams, logsNeededFromRevision, groupsV2Authorization.getAuthorizationForToday(selfUuid, groupSecretParams));
Collection<DecryptedGroupHistoryEntry> groupStatesFromRevision = groupsV2Api.getGroupHistory(groupSecretParams, logsNeededFromRevision, groupsV2Authorization.getAuthorizationForToday(selfAci, groupSecretParams));
ArrayList<ServerGroupLogEntry> history = new ArrayList<>(groupStatesFromRevision.size());
boolean ignoreServerChanges = SignalStore.internalValues().gv2IgnoreServerChanges();
@@ -496,9 +497,9 @@ public final class GroupsV2StateProcessor {
}
private void storeMessage(@NonNull DecryptedGroupV2Context decryptedGroupV2Context, long timestamp) {
Optional<UUID> editor = getEditor(decryptedGroupV2Context);
Optional<ACI> editor = getEditor(decryptedGroupV2Context).transform(ACI::from);
boolean outgoing = !editor.isPresent() || Recipient.self().requireUuid().equals(editor.get());
boolean outgoing = !editor.isPresent() || Recipient.self().requireAci().equals(editor.get());
if (outgoing) {
try {
@@ -536,7 +537,7 @@ public final class GroupsV2StateProcessor {
if (changeEditor.isPresent()) {
return changeEditor;
} else {
Optional<DecryptedPendingMember> pendingByUuid = DecryptedGroupUtil.findPendingByUuid(decryptedGroupV2Context.getGroupState().getPendingMembersList(), Recipient.self().requireUuid());
Optional<DecryptedPendingMember> pendingByUuid = DecryptedGroupUtil.findPendingByUuid(decryptedGroupV2Context.getGroupState().getPendingMembersList(), Recipient.self().requireAci().uuid());
if (pendingByUuid.isPresent()) {
return Optional.fromNullable(UuidUtil.fromByteStringOrNull(pendingByUuid.get().getAddedByUuid()));
}
@@ -21,7 +21,6 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.transport.RetryLaterException;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.groupsv2.NoCredentialForRedemptionTimeException;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
@@ -71,7 +70,7 @@ public class GroupV1MigrationJob extends BaseJob {
public static void enqueueRoutineMigrationsIfNecessary(@NonNull Application application) {
if (!SignalStore.registrationValues().isRegistrationComplete() ||
!TextSecurePreferences.isPushRegistered(application) ||
TextSecurePreferences.getLocalUuid(application) == null)
TextSecurePreferences.getLocalAci(application) == null)
{
Log.i(TAG, "Registration not complete. Skipping.");
return;
@@ -105,7 +105,7 @@ public class MmsDownloadJob extends BaseJob {
@Override
public void onRun() {
if (TextSecurePreferences.getLocalUuid(context) == null && TextSecurePreferences.getLocalNumber(context) == null) {
if (TextSecurePreferences.getLocalAci(context) == null && TextSecurePreferences.getLocalNumber(context) == null) {
throw new NotReadyException();
}
@@ -82,7 +82,7 @@ public class MultiDeviceBlockedUpdateJob extends BaseJob {
while ((recipient = reader.getNext()) != null) {
if (recipient.isPushGroup()) {
blockedGroups.add(recipient.requireGroupId().getDecodedId());
} else if (recipient.isMaybeRegistered() && (recipient.hasUuid() || recipient.hasE164())) {
} else if (recipient.isMaybeRegistered() && (recipient.hasAci() || recipient.hasE164())) {
blockedIndividuals.add(RecipientUtil.toSignalServiceAddress(context, recipient));
}
}
@@ -19,6 +19,7 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.messages.multidevice.OutgoingPaymentMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException;
@@ -88,9 +89,9 @@ public final class MultiDeviceOutgoingPaymentSyncJob extends BaseJob {
boolean defrag = payment.isDefrag();
Optional<UUID> uuid;
Optional<SignalServiceAddress> uuid;
if (!defrag && payment.getPayee().hasRecipientId()) {
uuid = Optional.of(Recipient.resolved(payment.getPayee().requireRecipientId()).requireUuid());
uuid = Optional.of(new SignalServiceAddress(Recipient.resolved(payment.getPayee().requireRecipientId()).requireAci()));
} else {
uuid = Optional.absent();
}
@@ -30,6 +30,7 @@ import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
import org.whispersystems.signalservice.api.messages.SendMessageResult;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
@@ -73,8 +74,8 @@ public final class PushGroupSilentUpdateSendJob extends BaseJob {
Set<RecipientId> 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 -> Recipient.externalPush(context, uuid, null, false))
.filter(uuid -> !Recipient.self().requireAci().uuid().equals(uuid))
.map(uuid -> Recipient.externalPush(context, ACI.from(uuid), null, false))
.filter(recipient -> recipient.getRegistered() != RecipientDatabase.RegisteredState.NOT_REGISTERED)
.map(Recipient::getId)
.collect(Collectors.toSet());
@@ -226,7 +226,7 @@ public class PushMediaSendJob extends PushSendJob {
.asExpirationUpdate(message.isExpirationUpdate())
.build();
if (Util.equals(TextSecurePreferences.getLocalUuid(context), address.getUuid())) {
if (Util.equals(TextSecurePreferences.getLocalAci(context), address.getAci())) {
Optional<UnidentifiedAccessPair> syncAccess = UnidentifiedAccessUtil.getAccessForSync(context);
SignalServiceSyncMessage syncMessage = buildSelfSendSyncMessage(context, mediaMessage, syncAccess);
@@ -13,7 +13,6 @@ import com.annimon.stream.Stream;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.signal.core.util.ThreadUtil;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.metadata.certificate.InvalidCertificateException;
import org.signal.libsignal.metadata.certificate.SenderCertificate;
@@ -43,7 +42,6 @@ import org.thoughtcrime.securesms.net.NotPushRegisteredException;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.registration.PushChallengeRequest;
import org.thoughtcrime.securesms.transport.RetryLaterException;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.BitmapDecodingException;
@@ -51,11 +49,9 @@ import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.Hex;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.SignalLocalMetrics;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
@@ -68,10 +64,7 @@ import org.whispersystems.signalservice.api.messages.shared.SharedContact;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
import org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException;
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
import org.whispersystems.signalservice.internal.push.ProofRequiredResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -416,7 +409,7 @@ public abstract class PushSendJob extends SendJob {
List<SignalServiceDataMessage.Mention> getMentionsFor(@NonNull List<Mention> mentions) {
return Stream.of(mentions)
.map(m -> new SignalServiceDataMessage.Mention(Recipient.resolved(m.getRecipientId()).requireUuid(), m.getStart(), m.getLength()))
.map(m -> new SignalServiceDataMessage.Mention(Recipient.resolved(m.getRecipientId()).requireAci(), m.getStart(), m.getLength()))
.toList();
}
@@ -454,7 +447,7 @@ public abstract class PushSendJob extends SendJob {
}
protected SignalServiceSyncMessage buildSelfSendSyncMessage(@NonNull Context context, @NonNull SignalServiceDataMessage message, Optional<UnidentifiedAccessPair> syncAccess) {
SignalServiceAddress localAddress = new SignalServiceAddress(TextSecurePreferences.getLocalUuid(context), TextSecurePreferences.getLocalNumber(context));
SignalServiceAddress localAddress = new SignalServiceAddress(TextSecurePreferences.getLocalAci(context), TextSecurePreferences.getLocalNumber(context));
SentTranscriptMessage transcript = new SentTranscriptMessage(Optional.of(localAddress),
message.getTimestamp(),
message,
@@ -188,7 +188,7 @@ public class PushTextSendJob extends PushSendJob {
.asEndSessionMessage(message.isEndSession())
.build();
if (Util.equals(TextSecurePreferences.getLocalUuid(context), address.getUuid())) {
if (Util.equals(TextSecurePreferences.getLocalAci(context), address.getAci())) {
Optional<UnidentifiedAccessPair> syncAccess = UnidentifiedAccessUtil.getAccessForSync(context);
SignalServiceSyncMessage syncMessage = buildSelfSendSyncMessage(context, textSecureMessage, syncAccess);
@@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.jobs;
import android.app.Application;
import android.content.Context;
import android.net.Uri;
import android.text.TextUtils;
import androidx.annotation.NonNull;
@@ -16,9 +15,7 @@ import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log;
import org.signal.zkgroup.profiles.ProfileKey;
import org.signal.zkgroup.profiles.ProfileKeyCredential;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.badges.Badges;
import org.thoughtcrime.securesms.badges.models.Badge;
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
@@ -38,7 +35,6 @@ import org.thoughtcrime.securesms.transport.RetryLaterException;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.IdentityUtil;
import org.thoughtcrime.securesms.util.ProfileUtil;
import org.thoughtcrime.securesms.util.ScreenDensity;
import org.thoughtcrime.securesms.util.SetUtil;
import org.thoughtcrime.securesms.util.Stopwatch;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@@ -51,6 +47,7 @@ import org.whispersystems.signalservice.api.crypto.InvalidCiphertextException;
import org.whispersystems.signalservice.api.crypto.ProfileCipher;
import org.whispersystems.signalservice.api.profiles.ProfileAndCredential;
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.services.ProfileService;
import org.whispersystems.signalservice.internal.ServiceResponse;
@@ -62,7 +59,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import io.reactivex.rxjava3.core.Observable;
@@ -175,7 +171,7 @@ public class RetrieveProfileJob extends BaseJob {
public static void enqueueRoutineFetchIfNecessary(Application application) {
if (!SignalStore.registrationValues().isRegistrationComplete() ||
!TextSecurePreferences.isPushRegistered(application) ||
TextSecurePreferences.getLocalUuid(application) == null)
TextSecurePreferences.getLocalAci(application) == null)
{
Log.i(TAG, "Registration not complete. Skipping.");
return;
@@ -293,11 +289,11 @@ public class RetrieveProfileJob extends BaseJob {
Set<RecipientId> success = SetUtil.difference(recipientIds, operationState.retries);
recipientDatabase.markProfilesFetched(success, System.currentTimeMillis());
Map<RecipientId, String> newlyRegistered = Stream.of(operationState.profiles)
.map(Pair::first)
.filterNot(Recipient::isRegistered)
.collect(Collectors.toMap(Recipient::getId,
r -> r.getUuid().transform(UUID::toString).orNull()));
Map<RecipientId, ACI> newlyRegistered = Stream.of(operationState.profiles)
.map(Pair::first)
.filterNot(Recipient::isRegistered)
.collect(Collectors.toMap(Recipient::getId,
r -> r.getAci().orNull()));
if (operationState.unregistered.size() > 0 || newlyRegistered.size() > 0) {
Log.i(TAG, "Marking " + newlyRegistered.size() + " users as registered and " + operationState.unregistered.size() + " users as unregistered.");
@@ -89,7 +89,7 @@ public class SmsReceiveJob extends BaseJob {
public void onRun() throws MigrationPendingException, RetryLaterException {
Optional<IncomingTextMessage> message = assembleMessageFragments(pdus, subscriptionId);
if (TextSecurePreferences.getLocalUuid(context) == null && TextSecurePreferences.getLocalNumber(context) == null) {
if (TextSecurePreferences.getLocalAci(context) == null && TextSecurePreferences.getLocalNumber(context) == null) {
Log.i(TAG, "Received an SMS before we're registered...");
if (message.isPresent()) {
@@ -22,7 +22,7 @@ public final class LogSectionCapabilities implements LogSection {
return "Unregistered";
}
if (TextSecurePreferences.getLocalNumber(context) == null || TextSecurePreferences.getLocalUuid(context) == null) {
if (TextSecurePreferences.getLocalNumber(context) == null || TextSecurePreferences.getLocalAci(context) == null) {
return "Self not yet available!";
}
@@ -29,7 +29,7 @@ final class LogSectionKeyPreferences implements LogSection {
.append("Client Deprecated : ").append(SignalStore.misc().isClientDeprecated()).append("\n")
.append("Push Registered : ").append(TextSecurePreferences.isPushRegistered(context)).append("\n")
.append("Unauthorized Received: ").append(TextSecurePreferences.isUnauthorizedRecieved(context)).append("\n")
.append("self.isRegistered() : ").append(TextSecurePreferences.getLocalUuid(context) == null ? "false" : Recipient.self().isRegistered()).append("\n")
.append("self.isRegistered() : ").append(TextSecurePreferences.getLocalAci(context) == null ? "false" : Recipient.self().isRegistered()).append("\n")
.append("Thread Trimming : ").append(getThreadTrimmingString()).append("\n");
}
@@ -15,7 +15,6 @@ import com.google.android.gms.common.GoogleApiAvailability;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.emoji.EmojiFiles;
import org.thoughtcrime.securesms.emoji.EmojiSource;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.AppSignatureUtil;
@@ -27,12 +26,11 @@ import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.VersionTracker;
import org.whispersystems.signalservice.api.push.ACI;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
public class LogSectionSystemInfo implements LogSection {
@@ -64,7 +62,7 @@ public class LogSectionSystemInfo implements LogSection {
builder.append("MemInfo : ").append(getMemoryInfo(context)).append("\n");
builder.append("OS Host : ").append(Build.HOST).append("\n");
builder.append("RecipientId : ").append(SignalStore.registrationValues().isRegistrationComplete() ? Recipient.self().getId() : "N/A").append("\n");
builder.append("UUID : ").append(getCensoredUuid(context)).append("\n");
builder.append("ACI : ").append(getCensoredAci(context)).append("\n");
builder.append("Censored : ").append(CensorshipUtil.isCensored(context)).append("\n");
builder.append("Play Services : ").append(getPlayServicesString(context)).append("\n");
builder.append("FCM : ").append(!TextSecurePreferences.isFcmDisabled(context)).append("\n");
@@ -166,12 +164,12 @@ public class LogSectionSystemInfo implements LogSection {
}
}
private static String getCensoredUuid(@NonNull Context context) {
UUID uuid = TextSecurePreferences.getLocalUuid(context);
private static String getCensoredAci(@NonNull Context context) {
ACI aci = TextSecurePreferences.getLocalAci(context);
if (uuid != null) {
String uuidString = uuid.toString();
String lastTwo = uuidString.substring(uuidString.length() - 2);
if (aci != null) {
String aciString = aci.toString();
String lastTwo = aciString.substring(aciString.length() - 2);
return "********-****-****-****-**********" + lastTwo;
} else {
@@ -174,9 +174,9 @@ public final class GroupSendUtil {
boolean validMembership = groupRecord.isPresent() && groupRecord.get().getMembers().contains(recipient.getId());
if (recipient.getSenderKeyCapability() == Recipient.Capability.SUPPORTED &&
recipient.hasUuid() &&
access.isPresent() &&
access.get().getTargetUnidentifiedAccess().isPresent() &&
recipient.hasAci() &&
access.isPresent() &&
access.get().getTargetUnidentifiedAccess().isPresent() &&
validMembership)
{
senderKeyTargets.add(recipient);
@@ -312,8 +312,8 @@ public final class GroupSendUtil {
Log.w(TAG, "There are " + unregisteredTargets.size() + " unregistered targets. Including failure results.");
List<SendMessageResult> unregisteredResults = unregisteredTargets.stream()
.filter(Recipient::hasUuid)
.map(t -> SendMessageResult.unregisteredFailure(new SignalServiceAddress(t.requireUuid(), t.getE164().orNull())))
.filter(Recipient::hasAci)
.map(t -> SendMessageResult.unregisteredFailure(new SignalServiceAddress(t.requireAci(), t.getE164().orNull())))
.collect(Collectors.toList());
if (unregisteredResults.size() < unregisteredTargets.size()) {
@@ -26,7 +26,6 @@ import org.thoughtcrime.securesms.contactshare.ContactModelMapper;
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
import org.thoughtcrime.securesms.crypto.SecurityEvent;
import org.thoughtcrime.securesms.crypto.SessionUtil;
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
@@ -83,7 +82,6 @@ import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
import org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob;
import org.thoughtcrime.securesms.jobs.SenderKeyDistributionSendJob;
import org.thoughtcrime.securesms.jobs.StickerPackDownloadJob;
import org.thoughtcrime.securesms.jobs.ThreadUpdateJob;
import org.thoughtcrime.securesms.jobs.TrimThreadJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
@@ -123,7 +121,6 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.protocol.DecryptionErrorMessage;
import org.whispersystems.libsignal.state.SessionStore;
import org.whispersystems.libsignal.util.Pair;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
@@ -643,7 +640,7 @@ public final class MessageContentProcessor {
}
ApplicationDependencies.getSignalCallManager()
.receivedOpaqueMessage(new WebRtcData.OpaqueMessageMetadata(senderRecipient.requireUuid(),
.receivedOpaqueMessage(new WebRtcData.OpaqueMessageMetadata(senderRecipient.requireAci().uuid(),
message.getOpaque(),
content.getSenderDevice(),
messageAgeSeconds));
@@ -1021,7 +1018,7 @@ public final class MessageContentProcessor {
private void handleSynchronizeOutgoingPayment(@NonNull SignalServiceContent content, @NonNull OutgoingPaymentMessage outgoingPaymentMessage) {
RecipientId recipientId = outgoingPaymentMessage.getRecipient()
.transform(uuid -> RecipientId.from(uuid, null))
.transform(RecipientId::from)
.orNull();
long timestamp = outgoingPaymentMessage.getBlockTimestamp();
if (timestamp == 0) {
@@ -1811,7 +1808,7 @@ public final class MessageContentProcessor {
warn(content.getTimestamp(), "[RetryReceipt] Received a retry receipt from " + formatSender(senderRecipient, content) + " for message with timestamp " + sentTimestamp + ".");
if (!senderRecipient.hasUuid()) {
if (!senderRecipient.hasAci()) {
warn(content.getTimestamp(), "[RetryReceipt] Requester " + senderRecipient.getId() + " somehow has no UUID! timestamp: " + sentTimestamp);
return;
}
@@ -1851,7 +1848,7 @@ public final class MessageContentProcessor {
GroupId.V2 groupId = threadRecipient.requireGroupId().requireV2();
DistributionId distributionId = DatabaseFactory.getGroupDatabase(context).getOrCreateDistributionId(groupId);
SignalProtocolAddress requesterAddress = new SignalProtocolAddress(requester.requireUuid().toString(), content.getSenderDevice());
SignalProtocolAddress requesterAddress = new SignalProtocolAddress(requester.requireAci().toString(), content.getSenderDevice());
DatabaseFactory.getSenderKeySharedDatabase(context).delete(distributionId, Collections.singleton(requesterAddress));
@@ -2090,7 +2087,7 @@ public final class MessageContentProcessor {
List<Mention> mentions = new ArrayList<>(signalServiceMentions.size());
for (SignalServiceDataMessage.Mention mention : signalServiceMentions) {
mentions.add(new Mention(Recipient.externalPush(context, mention.getUuid(), null, false).getId(), mention.getStart(), mention.getLength()));
mentions.add(new Mention(Recipient.externalPush(context, mention.getAci(), null, false).getId(), mention.getStart(), mention.getLength()));
}
return mentions;
@@ -2229,8 +2226,8 @@ public final class MessageContentProcessor {
if (recipient.hasE164()) {
unidentified |= message.isUnidentified(recipient.requireE164());
}
if (recipient.hasUuid()) {
unidentified |= message.isUnidentified(recipient.requireUuid());
if (recipient.hasAci()) {
unidentified |= message.isUnidentified(recipient.requireAci());
}
return unidentified;
@@ -78,7 +78,7 @@ public final class MessageDecryptionUtil {
*/
public static @NonNull DecryptionResult decrypt(@NonNull Context context, @NonNull SignalServiceEnvelope envelope) {
SignalProtocolStore axolotlStore = new SignalProtocolStoreImpl(context);
SignalServiceAddress localAddress = new SignalServiceAddress(TextSecurePreferences.getLocalUuid(context), Optional.of(TextSecurePreferences.getLocalNumber(context)));
SignalServiceAddress localAddress = new SignalServiceAddress(TextSecurePreferences.getLocalAci(context), Optional.of(TextSecurePreferences.getLocalNumber(context)));
SignalServiceCipher cipher = new SignalServiceCipher(localAddress, axolotlStore, ReentrantSessionLock.INSTANCE, UnidentifiedAccessUtil.getCertificateValidator());
List<Job> jobs = new LinkedList<>();
@@ -41,7 +41,7 @@ public class AccountRecordMigrationJob extends MigrationJob {
@Override
public void performMigration() {
if (!TextSecurePreferences.isPushRegistered(context) || TextSecurePreferences.getLocalUuid(context) == null) {
if (!TextSecurePreferences.isPushRegistered(context) || TextSecurePreferences.getLocalAci(context) == null) {
Log.w(TAG, "Not registered!");
return;
}
@@ -7,10 +7,8 @@ import com.google.protobuf.InvalidProtocolBufferException;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobmanager.Data;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobs.StorageSyncJob;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@@ -47,7 +45,7 @@ public class ApplyUnknownFieldsToSelfMigrationJob extends MigrationJob {
@Override
public void performMigration() {
if (!TextSecurePreferences.isPushRegistered(context) || TextSecurePreferences.getLocalUuid(context) == null) {
if (!TextSecurePreferences.isPushRegistered(context) || TextSecurePreferences.getLocalAci(context) == null) {
Log.w(TAG, "Not registered!");
return;
}
@@ -42,7 +42,7 @@ public final class DirectoryRefreshMigrationJob extends MigrationJob {
public void performMigration() throws IOException {
if (!TextSecurePreferences.isPushRegistered(context) ||
!SignalStore.registrationValues().isRegistrationComplete() ||
TextSecurePreferences.getLocalUuid(context) == null)
TextSecurePreferences.getLocalAci(context) == null)
{
Log.w(TAG, "Not registered! Skipping.");
return;
@@ -42,7 +42,7 @@ public class StorageServiceMigrationJob extends MigrationJob {
@Override
public void performMigration() {
if (TextSecurePreferences.getLocalUuid(context) == null) {
if (TextSecurePreferences.getLocalAci(context) == null) {
Log.w(TAG, "Self not yet available.");
return;
}
@@ -58,7 +58,7 @@ public class UserNotificationMigrationJob extends MigrationJob {
void performMigration() {
if (!TextSecurePreferences.isPushRegistered(context) ||
TextSecurePreferences.getLocalNumber(context) == null ||
TextSecurePreferences.getLocalUuid(context) == null)
TextSecurePreferences.getLocalAci(context) == null)
{
Log.w(TAG, "Not registered! Skipping.");
return;
@@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.push.ACI;
import java.io.IOException;
import java.util.UUID;
@@ -70,10 +71,10 @@ public class UuidMigrationJob extends MigrationJob {
private static void fetchOwnUuid(@NonNull Context context) throws IOException {
RecipientId self = Recipient.self().getId();
UUID localUuid = ApplicationDependencies.getSignalServiceAccountManager().getOwnUuid();
ACI localUuid = ApplicationDependencies.getSignalServiceAccountManager().getOwnAci();
DatabaseFactory.getRecipientDatabase(context).markRegisteredOrThrow(self, localUuid);
TextSecurePreferences.setLocalUuid(context, localUuid);
TextSecurePreferences.setLocalAci(context, localUuid);
}
public static class Factory implements Job.Factory<UuidMigrationJob> {
@@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.Base64;
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
@@ -191,7 +192,7 @@ public final class MessageGroupContext {
List<RecipientId> members = new ArrayList<>(decryptedGroupV2Context.getGroupState().getMembersCount());
for (DecryptedMember member : decryptedGroupV2Context.getGroupState().getMembersList()) {
RecipientId recipient = RecipientId.from(UuidUtil.fromByteString(member.getUuid()), null);
RecipientId recipient = RecipientId.from(ACI.fromByteString(member.getUuid()), null);
if (!Recipient.self().getId().equals(recipient)) {
members.add(recipient);
}
@@ -11,6 +11,7 @@ import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.ACI;
import java.util.UUID;
@@ -19,7 +20,7 @@ public class AccountManagerFactory {
private static final String TAG = Log.tag(AccountManagerFactory.class);
public static @NonNull SignalServiceAccountManager createAuthenticated(@NonNull Context context,
@NonNull UUID uuid,
@NonNull ACI aci,
@NonNull String number,
@NonNull String password)
{
@@ -34,7 +35,11 @@ public class AccountManagerFactory {
}
return new SignalServiceAccountManager(new SignalServiceNetworkAccess(context).getConfiguration(number),
uuid, number, password, BuildConfig.SIGNAL_AGENT, FeatureFlags.okHttpAutomaticRetry());
aci,
number,
password,
BuildConfig.SIGNAL_AGENT,
FeatureFlags.okHttpAutomaticRetry());
}
/**
@@ -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 {
@@ -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) &&
@@ -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();
@@ -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();
}
@@ -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);
}
@@ -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) {
@@ -36,13 +36,13 @@ import org.whispersystems.libsignal.util.KeyHelper;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.KbsPinData;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.ServiceResponse;
import org.whispersystems.signalservice.internal.push.VerifyAccountResponse;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.schedulers.Schedulers;
@@ -128,14 +128,14 @@ public final class RegistrationRepository {
SessionUtil.archiveAllSessions();
SenderKeyUtil.clearAllState(context);
UUID uuid = UuidUtil.parseOrThrow(response.getUuid());
ACI aci = ACI.parseOrThrow(response.getUuid());
boolean hasPin = response.isStorageCapable();
IdentityKeyPair identityKey = IdentityKeyUtil.getIdentityKeyPair(context);
List<PreKeyRecord> records = PreKeyUtil.generatePreKeys(context);
SignedPreKeyRecord signedPreKey = PreKeyUtil.generateSignedPreKey(context, identityKey, true);
SignalServiceAccountManager accountManager = AccountManagerFactory.createAuthenticated(context, uuid, registrationData.getE164(), registrationData.getPassword());
SignalServiceAccountManager accountManager = AccountManagerFactory.createAuthenticated(context, aci, registrationData.getE164(), registrationData.getPassword());
accountManager.setPreKeys(identityKey.getPublicKey(), signedPreKey, records);
if (registrationData.isFcm()) {
@@ -143,13 +143,13 @@ public final class RegistrationRepository {
}
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
RecipientId selfId = Recipient.externalPush(context, uuid, registrationData.getE164(), true).getId();
RecipientId selfId = Recipient.externalPush(context, aci, registrationData.getE164(), true).getId();
recipientDatabase.setProfileSharing(selfId, true);
recipientDatabase.markRegisteredOrThrow(selfId, uuid);
recipientDatabase.markRegisteredOrThrow(selfId, aci);
TextSecurePreferences.setLocalNumber(context, registrationData.getE164());
TextSecurePreferences.setLocalUuid(context, uuid);
TextSecurePreferences.setLocalAci(context, aci);
recipientDatabase.setProfileKey(selfId, registrationData.getProfileKey());
ApplicationDependencies.getRecipientCache().clearSelf();
@@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceStateBuilder;
import org.webrtc.VideoTrack;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
import org.whispersystems.signalservice.api.push.ACI;
import java.util.ArrayList;
import java.util.Collection;
@@ -82,7 +83,7 @@ public class GroupActionProcessor extends DeviceAwareActionProcessor {
seen.add(Recipient.self());
for (GroupCall.RemoteDeviceState device : remoteDeviceStates) {
Recipient recipient = Recipient.externalPush(context, device.getUserId(), null, false);
Recipient recipient = Recipient.externalPush(context, ACI.from(device.getUserId()), null, false);
CallParticipantId callParticipantId = new CallParticipantId(device.getDemuxId(), recipient.getId());
CallParticipant callParticipant = participants.get(callParticipantId);
@@ -122,8 +122,8 @@ public class GroupConnectedActionProcessor extends GroupActionProcessor {
webRtcInteractor.sendGroupCallMessage(currentState.getCallInfoState().getCallRecipient(), eraId);
List<UUID> members = new ArrayList<>(peekInfo.getJoinedMembers());
if (!members.contains(Recipient.self().requireUuid())) {
members.add(Recipient.self().requireUuid());
if (!members.contains(Recipient.self().requireAci().uuid())) {
members.add(Recipient.self().requireAci().uuid());
}
webRtcInteractor.updateGroupCallUpdateMessage(currentState.getCallInfoState().getCallRecipient().getId(), eraId, members, WebRtcUtil.isCallFull(peekInfo));
@@ -148,7 +148,7 @@ public class GroupConnectedActionProcessor extends GroupActionProcessor {
String eraId = WebRtcUtil.getGroupCallEraId(groupCall);
webRtcInteractor.sendGroupCallMessage(currentState.getCallInfoState().getCallRecipient(), eraId);
List<UUID> members = Stream.of(currentState.getCallInfoState().getRemoteCallParticipants()).map(p -> p.getRecipient().requireUuid()).toList();
List<UUID> members = Stream.of(currentState.getCallInfoState().getRemoteCallParticipants()).map(p -> p.getRecipient().requireAci().uuid()).toList();
webRtcInteractor.updateGroupCallUpdateMessage(currentState.getCallInfoState().getCallRecipient().getId(), eraId, members, false);
currentState = currentState.builder()
@@ -19,6 +19,7 @@ import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceStateBuilder;
import org.thoughtcrime.securesms.util.NetworkUtil;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
import org.whispersystems.signalservice.api.push.ACI;
import java.util.List;
@@ -108,7 +109,7 @@ public class GroupPreJoinActionProcessor extends GroupActionProcessor {
}
List<Recipient> callParticipants = Stream.of(peekInfo.getJoinedMembers())
.map(uuid -> Recipient.externalPush(context, uuid, null, false))
.map(uuid -> Recipient.externalPush(context, ACI.from(uuid), null, false))
.toList();
WebRtcServiceStateBuilder.CallInfoStateBuilder builder = currentState.builder()
@@ -24,6 +24,7 @@ import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.thoughtcrime.securesms.util.NetworkUtil;
import org.thoughtcrime.securesms.webrtc.locks.LockManager;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.push.ACI;
import java.util.UUID;
@@ -136,7 +137,7 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
.changeCallSetupState()
.isRemoteVideoOffer(true)
.ringId(ringId)
.ringerRecipient(Recipient.externalPush(context, uuid, null, false))
.ringerRecipient(Recipient.externalPush(context, ACI.from(uuid), null, false))
.commit()
.changeCallInfoState()
.callRecipient(remotePeerGroup.getRecipient())
@@ -64,6 +64,7 @@ import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
import org.whispersystems.signalservice.api.messages.calls.OpaqueMessage;
import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage;
import org.whispersystems.signalservice.api.messages.calls.TurnServerInfo;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
import java.io.IOException;
@@ -149,7 +150,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
serviceExecutor.execute(() -> {
if (needsToSetSelfUuid) {
try {
callManager.setSelfUuid(Recipient.self().requireUuid());
callManager.setSelfUuid(Recipient.self().requireAci().uuid());
needsToSetSelfUuid = false;
} catch (CallException e) {
Log.w(TAG, "Unable to set self UUID on CallManager", e);
@@ -593,7 +594,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall.
SignalServiceCallMessage callMessage = SignalServiceCallMessage.forOpaque(opaqueMessage, true, null);
networkExecutor.execute(() -> {
Recipient recipient = Recipient.resolved(RecipientId.from(uuid, null));
Recipient recipient = Recipient.resolved(RecipientId.from(ACI.from(uuid), null));
if (recipient.isBlocked()) {
return;
}
@@ -11,6 +11,7 @@ import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.storage.SignalContactRecord;
import org.whispersystems.signalservice.api.util.UuidUtil;
@@ -50,10 +51,10 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
if (address == null) {
Log.w(TAG, "No address on the ContentRecord -- marking as invalid.");
return true;
} else if (address.getUuid().equals(UuidUtil.UNKNOWN_UUID)) {
} else if (address.getAci().equals(UuidUtil.UNKNOWN_UUID)) {
Log.w(TAG, "Found a ContactRecord without a UUID -- marking as invalid.");
return true;
} else if ((self.getUuid().isPresent() && address.getUuid().equals(self.requireUuid())) ||
} else if ((self.getAci().isPresent() && address.getAci().equals(self.requireAci())) ||
(self.getE164().isPresent() && address.getNumber().equals(self.getE164())))
{
Log.w(TAG, "Found a ContactRecord for ourselves -- marking as invalid.");
@@ -66,7 +67,7 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
@Override
@NonNull Optional<SignalContactRecord> getMatching(@NonNull SignalContactRecord remote, @NonNull StorageKeyGenerator keyGenerator) {
SignalServiceAddress address = remote.getAddress();
Optional<RecipientId> byUuid = recipientDatabase.getByUuid(address.getUuid());
Optional<RecipientId> byUuid = recipientDatabase.getByAci(address.getAci());
Optional<RecipientId> byE164 = address.getNumber().isPresent() ? recipientDatabase.getByE164(address.getNumber().get()) : Optional.absent();
return byUuid.or(byE164).transform(recipientDatabase::getRecipientSettingsForSync)
@@ -97,9 +98,9 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
}
byte[] unknownFields = remote.serializeUnknownFields();
UUID uuid = local.getAddress().getUuid() == UuidUtil.UNKNOWN_UUID ? remote.getAddress().getUuid() : local.getAddress().getUuid();
ACI aci = local.getAddress().getAci() == ACI.UNKNOWN ? remote.getAddress().getAci() : local.getAddress().getAci();
String e164 = remote.getAddress().getNumber().or(local.getAddress().getNumber()).orNull();
SignalServiceAddress address = new SignalServiceAddress(uuid, e164);
SignalServiceAddress address = new SignalServiceAddress(aci, e164);
byte[] profileKey = remote.getProfileKey().or(local.getProfileKey()).orNull();
String username = remote.getUsername().or(local.getUsername()).or("");
IdentityState identityState = remote.getIdentityState();
@@ -146,7 +147,7 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
@Override
public int compare(@NonNull SignalContactRecord lhs, @NonNull SignalContactRecord rhs) {
if (Objects.equals(lhs.getAddress().getUuid(), rhs.getAddress().getUuid()) ||
if (Objects.equals(lhs.getAddress().getAci(), rhs.getAddress().getAci()) ||
Objects.equals(lhs.getAddress().getNumber(), rhs.getAddress().getNumber()))
{
return 0;
@@ -10,6 +10,7 @@ import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.storage.SignalAccountRecord;
import org.whispersystems.signalservice.api.storage.SignalContactRecord;
@@ -81,7 +82,7 @@ public final class StorageSyncModels {
private static @NonNull SignalAccountRecord.PinnedConversation localToRemotePinnedConversation(@NonNull RecipientSettings settings) {
switch (settings.getGroupType()) {
case NONE : return SignalAccountRecord.PinnedConversation.forContact(new SignalServiceAddress(settings.getUuid(), settings.getE164()));
case NONE : return SignalAccountRecord.PinnedConversation.forContact(new SignalServiceAddress(settings.getAci(), settings.getE164()));
case SIGNAL_V1: return SignalAccountRecord.PinnedConversation.forGroupV1(settings.getGroupId().requireV1().getDecodedId());
case SIGNAL_V2: return SignalAccountRecord.PinnedConversation.forGroupV2(settings.getSyncExtras().getGroupMasterKey().serialize());
default : throw new AssertionError("Unexpected group type!");
@@ -89,13 +90,13 @@ public final class StorageSyncModels {
}
private static @NonNull SignalContactRecord localToRemoteContact(@NonNull RecipientSettings recipient, byte[] rawStorageId) {
if (recipient.getUuid() == null && recipient.getE164() == null) {
if (recipient.getAci() == null && recipient.getE164() == null) {
throw new AssertionError("Must have either a UUID or a phone number!");
}
UUID uuid = recipient.getUuid() != null ? recipient.getUuid() : UuidUtil.UNKNOWN_UUID;
ACI aci = recipient.getAci() != null ? recipient.getAci() : ACI.UNKNOWN;
return new SignalContactRecord.Builder(rawStorageId, new SignalServiceAddress(uuid, recipient.getE164()))
return new SignalContactRecord.Builder(rawStorageId, new SignalServiceAddress(aci, recipient.getE164()))
.setUnknownFields(recipient.getSyncExtras().getStorageProto())
.setProfileKey(recipient.getProfileKey())
.setGivenName(recipient.getProfileName().getGivenName())
@@ -7,12 +7,9 @@ import com.annimon.stream.Stream;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.transport.RetryLaterException;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.SetUtil;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.storage.SignalRecord;
import org.whispersystems.signalservice.api.storage.SignalStorageManifest;
import org.whispersystems.signalservice.api.storage.SignalStorageRecord;
import org.whispersystems.signalservice.api.storage.StorageId;
@@ -145,7 +142,7 @@ public final class StorageSyncValidations {
if (insert.getContact().isPresent()) {
SignalServiceAddress address = insert.getContact().get().getAddress();
if (self.getE164().get().equals(address.getNumber().or("")) || self.getUuid().get().equals(address.getUuid())) {
if (self.getE164().get().equals(address.getNumber().or("")) || self.requireAci().equals(address.getAci())) {
throw new SelfAddedAsContactError();
}
}
@@ -23,7 +23,7 @@ public final class BucketingUtil {
* Calculate a user bucket for a given feature flag, uuid, and part per modulus.
*
* @param key Feature flag key (e.g., "research.megaphone.1")
* @param uuid Current user's UUID (see {@link Recipient#getUuid()})
* @param uuid Current user's UUID (see {@link Recipient#getAci()})
* @param modulus Drives the bucketing parts per N (e.g., passing 1,000,000 indicates bucketing into parts per million)
*/
public static long bucket(@NonNull String key, @NonNull UUID uuid, long modulus) {
@@ -242,7 +242,7 @@ public class CommunicationActions {
SimpleTask.run(() -> {
Recipient recipient = Recipient.external(activity, e164);
if (!recipient.isRegistered() || !recipient.hasUuid()) {
if (!recipient.isRegistered() || !recipient.hasAci()) {
try {
DirectoryHelper.refreshDirectoryFor(activity, recipient, false);
recipient = Recipient.resolved(recipient.getId());
@@ -72,12 +72,12 @@ public final class LocaleFeatureFlags {
Map<String, Integer> countryCodeValues = parseCountryValues(serialized, 0);
Recipient self = Recipient.self();
if (countryCodeValues.isEmpty() || !self.getE164().isPresent() || !self.getUuid().isPresent()) {
if (countryCodeValues.isEmpty() || !self.getE164().isPresent() || !self.getAci().isPresent()) {
return false;
}
long countEnabled = getCountryValue(countryCodeValues, self.getE164().or(""), 0);
long currentUserBucket = BucketingUtil.bucket(flag, self.requireUuid(), 1_000_000);
long currentUserBucket = BucketingUtil.bucket(flag, self.requireAci().uuid(), 1_000_000);
return countEnabled > currentUserBucket;
}
@@ -284,7 +284,7 @@ public final class ProfileUtil {
ProfileKey profileKey = ProfileKeyUtil.getSelfProfileKey();
SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager();
String avatarPath = accountManager.setVersionedProfile(Recipient.self().getUuid().get(),
String avatarPath = accountManager.setVersionedProfile(Recipient.self().requireAci(),
profileKey,
profileName.serialize(),
about,
@@ -321,8 +321,8 @@ public final class ProfileUtil {
private static @NonNull SignalServiceAddress toSignalServiceAddress(@NonNull Context context, @NonNull Recipient recipient) throws IOException {
if (recipient.getRegistered() == RecipientDatabase.RegisteredState.NOT_REGISTERED) {
if (recipient.hasUuid()) {
return new SignalServiceAddress(recipient.requireUuid(), recipient.getE164().orNull());
if (recipient.hasAci()) {
return new SignalServiceAddress(recipient.requireAci(), recipient.getE164().orNull());
} else {
throw new IOException(recipient.getId() + " not registered!");
}
@@ -2,9 +2,9 @@ package org.thoughtcrime.securesms.util
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.whispersystems.signalservice.api.push.ACI
import org.whispersystems.signalservice.api.push.SignalServiceAddress
import java.lang.IllegalArgumentException
import java.util.UUID
/**
* A list of Recipients, but with some helpful methods for retrieving them by various properties. Uses lazy properties to ensure that it will be as performant
@@ -12,10 +12,10 @@ import java.util.UUID
*/
class RecipientAccessList(private val recipients: List<Recipient>) : List<Recipient> by recipients {
private val byUuid: Map<UUID, Recipient> by lazy {
private val byAci: Map<ACI, Recipient> by lazy {
recipients
.filter { it.hasUuid() }
.associateBy { it.requireUuid() }
.filter { it.hasAci() }
.associateBy { it.requireAci() }
}
private val byE164: Map<String, Recipient> by lazy {
@@ -25,10 +25,10 @@ class RecipientAccessList(private val recipients: List<Recipient>) : List<Recipi
}
fun requireByAddress(address: SignalServiceAddress): Recipient {
if (byUuid.containsKey(address.uuid)) {
return byUuid.get(address.uuid)!!
if (byAci.containsKey(address.aci)) {
return byAci[address.aci]!!
} else if (address.number.isPresent && byE164.containsKey(address.number.get())) {
return byE164.get(address.number.get())!!
return byE164[address.number.get()]!!
} else {
throw IllegalArgumentException("Could not find a matching recipient!")
}
@@ -29,7 +29,7 @@ import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.whispersystems.libsignal.util.Medium;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.api.push.ACI;
import java.io.IOException;
import java.security.SecureRandom;
@@ -82,7 +82,7 @@ public class TextSecurePreferences {
public static final String MMS_USER_AGENT = "pref_mms_user_agent";
private static final String MMS_CUSTOM_USER_AGENT = "pref_custom_mms_user_agent";
private static final String LOCAL_NUMBER_PREF = "pref_local_number";
private static final String LOCAL_UUID_PREF = "pref_local_uuid";
private static final String LOCAL_ACI_PREF = "pref_local_uuid";
private static final String LOCAL_USERNAME_PREF = "pref_local_username";
public static final String REGISTERED_GCM_PREF = "pref_gcm_registered";
private static final String GCM_PASSWORD_PREF = "pref_gcm_password";
@@ -742,12 +742,12 @@ public class TextSecurePreferences {
setStringPreference(context, LOCAL_NUMBER_PREF, localNumber);
}
public static UUID getLocalUuid(Context context) {
return UuidUtil.parseOrNull(getStringPreference(context, LOCAL_UUID_PREF, null));
public static ACI getLocalAci(Context context) {
return ACI.parseOrNull(getStringPreference(context, LOCAL_ACI_PREF, null));
}
public static void setLocalUuid(Context context, UUID uuid) {
setStringPreference(context, LOCAL_UUID_PREF, uuid.toString());
public static void setLocalAci(Context context, ACI aci) {
setStringPreference(context, LOCAL_ACI_PREF, aci.toString());
}
public static String getPushServerPassword(Context context) {
@@ -14,10 +14,10 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
import org.whispersystems.signalservice.api.push.ACI;
import java.io.IOException;
import java.util.Locale;
import java.util.UUID;
import java.util.regex.Pattern;
public class UsernameUtil {
@@ -51,15 +51,15 @@ public class UsernameUtil {
}
@WorkerThread
public static @NonNull Optional<UUID> fetchUuidForUsername(@NonNull Context context, @NonNull String username) {
public static @NonNull Optional<ACI> fetchAciForUsername(@NonNull Context context, @NonNull String username) {
Optional<RecipientId> localId = DatabaseFactory.getRecipientDatabase(context).getByUsername(username);
if (localId.isPresent()) {
Recipient recipient = Recipient.resolved(localId.get());
if (recipient.getUuid().isPresent()) {
if (recipient.getAci().isPresent()) {
Log.i(TAG, "Found username locally -- using associated UUID.");
return recipient.getUuid();
return recipient.getAci();
} else {
Log.w(TAG, "Found username locally, but it had no associated UUID! Clearing it.");
DatabaseFactory.getRecipientDatabase(context).clearUsernameIfExists(username);
@@ -69,7 +69,7 @@ public class UsernameUtil {
try {
Log.d(TAG, "No local user with this username. Searching remotely.");
SignalServiceProfile profile = ApplicationDependencies.getSignalServiceMessageReceiver().retrieveProfileByUsername(username, Optional.absent(), Locale.getDefault());
return Optional.fromNullable(profile.getUuid());
return Optional.fromNullable(profile.getAci());
} catch (IOException e) {
return Optional.absent();
}