diff --git a/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java b/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java index d20f2be589..583deb244a 100644 --- a/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java +++ b/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java @@ -7,7 +7,6 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import org.thoughtcrime.securesms.ApplicationContext; -import org.thoughtcrime.securesms.contacts.ContactAccessor; import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData; import org.thoughtcrime.securesms.crypto.ProfileKeyUtil; import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil; @@ -19,6 +18,7 @@ import org.thoughtcrime.securesms.jobmanager.Data; import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; import org.thoughtcrime.securesms.logging.Log; +import org.thoughtcrime.securesms.loki.protocol.SyncMessagesProtocol; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.libsignal.IdentityKey; @@ -33,15 +33,13 @@ import org.whispersystems.signalservice.api.messages.multidevice.DeviceContact; import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsOutputStream; import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage; import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage; -import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.util.InvalidNumberException; -import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus; +import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; @@ -56,57 +54,47 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy private static final long FULL_SYNC_TIME = TimeUnit.HOURS.toMillis(6); private static final String KEY_ADDRESS = "address"; - private static final String KEY_RECIPIENT = "recipient"; private static final String KEY_FORCE_SYNC = "force_sync"; @Inject SignalServiceMessageSender messageSender; private @Nullable String address; - // The recipient of this sync message. If null then we send to all devices - private @Nullable String recipient; - private boolean forceSync; /** - * Create a full contact sync job which syncs across to all other devices + * Create a full contact sync job that syncs to all linked devices. */ public MultiDeviceContactUpdateJob(@NonNull Context context) { this(context, false); } - public MultiDeviceContactUpdateJob(@NonNull Context context, boolean forceSync) { this(context, null, forceSync); } - /** - * Create a full contact sync job which only gets sent to `recipient` - */ - public MultiDeviceContactUpdateJob(@NonNull Context context, @Nullable Address recipient, boolean forceSync) { - this(context, recipient, null, forceSync); + public MultiDeviceContactUpdateJob(@NonNull Context context, boolean forceSync) { + this(context, null, forceSync); } /** - * Create a single contact sync job which syncs across `address` to the all other devices + * Create a single contact sync job that syncs `address` to all linked devices. */ public MultiDeviceContactUpdateJob(@NonNull Context context, @Nullable Address address) { - this(context, null, address, true); + this(context, address, true); } - private MultiDeviceContactUpdateJob(@NonNull Context context, @Nullable Address recipient, @Nullable Address address, boolean forceSync) { + private MultiDeviceContactUpdateJob(@NonNull Context context, @Nullable Address address, boolean forceSync) { this(new Job.Parameters.Builder() .addConstraint(NetworkConstraint.KEY) .setQueue("MultiDeviceContactUpdateJob") .setLifespan(TimeUnit.DAYS.toMillis(1)) .setMaxAttempts(1) .build(), - recipient, address, forceSync); } - private MultiDeviceContactUpdateJob(@NonNull Job.Parameters parameters, @Nullable Address recipient, @Nullable Address address, boolean forceSync) { + private MultiDeviceContactUpdateJob(@NonNull Job.Parameters parameters, @Nullable Address address, boolean forceSync) { super(parameters); this.forceSync = forceSync; - this.recipient = (recipient != null) ? recipient.serialize() : null; if (address != null) this.address = address.serialize(); else this.address = null; @@ -116,7 +104,6 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy public @NonNull Data serialize() { return new Data.Builder().putString(KEY_ADDRESS, address) .putBoolean(KEY_FORCE_SYNC, forceSync) - .putString(KEY_RECIPIENT, recipient) .build(); } @@ -135,14 +122,14 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy } if (address == null) generateFullContactUpdate(); - else if (!address.equals(TextSecurePreferences.getMasterHexEncodedPublicKey(context))) generateSingleContactUpdate(Address.fromSerialized(address)); + else if (!SyncMessagesProtocol.shouldSyncContact(context, Address.fromSerialized(address))) generateSingleContactUpdate(Address.fromSerialized(address)); } private void generateSingleContactUpdate(@NonNull Address address) throws IOException, UntrustedIdentityException, NetworkException { // Loki - Only sync regular contacts - if (!address.isPhone()) { return; } + if (!PublicKeyValidation.isValid(address.serialize())) { return; } File contactDataFile = createTempFile("multidevice-contact-update"); @@ -153,7 +140,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy Optional verifiedMessage = getVerifiedMessage(recipient, identityRecord); // Loki - Only sync contacts we are friends with - if (getFriendRequestStatus(recipient) == LokiThreadFriendRequestStatus.FRIENDS) { + if (SyncMessagesProtocol.shouldSyncContact(context, address)) { out.write(new DeviceContact(address.toPhoneString(), Optional.fromNullable(recipient.getName()), getAvatar(recipient.getContactUri()), @@ -197,7 +184,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy try { DeviceContactsOutputStream out = new DeviceContactsOutputStream(new FileOutputStream(contactDataFile)); - List contacts = getAllContacts(); + List contacts = SyncMessagesProtocol.getContactsToSync(context); for (ContactData contactData : contacts) { Uri contactUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, String.valueOf(contactData.id)); @@ -211,10 +198,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy boolean blocked = recipient.isBlocked(); Optional expireTimer = recipient.getExpireMessages() > 0 ? Optional.of(recipient.getExpireMessages()) : Optional.absent(); - // Loki - Only sync contacts we are friends with - if (getFriendRequestStatus(recipient) == LokiThreadFriendRequestStatus.FRIENDS) { - out.write(new DeviceContact(address.toPhoneString(), name, getAvatar(contactUri), color, verified, profileKey, blocked, expireTimer)); - } + out.write(new DeviceContact(address.toPhoneString(), name, getAvatar(contactUri), color, verified, profileKey, blocked, expireTimer)); } if (ProfileKeyUtil.hasProfileKey(context)) { @@ -235,29 +219,9 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy } } - private List getAllContacts() { - List
contactAddresses = new ArrayList<>(DatabaseFactory.getRecipientDatabase(context).getAllAddresses()); - List contacts = new ArrayList<>(contactAddresses.size()); - for (Address address : contactAddresses) { - if (!address.isPhone()) { continue; } - long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, address, false)); - String name = DatabaseFactory.getLokiUserDatabase(context).getDisplayName(address.serialize()); - ContactData contactData = new ContactData(threadId, name); - contactData.numbers.add(new ContactAccessor.NumberData("TextSecure", address.serialize())); - contacts.add(contactData); - } - return contacts; - } - - private LokiThreadFriendRequestStatus getFriendRequestStatus(Recipient recipient) { - long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(recipient); - return DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadId); - } - @Override public boolean onShouldRetry(@NonNull Exception exception) { - // Loki - Disabled because we have our own retrying - // if (exception instanceof PushNetworkException) return true; + // Loki - Disabled since we have our own retrying return false; } @@ -277,13 +241,10 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy .withLength(contactsFile.length()) .build(); - SignalServiceAddress messageRecipient = recipient != null ? new SignalServiceAddress(recipient) : null; - Address address = recipient != null ? Address.fromSerialized(recipient) : null; - - Optional unidentifiedAccess = address != null ? UnidentifiedAccessUtil.getAccessFor(context, Recipient.from(context, address, false)) : Optional.absent(); + Optional unidentifiedAccess = address != null ? UnidentifiedAccessUtil.getAccessFor(context, Recipient.from(context, Address.fromSerialized(address), false)) : Optional.absent(); try { - messageSender.sendMessage(0, SignalServiceSyncMessage.forContacts(new ContactsMessage(attachmentStream, complete)), unidentifiedAccess, Optional.fromNullable(messageRecipient)); + messageSender.sendMessage(SignalServiceSyncMessage.forContacts(new ContactsMessage(attachmentStream, complete)), unidentifiedAccess); } catch (IOException ioe) { throw new NetworkException(ioe); } @@ -293,7 +254,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy private Optional getAvatar(@Nullable Uri uri) throws IOException { return Optional.absent(); - /* Loki - Disabled until we support custom avatars. This will need to be reworked + /* Loki - Disabled until we support custom profile pictures. This will then need to be reworked. if (uri == null) { return Optional.absent(); } @@ -388,10 +349,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy String serialized = data.getString(KEY_ADDRESS); Address address = serialized != null ? Address.fromSerialized(serialized) : null; - String recipientSerialized = data.getString(KEY_RECIPIENT); - Address recipient = recipientSerialized != null ? Address.fromSerialized(recipientSerialized) : null; - - return new MultiDeviceContactUpdateJob(parameters, recipient, address, data.getBoolean(KEY_FORCE_SYNC)); + return new MultiDeviceContactUpdateJob(parameters, address, data.getBoolean(KEY_FORCE_SYNC)); } } } diff --git a/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt index 4ab38a927f..715479a24f 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt @@ -1,6 +1,15 @@ package org.thoughtcrime.securesms.loki.protocol +import android.content.Context +import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData +import org.thoughtcrime.securesms.contacts.ContactAccessor.NumberData import org.thoughtcrime.securesms.database.Address +import org.thoughtcrime.securesms.database.DatabaseFactory +import org.thoughtcrime.securesms.recipients.Recipient +import org.thoughtcrime.securesms.util.TextSecurePreferences +import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus +import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation +import java.util.* object SyncMessagesProtocol { @@ -8,4 +17,28 @@ object SyncMessagesProtocol { fun shouldSyncReadReceipt(address: Address): Boolean { return !address.isGroup } + + @JvmStatic + fun getContactsToSync(context: Context): List { + val allAddresses = ArrayList(DatabaseFactory.getRecipientDatabase(context).allAddresses) + val result = mutableSetOf() + for (address in allAddresses) { + if (!shouldSyncContact(context, address)) { continue } + val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, address, false)) + val displayName = DatabaseFactory.getLokiUserDatabase(context).getDisplayName(address.serialize()) + val contactData = ContactData(threadID, displayName) + contactData.numbers.add(NumberData("TextSecure", address.serialize())) + result.add(contactData) + } + return result.toList() + } + + @JvmStatic + fun shouldSyncContact(context: Context, address: Address): Boolean { + if (!PublicKeyValidation.isValid(address.serialize())) { return false } + if (address.serialize() == TextSecurePreferences.getMasterHexEncodedPublicKey(context)) { return false } + val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, address, false)) + val isFriend = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS + return isFriend + } } \ No newline at end of file