From ce265f29fd9e8f45b418c302dd9bd2d726899310 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Mon, 4 Nov 2019 16:16:56 +1100 Subject: [PATCH] Handle received contact sync message --- .../securesms/jobs/PushDecryptJob.java | 45 +++++++++++++++++++ .../securesms/loki/MultiDeviceUtilities.kt | 2 +- .../push/MessageSenderEventListener.java | 2 +- .../securesms/sms/MessageSender.java | 21 ++++++--- 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 071e46251d..d556f69499 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -116,6 +116,9 @@ import org.whispersystems.signalservice.api.messages.calls.HangupMessage; import org.whispersystems.signalservice.api.messages.calls.IceUpdateMessage; import org.whispersystems.signalservice.api.messages.calls.OfferMessage; import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage; +import org.whispersystems.signalservice.api.messages.multidevice.ContactsMessage; +import org.whispersystems.signalservice.api.messages.multidevice.DeviceContact; +import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsInputStream; import org.whispersystems.signalservice.api.messages.multidevice.ReadMessage; import org.whispersystems.signalservice.api.messages.multidevice.RequestMessage; import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage; @@ -135,6 +138,7 @@ import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestSt import org.whispersystems.signalservice.loki.messaging.LokiThreadSessionResetStatus; import org.whispersystems.signalservice.loki.utilities.PromiseUtil; +import java.io.IOException; import java.security.MessageDigest; import java.security.SecureRandom; import java.util.ArrayList; @@ -352,6 +356,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { else if (syncMessage.getRead().isPresent()) handleSynchronizeReadMessage(syncMessage.getRead().get(), content.getTimestamp()); else if (syncMessage.getVerified().isPresent()) handleSynchronizeVerifiedMessage(syncMessage.getVerified().get()); else if (syncMessage.getStickerPackOperations().isPresent()) handleSynchronizeStickerPackOperation(syncMessage.getStickerPackOperations().get()); + else if (syncMessage.getContacts().isPresent()) handleSynchronizeContactMessage(syncMessage.getContacts().get()); else Log.w(TAG, "Contains no known sync types..."); } else if (content.getCallMessage().isPresent()) { Log.i(TAG, "Got call message..."); @@ -641,6 +646,46 @@ public class PushDecryptJob extends BaseJob implements InjectableType { } } + private void handleSynchronizeContactMessage(@NonNull ContactsMessage contactsMessage) { + if (contactsMessage.getContactsStream().isStream()) { + try { + DeviceContactsInputStream contactsInputStream = new DeviceContactsInputStream(contactsMessage.getContactsStream().asStream().getInputStream()); + DeviceContact deviceContact = contactsInputStream.read(); + while (deviceContact != null) { + // Check if we have the contact as a friend + Address address = Address.fromSerialized(deviceContact.getNumber()); + if (!address.isPhone()) { continue; } + + /* + If we're not friends with the contact we received or our friend request expired then we should send them a friend request + otherwise if we have received a friend request with from them then we should automatically accept the friend request + */ + Recipient recipient = Recipient.from(context, address, false); + long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient); + LokiThreadFriendRequestStatus status = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadId); + if (status == LokiThreadFriendRequestStatus.NONE || status == LokiThreadFriendRequestStatus.REQUEST_EXPIRED) { + MessageSender.sendBackgroundFriendRequest(context, deviceContact.getNumber(), "This is an automated friend request. Still under testing!"); + } else if (status == LokiThreadFriendRequestStatus.REQUEST_RECEIVED) { + // Accept the incoming friend request + becomeFriendsWithContact(deviceContact.getNumber()); + } + + // TODO: Handle blocked - If user is not blocked then we should do the friend request logic otherwise add them to our block list + // TODO: Handle expiration timer - Update expiration timer? + // TODO: Handle avatar - Download and set avatar? + + // Read the next contact + deviceContact = contactsInputStream.read(); + } + } catch (IOException e) { + // Exception is thrown when we don't have any more contacts to read from + } catch (Exception e) { + Log.d("Loki", "Failed to sync contact: " + e.getMessage()); + } + } + + } + private void handleSynchronizeSentMessage(@NonNull SignalServiceContent content, @NonNull SentTranscriptMessage message) throws StorageFailedException diff --git a/src/org/thoughtcrime/securesms/loki/MultiDeviceUtilities.kt b/src/org/thoughtcrime/securesms/loki/MultiDeviceUtilities.kt index 7f3883e73c..5b471a42bb 100644 --- a/src/org/thoughtcrime/securesms/loki/MultiDeviceUtilities.kt +++ b/src/org/thoughtcrime/securesms/loki/MultiDeviceUtilities.kt @@ -82,7 +82,7 @@ fun shouldAutomaticallyBecomeFriendsWithDevice(publicKey: String, context: Conte fun sendPairingAuthorisationMessage(context: Context, contactHexEncodedPublicKey: String, authorisation: PairingAuthorisation): Promise { val messageSender = ApplicationContext.getInstance(context).communicationModule.provideSignalMessageSender() val address = SignalServiceAddress(contactHexEncodedPublicKey) - val message = SignalServiceDataMessage.newBuilder().withBody("").withPairingAuthorisation(authorisation) + val message = SignalServiceDataMessage.newBuilder().withBody(null).withPairingAuthorisation(authorisation) // A REQUEST should always act as a friend request. A GRANT should always be replying back as a normal message. if (authorisation.type == PairingAuthorisation.Type.REQUEST) { val preKeyBundle = DatabaseFactory.getLokiPreKeyBundleDatabase(context).generatePreKeyBundle(address.number) diff --git a/src/org/thoughtcrime/securesms/push/MessageSenderEventListener.java b/src/org/thoughtcrime/securesms/push/MessageSenderEventListener.java index cca8b0b7b1..6b492be25e 100644 --- a/src/org/thoughtcrime/securesms/push/MessageSenderEventListener.java +++ b/src/org/thoughtcrime/securesms/push/MessageSenderEventListener.java @@ -26,7 +26,7 @@ public class MessageSenderEventListener implements SignalServiceMessageSender.Ev @Override public void onSyncEvent(long messageID, long timestamp, byte[] message, int ttl) { - if (messageID > 0 && timestamp > 0 && message != null && ttl > 0) { + if (messageID >= 0 && timestamp > 0 && message != null && ttl > 0) { MessageSender.sendSyncMessageToOurDevices(context, messageID, timestamp, message, ttl); } } diff --git a/src/org/thoughtcrime/securesms/sms/MessageSender.java b/src/org/thoughtcrime/securesms/sms/MessageSender.java index 4b4726f4df..64653eb88d 100644 --- a/src/org/thoughtcrime/securesms/sms/MessageSender.java +++ b/src/org/thoughtcrime/securesms/sms/MessageSender.java @@ -55,6 +55,7 @@ import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.service.ExpiringMessageManager; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; +import org.whispersystems.libsignal.state.PreKeyBundle; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.SignalServiceMessageSender; @@ -120,18 +121,28 @@ public class MessageSender { } public static void sendBackgroundMessage(Context context, String contactHexEncodedPublicKey) { - sendMessageWithBody(context, contactHexEncodedPublicKey, null); + SignalServiceDataMessage message = new SignalServiceDataMessage(System.currentTimeMillis(), null); + sendMessage(context, contactHexEncodedPublicKey, message); } - public static void sendMessageWithBody(Context context, String contactHexEncodedPublicKey, @Nullable String messageBody) { + public static void sendBackgroundFriendRequest(Context context, String contactHexEncodedPublicKey, String messageBody) { + PreKeyBundle bundle = DatabaseFactory.getLokiPreKeyBundleDatabase(context).generatePreKeyBundle(contactHexEncodedPublicKey); + SignalServiceDataMessage message = SignalServiceDataMessage.newBuilder() + .withTimestamp(System.currentTimeMillis()) + .withBody(messageBody) + .asFriendRequest(true) + .withPreKeyBundle(bundle) + .build(); + sendMessage(context, contactHexEncodedPublicKey, message); + } + + private static void sendMessage(Context context, String contactHexEncodedPublicKey, SignalServiceDataMessage message) { Util.runOnMain(() -> { SignalServiceMessageSender messageSender = ApplicationContext.getInstance(context).communicationModule.provideSignalMessageSender(); SignalServiceAddress address = new SignalServiceAddress(contactHexEncodedPublicKey); - String body = (messageBody == null || messageBody.isEmpty()) ? null : messageBody; - SignalServiceDataMessage message = new SignalServiceDataMessage(System.currentTimeMillis(), body); try { // Try send to the original person - messageSender.sendMessage(0, address, Optional.absent(), message); // The message ID doesn't matter + messageSender.sendMessage(-1, address, Optional.absent(), message); // The message ID doesn't matter } catch (Exception e) { Log.d("Loki", "Failed to send background message to: " + contactHexEncodedPublicKey + "."); }