Remove the Canonical Address Database

This was a holdover from Signal's origins as a pure SMS app.
It causes problems, depends on undefined device specific behavior,
and should no longer be necessary now that we have all the
information we need to E164 all numbers.

// FREEBIE
This commit is contained in:
Moxie Marlinspike
2017-07-26 09:59:15 -07:00
parent e452862813
commit 737810475e
113 changed files with 2029 additions and 2130 deletions

View File

@@ -15,9 +15,10 @@ import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.crypto.SessionUtil;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.NotInDirectoryException;
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
import org.thoughtcrime.securesms.database.NotInDirectoryException;
import org.thoughtcrime.securesms.database.TextSecureDirectory;
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
@@ -28,7 +29,6 @@ import org.thoughtcrime.securesms.util.DirectoryHelper.UserCapabilities.Capabili
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.ContactTokenDetails;
import org.whispersystems.signalservice.api.util.InvalidNumberException;
import java.io.IOException;
import java.util.Calendar;
@@ -118,36 +118,31 @@ public class DirectoryHelper {
@NonNull String localNumber)
throws IOException
{
try {
TextSecureDirectory directory = TextSecureDirectory.getInstance(context);
SignalServiceAccountManager accountManager = AccountManagerFactory.createManager(context);
String number = Util.canonicalizeNumber(context, recipients.getPrimaryRecipient().getNumber());
Optional<ContactTokenDetails> details = accountManager.getContact(number);
TextSecureDirectory directory = TextSecureDirectory.getInstance(context);
SignalServiceAccountManager accountManager = AccountManagerFactory.createManager(context);
String number = recipients.getPrimaryRecipient().getAddress().serialize();
Optional<ContactTokenDetails> details = accountManager.getContact(number);
if (details.isPresent()) {
directory.setNumber(details.get(), true);
if (details.isPresent()) {
directory.setNumber(details.get(), true);
RefreshResult result = updateContactsDatabase(context, localNumber, details.get());
RefreshResult result = updateContactsDatabase(context, localNumber, details.get());
if (!result.getNewUsers().isEmpty() && TextSecurePreferences.isMultiDevice(context)) {
ApplicationContext.getInstance(context).getJobManager().add(new MultiDeviceContactUpdateJob(context));
}
if (!result.isFresh()) {
notifyNewUsers(context, masterSecret, result.getNewUsers());
}
return new UserCapabilities(Capability.SUPPORTED,
details.get().isVoice() ? Capability.SUPPORTED : Capability.UNSUPPORTED,
details.get().isVideo() ? Capability.SUPPORTED : Capability.UNSUPPORTED);
} else {
ContactTokenDetails absent = new ContactTokenDetails();
absent.setNumber(number);
directory.setNumber(absent, false);
return UserCapabilities.UNSUPPORTED;
if (!result.getNewUsers().isEmpty() && TextSecurePreferences.isMultiDevice(context)) {
ApplicationContext.getInstance(context).getJobManager().add(new MultiDeviceContactUpdateJob(context));
}
} catch (InvalidNumberException e) {
Log.w(TAG, e);
if (!result.isFresh()) {
notifyNewUsers(context, masterSecret, result.getNewUsers());
}
return new UserCapabilities(Capability.SUPPORTED,
details.get().isVoice() ? Capability.SUPPORTED : Capability.UNSUPPORTED,
details.get().isVideo() ? Capability.SUPPORTED : Capability.UNSUPPORTED);
} else {
ContactTokenDetails absent = new ContactTokenDetails();
absent.setNumber(number);
directory.setNumber(absent, false);
return UserCapabilities.UNSUPPORTED;
}
}
@@ -172,24 +167,14 @@ public class DirectoryHelper {
return new UserCapabilities(Capability.SUPPORTED, Capability.UNSUPPORTED, Capability.UNSUPPORTED);
}
final String number = recipients.getPrimaryRecipient().getNumber();
final Address address = recipients.getPrimaryRecipient().getAddress();
if (number == null) {
return UserCapabilities.UNSUPPORTED;
}
boolean secureText = TextSecureDirectory.getInstance(context).isSecureTextSupported(address);
String e164number = Util.canonicalizeNumber(context, number);
boolean secureText = TextSecureDirectory.getInstance(context).isSecureTextSupported(e164number);
boolean secureVoice = TextSecureDirectory.getInstance(context).isSecureVoiceSupported(e164number);
boolean secureVideo = TextSecureDirectory.getInstance(context).isSecureVideoSupported(e164number);
return new UserCapabilities(secureText ? Capability.SUPPORTED : Capability.UNSUPPORTED,
secureText ? Capability.SUPPORTED : Capability.UNSUPPORTED,
secureText ? Capability.SUPPORTED : Capability.UNSUPPORTED);
return new UserCapabilities(secureText ? Capability.SUPPORTED : Capability.UNSUPPORTED,
secureVoice ? Capability.SUPPORTED : Capability.UNSUPPORTED,
secureVideo ? Capability.SUPPORTED : Capability.UNSUPPORTED);
} catch (InvalidNumberException e) {
Log.w(TAG, e);
return UserCapabilities.UNSUPPORTED;
} catch (NotInDirectoryException e) {
return UserCapabilities.UNKNOWN;
}
@@ -231,7 +216,9 @@ public class DirectoryHelper {
{
if (!TextSecurePreferences.isNewContactsNotificationEnabled(context)) return;
for (String newUser : newUsers) {
for (String newUserString : newUsers) {
Address newUser = Address.fromSerialized(newUserString);
if (!SessionUtil.hasSession(context, masterSecret, newUser) && !Util.isOwnNumber(context, newUser)) {
IncomingJoinedMessage message = new IncomingJoinedMessage(newUser);
Optional<InsertResult> insertResult = DatabaseFactory.getSmsDatabase(context).insertMessageInbox(message);

View File

@@ -6,11 +6,14 @@ import android.support.annotation.Nullable;
import android.util.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
@@ -62,7 +65,13 @@ public class GroupUtil {
if (groupContext == null || groupContext.getMembersList().isEmpty()) {
this.members = null;
} else {
this.members = RecipientFactory.getRecipientsFromStrings(context, groupContext.getMembersList(), true);
List<Address> adddresses = new LinkedList<>();
for (String member : groupContext.getMembersList()) {
adddresses.add(Address.fromExternal(context, member));
}
this.members = RecipientFactory.getRecipientsFor(context, adddresses.toArray(new Address[0]), true);
}
}

View File

@@ -12,6 +12,7 @@ import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.IdentityDatabase;
@@ -39,7 +40,6 @@ import org.whispersystems.libsignal.state.SessionStore;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
import org.whispersystems.signalservice.api.util.InvalidNumberException;
import java.util.List;
@@ -57,7 +57,7 @@ public class IdentityUtil {
@Override
protected Optional<IdentityRecord> doInBackground(Recipient... recipient) {
return DatabaseFactory.getIdentityDatabase(context)
.getIdentity(recipient[0].getRecipientId());
.getIdentity(recipient[0].getAddress());
}
@Override
@@ -78,29 +78,21 @@ public class IdentityUtil {
Recipients recipients = RecipientFactory.getRecipientsFor(context, recipient, true);
GroupDatabase.Reader reader = groupDatabase.getGroups();
String number = recipient.getNumber();
try {
number = Util.canonicalizeNumber(context, number);
} catch (InvalidNumberException e) {
Log.w(TAG, e);
}
GroupDatabase.GroupRecord groupRecord;
while ((groupRecord = reader.getNext()) != null) {
if (groupRecord.getMembers().contains(number) && groupRecord.isActive()) {
if (groupRecord.getMembers().contains(recipient.getAddress()) && groupRecord.isActive()) {
SignalServiceGroup group = new SignalServiceGroup(groupRecord.getId());
if (remote) {
IncomingTextMessage incoming = new IncomingTextMessage(number, 1, time, null, Optional.of(group), 0);
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getAddress(), 1, time, null, Optional.of(group), 0);
if (verified) incoming = new IncomingIdentityVerifiedMessage(incoming);
else incoming = new IncomingIdentityDefaultMessage(incoming);
smsDatabase.insertMessageInbox(incoming);
} else {
Recipients groupRecipients = RecipientFactory.getRecipientsFromString(context, GroupUtil.getEncodedId(group.getGroupId()), true);
Recipients groupRecipients = RecipientFactory.getRecipientsFor(context, new Address[] {Address.fromSerialized(GroupUtil.getEncodedId(group.getGroupId()))}, true);
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipients);
OutgoingTextMessage outgoing ;
@@ -113,7 +105,7 @@ public class IdentityUtil {
}
if (remote) {
IncomingTextMessage incoming = new IncomingTextMessage(number, 1, time, null, Optional.<SignalServiceGroup>absent(), 0);
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getAddress(), 1, time, null, Optional.<SignalServiceGroup>absent(), 0);
if (verified) incoming = new IncomingIdentityVerifiedMessage(incoming);
else incoming = new IncomingIdentityDefaultMessage(incoming);
@@ -139,27 +131,19 @@ public class IdentityUtil {
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
GroupDatabase.Reader reader = groupDatabase.getGroups();
String number = recipient.getNumber();
try {
number = Util.canonicalizeNumber(context, number);
} catch (InvalidNumberException e) {
Log.w(TAG, e);
}
GroupDatabase.GroupRecord groupRecord;
while ((groupRecord = reader.getNext()) != null) {
if (groupRecord.getMembers().contains(number) && groupRecord.isActive()) {
if (groupRecord.getMembers().contains(recipient.getAddress()) && groupRecord.isActive()) {
SignalServiceGroup group = new SignalServiceGroup(groupRecord.getId());
IncomingTextMessage incoming = new IncomingTextMessage(number, 1, time, null, Optional.of(group), 0);
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getAddress(), 1, time, null, Optional.of(group), 0);
IncomingIdentityUpdateMessage groupUpdate = new IncomingIdentityUpdateMessage(incoming);
smsDatabase.insertMessageInbox(groupUpdate);
}
}
IncomingTextMessage incoming = new IncomingTextMessage(number, 1, time, null, Optional.<SignalServiceGroup>absent(), 0);
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getAddress(), 1, time, null, Optional.<SignalServiceGroup>absent(), 0);
IncomingIdentityUpdateMessage individualUpdate = new IncomingIdentityUpdateMessage(incoming);
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(individualUpdate);
@@ -188,8 +172,8 @@ public class IdentityUtil {
public static void processVerifiedMessage(Context context, MasterSecretUnion masterSecret, VerifiedMessage verifiedMessage) {
synchronized (SESSION_LOCK) {
IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(context);
Recipient recipient = RecipientFactory.getRecipientsFromString(context, verifiedMessage.getDestination(), true).getPrimaryRecipient();
Optional<IdentityRecord> identityRecord = identityDatabase.getIdentity(recipient.getRecipientId());
Recipient recipient = RecipientFactory.getRecipientFor(context, Address.fromExternal(context, verifiedMessage.getDestination()), true);
Optional<IdentityRecord> identityRecord = identityDatabase.getIdentity(recipient.getAddress());
if (!identityRecord.isPresent() && verifiedMessage.getVerified() == VerifiedMessage.VerifiedState.DEFAULT) {
Log.w(TAG, "No existing record for default status");
@@ -201,7 +185,7 @@ public class IdentityUtil {
identityRecord.get().getIdentityKey().equals(verifiedMessage.getIdentityKey()) &&
identityRecord.get().getVerifiedStatus() != IdentityDatabase.VerifiedStatus.DEFAULT)
{
identityDatabase.setVerified(recipient.getRecipientId(), identityRecord.get().getIdentityKey(), IdentityDatabase.VerifiedStatus.DEFAULT);
identityDatabase.setVerified(recipient.getAddress(), identityRecord.get().getIdentityKey(), IdentityDatabase.VerifiedStatus.DEFAULT);
markIdentityVerified(context, masterSecret, recipient, false, true);
}
@@ -211,7 +195,7 @@ public class IdentityUtil {
(identityRecord.isPresent() && identityRecord.get().getVerifiedStatus() != IdentityDatabase.VerifiedStatus.VERIFIED)))
{
saveIdentity(context, verifiedMessage.getDestination(), verifiedMessage.getIdentityKey());
identityDatabase.setVerified(recipient.getRecipientId(), verifiedMessage.getIdentityKey(), IdentityDatabase.VerifiedStatus.VERIFIED);
identityDatabase.setVerified(recipient.getAddress(), verifiedMessage.getIdentityKey(), IdentityDatabase.VerifiedStatus.VERIFIED);
markIdentityVerified(context, masterSecret, recipient, true, true);
}
}

View File

@@ -34,25 +34,25 @@ public class NumberUtil {
return PhoneNumberUtils.isWellFormedSmsAddress(number) || isValidEmail(number);
}
public static boolean isValidSmsOrEmailOrGroup(String number) {
return PhoneNumberUtils.isWellFormedSmsAddress(number) ||
isValidEmail(number) ||
GroupUtil.isEncodedGroup(number);
}
public static String filterNumber(String number) {
if (number == null) return null;
int length = number.length();
StringBuilder builder = new StringBuilder(length);
for (int i = 0; i < length; i++) {
char character = number.charAt(i);
if (Character.isDigit(character) || character == '+')
builder.append(character);
}
return builder.toString();
}
// public static boolean isValidSmsOrEmailOrGroup(String number) {
// return PhoneNumberUtils.isWellFormedSmsAddress(number) ||
// isValidEmail(number) ||
// GroupUtil.isEncodedGroup(number);
// }
//
// public static String filterNumber(String number) {
// if (number == null) return null;
//
// int length = number.length();
// StringBuilder builder = new StringBuilder(length);
//
// for (int i = 0; i < length; i++) {
// char character = number.charAt(i);
//
// if (Character.isDigit(character) || character == '+')
// builder.append(character);
// }
//
// return builder.toString();
// }
}

View File

@@ -106,7 +106,7 @@ public class SelectedRecipientsAdapter extends BaseAdapter {
ImageButton delete = (ImageButton) v.findViewById(R.id.delete);
name.setText(p.getName());
phone.setText(p.getNumber());
phone.setText(p.getAddress().serialize());
delete.setVisibility(modifiable ? View.VISIBLE : View.GONE);
delete.setOnClickListener(new View.OnClickListener() {
@Override

View File

@@ -45,8 +45,8 @@ import com.google.android.mms.pdu_alt.EncodedStringValue;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.mms.OutgoingLegacyMmsConnection;
import org.whispersystems.signalservice.api.util.InvalidNumberException;
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
import java.io.ByteArrayOutputStream;
@@ -72,6 +72,20 @@ public class Util {
public static Handler handler = new Handler(Looper.getMainLooper());
public static String join(List<Address> list, String delimiter) {
return join(list.toArray(new Address[0]), delimiter);
}
public static String join(Address[] list, String delimiter) {
List<String> stringList = new LinkedList<>();
for (Address address : list) {
stringList.add(address.serialize());
}
return join(stringList, delimiter);
}
public static String join(String[] list, String delimiter) {
return join(Arrays.asList(list), delimiter);
}
@@ -193,28 +207,11 @@ public class Util {
return totalSize;
}
public static String canonicalizeNumber(Context context, String number)
throws InvalidNumberException
{
String localNumber = TextSecurePreferences.getLocalNumber(context);
return PhoneNumberFormatter.formatNumber(number, localNumber);
}
public static boolean isOwnNumber(Context context, Address address) {
if (address.isGroup()) return false;
if (address.isEmail()) return false;
public static String canonicalizeNumberOrGroup(@NonNull Context context, @NonNull String number)
throws InvalidNumberException
{
if (GroupUtil.isEncodedGroup(number)) return number;
else return canonicalizeNumber(context, number);
}
public static boolean isOwnNumber(Context context, String number) {
try {
String e164number = canonicalizeNumber(context, number);
return TextSecurePreferences.getLocalNumber(context).equals(e164number);
} catch (InvalidNumberException e) {
Log.w(TAG, e);
}
return false;
return TextSecurePreferences.getLocalNumber(context).equals(address.toPhoneString());
}
public static byte[] readFully(InputStream in) throws IOException {

View File

@@ -8,31 +8,32 @@ import android.view.View;
import org.thoughtcrime.securesms.VerifyIdentityActivity;
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.whispersystems.libsignal.IdentityKey;
public class VerifySpan extends ClickableSpan {
private final Context context;
private final long recipientId;
private final Address address;
private final IdentityKey identityKey;
public VerifySpan(@NonNull Context context, @NonNull IdentityKeyMismatch mismatch) {
this.context = context;
this.recipientId = mismatch.getRecipientId();
this.address = mismatch.getAddress();
this.identityKey = mismatch.getIdentityKey();
}
public VerifySpan(@NonNull Context context, long recipientId, @NonNull IdentityKey identityKey) {
public VerifySpan(@NonNull Context context, @NonNull Address address, @NonNull IdentityKey identityKey) {
this.context = context;
this.recipientId = recipientId;
this.address = address;
this.identityKey = identityKey;
}
@Override
public void onClick(View widget) {
Intent intent = new Intent(context, VerifyIdentityActivity.class);
intent.putExtra(VerifyIdentityActivity.RECIPIENT_ID_EXTRA, recipientId);
intent.putExtra(VerifyIdentityActivity.ADDRESS_EXTRA, address);
intent.putExtra(VerifyIdentityActivity.IDENTITY_EXTRA, new IdentityKeyParcelable(identityKey));
intent.putExtra(VerifyIdentityActivity.VERIFIED_EXTRA, false);
context.startActivity(intent);