Cleanup code.

This commit is contained in:
Mikunj 2019-10-30 09:59:11 +11:00
parent 3298d665e9
commit 7ff7c36e27
11 changed files with 156 additions and 287 deletions

View File

@ -44,7 +44,7 @@ import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.loki.DeviceLinkingDialog;
import org.thoughtcrime.securesms.loki.DeviceLinkingDialogDelegate;
import org.thoughtcrime.securesms.loki.DeviceLinkingView;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
import org.thoughtcrime.securesms.loki.QRCodeDialog;
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
import org.thoughtcrime.securesms.preferences.ChatsPreferenceFragment;
@ -394,7 +394,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
}
@Override public void sendPairingAuthorizedMessage(@NotNull PairingAuthorisation pairingAuthorisation) {
MultiDeviceUtilitiesKt.signAndSendPairingAuthorisationMessage(context, pairingAuthorisation);
MultiDeviceUtilities.signAndSendPairingAuthorisationMessage(context, pairingAuthorisation);
}
@Override public void handleDeviceLinkAuthorized(@NotNull PairingAuthorisation pairingAuthorisation) {}
@Override public void handleDeviceLinkingDialogDismissed() {}

View File

@ -9,13 +9,14 @@ import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.jobs.TypingSendJob;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.signalservice.loki.api.LokiStorageAPI;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import kotlin.Unit;
@ -91,14 +92,14 @@ public class TypingStatusSender {
return;
}
MultiDeviceUtilitiesKt.getAllDevicePublicKeys(context, recipient.getAddress().serialize(), storageAPI, (devicePublicKey, isFriend, friendCount) -> {
Recipient device = Recipient.from(context, Address.fromSerialized(devicePublicKey), false);
long deviceThreadID = threadDatabase.getThreadIdIfExistsFor(device);
Set<String> devices = LokiStorageAPI.shared.getAllDevicePublicKeys(recipient.getAddress().serialize());
for (String device : devices) {
Recipient deviceRecipient = Recipient.from(context, Address.fromSerialized(device), false);
long deviceThreadID = threadDatabase.getThreadIdIfExistsFor(deviceRecipient);
if (deviceThreadID > -1) {
ApplicationContext.getInstance(context).getJobManager().add(new TypingSendJob(deviceThreadID, typingStarted));
}
return Unit.INSTANCE;
});
}
}
private class StartRunnable implements Runnable {

View File

@ -38,7 +38,6 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Vibrator;
import android.provider.Browser;
import android.provider.ContactsContract;
@ -128,7 +127,6 @@ import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher;
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
import org.thoughtcrime.securesms.crypto.SecurityEvent;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.Database;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.DraftDatabase;
import org.thoughtcrime.securesms.database.DraftDatabase.Draft;
@ -163,7 +161,7 @@ import org.thoughtcrime.securesms.loki.LokiMessageDatabase;
import org.thoughtcrime.securesms.loki.LokiThreadDatabaseDelegate;
import org.thoughtcrime.securesms.loki.LokiUserDatabase;
import org.thoughtcrime.securesms.loki.MentionCandidateSelectionView;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
import org.thoughtcrime.securesms.mediasend.Media;
import org.thoughtcrime.securesms.mediasend.MediaSendActivity;
import org.thoughtcrime.securesms.mms.AttachmentManager;
@ -228,9 +226,6 @@ import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
import org.thoughtcrime.securesms.util.views.Stub;
import org.whispersystems.libsignal.InvalidMessageException;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.loki.api.LokiAPI;
import org.whispersystems.signalservice.loki.api.LokiStorageAPI;
import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestStatus;
@ -246,6 +241,7 @@ import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
@ -2195,7 +2191,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
Recipient threadRecipient = DatabaseFactory.getThreadDatabase(this).getRecipientForThreadId(threadID);
if (threadRecipient != null && !threadRecipient.isGroupRecipient()) {
// We should update our input if this thread is a part of the other threads device
Set<String> devices = MultiDeviceUtilitiesKt.getAllDevicePublicKeys(threadRecipient.getAddress().serialize(), LokiStorageAPI.Companion.getShared());
Set<String> devices = LokiStorageAPI.shared.getAllDevicePublicKeys(threadRecipient.getAddress().serialize());
shouldUpdateInputPanel = devices.contains(recipient.getAddress().serialize());
} else {
shouldUpdateInputPanel = false;
@ -2216,13 +2212,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
inputMethodManager.showSoftInput(inputPanel.composeText, 0);
}
boolean hasPendingFriendRequest = !recipient.isGroupRecipient() && hasPendingFriendRequestWithAnyLinkedDevice();
boolean isFriendsWithAnyLinkedDevices = MultiDeviceUtilitiesKt.isFriendsWithAnyLinkedDevice(this, recipient);
boolean isFriendsWithAnyLinkedDevices = MultiDeviceUtilities.isFriendsWithAnyLinkedDevice(this, recipient);
boolean shouldEnableInput = isFriendsWithAnyLinkedDevices || !hasPendingFriendRequest;
updateToggleButtonState();
inputPanel.setEnabled(shouldEnableInput);
int hintID = shouldEnableInput ? R.string.activity_conversation_default_hint : R.string.activity_conversation_pending_friend_request_hint;
inputPanel.setHint(getResources().getString(hintID));
if (!shouldEnableInput) {
if (shouldEnableInput) {
inputPanel.composeText.requestFocus();
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
inputMethodManager.showSoftInput(inputPanel.composeText, 0);
@ -3050,31 +3046,15 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
public boolean hasPendingFriendRequestWithAnyLinkedDevice() {
if (recipient.isGroupRecipient()) return false;
SettableFuture<Boolean> future = new SettableFuture<>();
LokiStorageAPI storageAPI = LokiStorageAPI.Companion.getShared();
MultiDeviceUtilitiesKt.getAllDeviceFriendRequestStatus(this, recipient.getAddress().serialize(), storageAPI).success(map -> {
for (LokiThreadFriendRequestStatus status : map.values()) {
// Break out of the loop as soon as one of the device has a pending friend request
if (status == LokiThreadFriendRequestStatus.REQUEST_SENDING || status == LokiThreadFriendRequestStatus.REQUEST_SENT || status == LokiThreadFriendRequestStatus.REQUEST_RECEIVED) {
future.set(true);
break;
}
Map<String, LokiThreadFriendRequestStatus> map = MultiDeviceUtilities.getAllDeviceFriendRequestStatuses(this, recipient.getAddress().serialize());
for (LokiThreadFriendRequestStatus status : map.values()) {
if (status == LokiThreadFriendRequestStatus.REQUEST_SENDING || status == LokiThreadFriendRequestStatus.REQUEST_SENT || status == LokiThreadFriendRequestStatus.REQUEST_RECEIVED) {
return true;
}
// If we reached this and we haven't set anything on the future then it means that we don't have a pending request
if (!future.isDone()) { future.set(false); }
return Unit.INSTANCE;
}).fail(e -> {
future.set(false);
return Unit.INSTANCE;
});
try {
return future.get();
} catch (Exception e) {
return false;
}
return false;
}
// endregion
}

View File

@ -61,7 +61,7 @@ public class Address implements Parcelable, Comparable<Address> {
private Address(@NonNull String address, Boolean isPublicChat) {
if (address == null) throw new AssertionError(address);
this.address = address;
this.address = address.toLowerCase();
this.isPublicChat = isPublicChat;
}

View File

@ -72,7 +72,7 @@ import org.thoughtcrime.securesms.loki.LokiMessageDatabase;
import org.thoughtcrime.securesms.loki.LokiPreKeyBundleDatabase;
import org.thoughtcrime.securesms.loki.LokiPreKeyRecordDatabase;
import org.thoughtcrime.securesms.loki.LokiThreadDatabase;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
@ -780,11 +780,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
return;
}
// Don't insert friend request if we're already friends with a one of the users other device
if (message.isFriendRequest() && MultiDeviceUtilitiesKt.isFriendsWithAnyLinkedDevice(context, primaryDeviceRecipient)) {
return;
}
Optional<InsertResult> insertResult;
try {
@ -828,8 +823,8 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
}
private long handleSynchronizeSentExpirationUpdate(@NonNull SentTranscriptMessage message) throws MmsException {
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
Recipient recipient = getSyncMessagePrimaryDestination(message);
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
Recipient recipient = getSyncMessagePrimaryDestination(message);
OutgoingExpirationUpdateMessage expirationUpdateMessage = new OutgoingExpirationUpdateMessage(recipient,
message.getTimestamp(),
@ -1099,7 +1094,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
// it must be a friend request accepted message. Declining a friend request doesn't send a message.
lokiThreadDatabase.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.FRIENDS);
// Update the last message if needed
String primaryDevice = MultiDeviceUtilitiesKt.getPrimaryDevicePublicKey(pubKey);
String primaryDevice = LokiStorageAPI.shared.getPrimaryDevicePublicKey(pubKey);
long primaryDeviceThreadID = primaryDevice == null ? threadID : DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, Address.fromSerialized(primaryDevice), false));
FriendRequestHandler.updateLastFriendRequestMessage(context, primaryDeviceThreadID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED);
}
@ -1107,7 +1102,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
private void updateFriendRequestStatusIfNeeded(@NonNull SignalServiceEnvelope envelope, @NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message) {
if (!envelope.isFriendRequest()) { return; }
// This handles the case where another user sends us a regular message without authorisation
boolean shouldBecomeFriends = MultiDeviceUtilitiesKt.shouldAutomaticallyBecomeFriendsWithDevice(content.getSender(), context);
boolean shouldBecomeFriends = MultiDeviceUtilities.shouldAutomaticallyBecomeFriendsWithDevice(content.getSender(), context);
if (shouldBecomeFriends) {
// Become friends AND update the message they sent
becomeFriendsWithContact(content.getSender());
@ -1536,26 +1531,15 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
}
private Recipient getPrimaryDeviceRecipient(String recipient) {
SettableFuture<String> device = new SettableFuture<>();
// Get the primary device
LokiStorageAPI.shared.getPrimaryDevicePublicKey(recipient).success(primaryDevice -> {
try {
String primaryDevice = LokiStorageAPI.shared.getPrimaryDevicePublicKey(recipient);
String publicKey = (primaryDevice != null) ? primaryDevice : recipient;
// If our the public key matches our primary device then we need to forward the message to ourselves (Note to self)
// If the public key matches our primary device then we need to forward the message to ourselves (Note to self)
String ourPrimaryDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
if (ourPrimaryDevice != null && ourPrimaryDevice.equals(publicKey)) {
publicKey = TextSecurePreferences.getLocalNumber(context);
}
device.set(publicKey);
return Unit.INSTANCE;
}).fail(exception -> {
device.set(recipient);
return Unit.INSTANCE;
});
try {
String primarySender = device.get();
return Recipient.from(context, Address.fromSerialized(primarySender), false);
return Recipient.from(context, Address.fromSerialized(publicKey), false);
} catch (Exception e) {
Log.d("Loki", "Failed to get primary device public key for message. " + e.getMessage());
return Recipient.from(context, Address.fromSerialized(recipient), false);
@ -1610,7 +1594,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
return sender.isBlocked();
} else if (content.getSyncMessage().isPresent()) {
// We should ignore a sync message if the sender is not one of our devices
boolean isOurDevice = MultiDeviceUtilitiesKt.isOneOfOurDevices(context, sender.getAddress());
boolean isOurDevice = MultiDeviceUtilities.isOneOfOurDevices(context, sender.getAddress());
if (!isOurDevice) { Log.w(TAG, "Got a sync message from a device that is not ours!."); }
return !isOurDevice;
}

View File

@ -22,7 +22,7 @@ import org.thoughtcrime.securesms.jobmanager.Data;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.JobManager;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.recipients.Recipient;
@ -43,6 +43,7 @@ import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSy
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
import org.whispersystems.signalservice.loki.api.LokiStorageAPI;
import org.whispersystems.signalservice.loki.messaging.LokiSyncMessage;
import java.io.FileNotFoundException;
@ -280,7 +281,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
LokiSyncMessage syncMessage = null;
if (shouldSendSyncMessage) {
// Set the sync message destination the primary device, this way it will show that we sent a message to the primary device and not a secondary device
String primaryDevice = MultiDeviceUtilitiesKt.getPrimaryDevicePublicKey(address.getNumber());
String primaryDevice = LokiStorageAPI.shared.getPrimaryDevicePublicKey(address.getNumber());
SignalServiceAddress primaryAddress = primaryDevice == null ? address : new SignalServiceAddress(primaryDevice);
// We also need to use the original message id and not -1
syncMessage = new LokiSyncMessage(primaryAddress, templateMessageId);

View File

@ -14,7 +14,7 @@ import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.jobmanager.Data;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
@ -30,6 +30,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
import org.whispersystems.signalservice.loki.api.LokiStorageAPI;
import org.whispersystems.signalservice.loki.messaging.LokiSyncMessage;
import java.io.IOException;
@ -231,7 +232,7 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
LokiSyncMessage syncMessage = null;
if (shouldSendSyncMessage) {
// Set the sync message destination to the primary device, this way it will show that we sent a message to the primary device and not a secondary device
String primaryDevice = MultiDeviceUtilitiesKt.getPrimaryDevicePublicKey(address.getNumber());
String primaryDevice = LokiStorageAPI.shared.getPrimaryDevicePublicKey(address.getNumber());
SignalServiceAddress primaryAddress = primaryDevice == null ? address : new SignalServiceAddress(primaryDevice);
// We also need to use the original message id and not -1
syncMessage = new LokiSyncMessage(primaryAddress, templateMessageId);

View File

@ -10,7 +10,7 @@ import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.jobmanager.Data;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@ -98,7 +98,7 @@ public class TypingSendJob extends BaseJob implements InjectableType {
SignalServiceTypingMessage typingMessage = new SignalServiceTypingMessage(typing ? Action.STARTED : Action.STOPPED, System.currentTimeMillis(), groupId);
// Loki - Don't send typing indicators in group chats or to ourselves
if (!recipient.isGroupRecipient() && !MultiDeviceUtilitiesKt.isOneOfOurDevices(context, recipient.getAddress())) {
if (!recipient.isGroupRecipient() && !MultiDeviceUtilities.isOneOfOurDevices(context, recipient.getAddress())) {
messageSender.sendTyping(0, addresses, unidentifiedAccess, typingMessage);
}
}

View File

@ -1,11 +1,9 @@
@file:JvmName("MultiDeviceUtilities")
package org.thoughtcrime.securesms.loki
import android.content.Context
import android.os.Handler
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.deferred
import nl.komponents.kovenant.functional.bind
import nl.komponents.kovenant.functional.map
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.database.Address
@ -13,7 +11,6 @@ import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.logging.Log
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.concurrent.SettableFuture
import org.whispersystems.libsignal.util.guava.Optional
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage
@ -23,85 +20,53 @@ import org.whispersystems.signalservice.loki.api.PairingAuthorisation
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus
import org.whispersystems.signalservice.loki.utilities.retryIfNeeded
fun getAllDeviceFriendRequestStatus(context: Context, hexEncodedPublicKey: String, storageAPI: LokiStorageAPI): Promise<Map<String, LokiThreadFriendRequestStatus>, Exception> {
fun getAllDeviceFriendRequestStatuses(context: Context, hexEncodedPublicKey: String): Map<String, LokiThreadFriendRequestStatus> {
val lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context)
return storageAPI.getAllDevicePublicKeys(hexEncodedPublicKey).map { keys ->
val map = mutableMapOf<String, LokiThreadFriendRequestStatus>()
for (devicePublicKey in keys) {
val device = Recipient.from(context, Address.fromSerialized(devicePublicKey), false)
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(device)
val friendRequestStatus = if (threadID < 0) LokiThreadFriendRequestStatus.NONE else lokiThreadDatabase.getFriendRequestStatus(threadID)
map.put(devicePublicKey, friendRequestStatus);
}
map
val keys = LokiStorageAPI.shared.getAllDevicePublicKeys(hexEncodedPublicKey)
val map = mutableMapOf<String, LokiThreadFriendRequestStatus>()
for (devicePublicKey in keys) {
val device = Recipient.from(context, Address.fromSerialized(devicePublicKey), false)
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(device)
val friendRequestStatus = if (threadID < 0) LokiThreadFriendRequestStatus.NONE else lokiThreadDatabase.getFriendRequestStatus(threadID)
map[devicePublicKey] = friendRequestStatus
}
return map
}
fun getAllDevicePublicKeys(context: Context, hexEncodedPublicKey: String, storageAPI: LokiStorageAPI, block: (devicePublicKey: String, isFriend: Boolean, friendCount: Int) -> Unit) {
fun getAllDevicePublicKeysWithFriendStatus(context: Context, hexEncodedPublicKey: String): Map<String, Boolean> {
val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context)
val devices = getAllDevicePublicKeys(hexEncodedPublicKey, storageAPI).toMutableSet()
val devices = LokiStorageAPI.shared.getAllDevicePublicKeys(hexEncodedPublicKey).toMutableSet()
if (hexEncodedPublicKey != userHexEncodedPublicKey) {
devices.remove(userHexEncodedPublicKey)
}
val friends = getFriendPublicKeys(context, devices)
val map = mutableMapOf<String, Boolean>()
for (device in devices) {
block(device, friends.contains(device), friends.count())
map[device] = friends.contains(device)
}
return map
}
fun getAllDevicePublicKeys(hexEncodedPublicKey: String, storageAPI: LokiStorageAPI): Set<String> {
val future = SettableFuture<Set<String>>()
storageAPI.getAllDevicePublicKeys(hexEncodedPublicKey).success { future.set(it) }.fail { future.setException(it) }
return try {
future.get()
} catch (e: Exception) {
setOf()
}
fun getFriendCount(context: Context, devices: Set<String>): Int {
return getFriendPublicKeys(context, devices).count()
}
fun shouldAutomaticallyBecomeFriendsWithDevice(publicKey: String, context: Context): Boolean {
val lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context)
val storageAPI = LokiStorageAPI.shared
val future = SettableFuture<Boolean>()
storageAPI.getPrimaryDevicePublicKey(publicKey).success { primaryDevicePublicKey ->
if (primaryDevicePublicKey == null) {
// If the public key doesn't have any other devices then go through regular friend request logic
future.set(false)
return@success
}
// If we are the primary device and the public key is our secondary device then we should become friends
val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context)
if (primaryDevicePublicKey == userHexEncodedPublicKey) {
storageAPI.getSecondaryDevicePublicKeys(userHexEncodedPublicKey).success { secondaryDevices ->
future.set(secondaryDevices.contains(publicKey))
}.fail {
future.set(false)
}
return@success
}
// If we share the same primary device then we should become friends
val ourPrimaryDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context)
if (ourPrimaryDevice != null && ourPrimaryDevice == primaryDevicePublicKey) {
future.set(true)
return@success
}
// If we are friends with the primary device then we should become friends
val primaryDevice = Recipient.from(context, Address.fromSerialized(primaryDevicePublicKey), false)
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(primaryDevice)
if (threadID < 0) {
future.set(false)
return@success
}
future.set(lokiThreadDatabase.getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS)
// If the public key doesn't have any other devices then go through regular friend request logic
val primaryDevicePublicKey = storageAPI.getPrimaryDevicePublicKey(publicKey) ?: return false
// If this is one of our devices then we should become friends
if (isOneOfOurDevices(context, publicKey)) {
return true
}
return try {
future.get()
} catch (e: Exception) {
false
}
// If we are friends with the primary device then we should become friends
val primaryDevice = Recipient.from(context, Address.fromSerialized(primaryDevicePublicKey), false)
val primaryDeviceThreadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(primaryDevice)
return primaryDeviceThreadID >= 0 && lokiThreadDatabase.getFriendRequestStatus(primaryDeviceThreadID) == LokiThreadFriendRequestStatus.FRIENDS
}
fun sendPairingAuthorisationMessage(context: Context, contactHexEncodedPublicKey: String, authorisation: PairingAuthorisation): Promise<Unit, Exception> {
@ -157,27 +122,12 @@ fun shouldSendSycMessage(context: Context, address: Address): Boolean {
return false
}
// Don't send sync messages if it's our address
val publicKey = address.serialize()
if (publicKey == TextSecurePreferences.getLocalNumber(context)) {
return false
}
// Don't send sync messages if it's one of our devices
return !isOneOfOurDevices(context, address)
}
val storageAPI = LokiStorageAPI.shared
val future = SettableFuture<Boolean>()
storageAPI.getPrimaryDevicePublicKey(publicKey).success { primaryDevicePublicKey ->
val isOurPrimaryDevice = primaryDevicePublicKey != null && TextSecurePreferences.getMasterHexEncodedPublicKey(context) == publicKey
// Don't send sync message if the primary device is the same as ours
future.set(!isOurPrimaryDevice)
}.fail {
future.set(false)
}
return try {
future.get()
} catch (e: Exception) {
false
}
fun isOneOfOurDevices(context: Context, publicKey: String): Boolean {
return isOneOfOurDevices(context, Address.fromSerialized(publicKey))
}
fun isOneOfOurDevices(context: Context, address: Address): Boolean {
@ -186,61 +136,18 @@ fun isOneOfOurDevices(context: Context, address: Address): Boolean {
}
val ourPublicKey = TextSecurePreferences.getLocalNumber(context)
val storageAPI = LokiStorageAPI.shared
val future = SettableFuture<Boolean>()
storageAPI.getAllDevicePublicKeys(ourPublicKey).success {
future.set(it.contains(address.serialize()))
}.fail {
future.set(false)
}
return try {
future.get()
} catch (e: Exception) {
false
}
}
fun getPrimaryDevicePublicKey(hexEncodedPublicKey: String): String? {
val storageAPI = LokiStorageAPI.shared
val future = SettableFuture<String?>()
storageAPI.getPrimaryDevicePublicKey(hexEncodedPublicKey).success {
future.set(it)
}.fail {
future.set(null)
}
return try {
future.get()
} catch (e: Exception) {
null
}
val devices = LokiStorageAPI.shared.getAllDevicePublicKeys(ourPublicKey)
return devices.contains(address.serialize())
}
fun isFriendsWithAnyLinkedDevice(context: Context, recipient: Recipient): Boolean {
if (recipient.isGroupRecipient) return true
val future = SettableFuture<Boolean>()
val storageAPI = LokiStorageAPI.shared
getAllDeviceFriendRequestStatus(context, recipient.address.serialize(), storageAPI).success { map ->
for (status in map.values) {
if (status == LokiThreadFriendRequestStatus.FRIENDS) {
future.set(true)
break
}
val map = getAllDeviceFriendRequestStatuses(context, recipient.address.serialize())
for (status in map.values) {
if (status == LokiThreadFriendRequestStatus.FRIENDS) {
return true
}
if (!future.isDone) {
future.set(false)
}
}.fail { e ->
future.set(false)
}
try {
return future.get()
} catch (e: Exception) {
return false
}
return false
}

View File

@ -20,7 +20,7 @@ import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
import org.thoughtcrime.securesms.jobs.MultiDeviceReadUpdateJob;
import org.thoughtcrime.securesms.jobs.SendReadReceiptJob;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.whispersystems.signalservice.loki.api.LokiStorageAPI;
@ -90,17 +90,17 @@ public class MarkReadReceiver extends BroadcastReceiver {
.collect(Collectors.groupingBy(SyncMessageId::getAddress));
for (Address address : addressMap.keySet()) {
LokiStorageAPI storageAPI = LokiStorageAPI.Companion.getShared();
List<Long> timestamps = Stream.of(addressMap.get(address)).map(SyncMessageId::getTimetamp).toList();
MultiDeviceUtilitiesKt.getAllDevicePublicKeys(context, address.serialize(), storageAPI, (devicePublicKey, isFriend, friendCount) -> {
Map<String, Boolean> devices = MultiDeviceUtilities.getAllDevicePublicKeysWithFriendStatus(context, address.serialize());
for (Map.Entry<String, Boolean> entry : devices.entrySet()) {
String device = entry.getKey();
boolean isFriend = entry.getValue();
// Loki - This also prevents read receipts from being sent in group chats as they don't maintain a friend request status
if (isFriend) {
ApplicationContext.getInstance(context).getJobManager().add(new SendReadReceiptJob(Address.fromSerialized(devicePublicKey), timestamps));
ApplicationContext.getInstance(context).getJobManager().add(new SendReadReceiptJob(Address.fromSerialized(device), timestamps));
}
return Unit.INSTANCE;
});
}
}
}

View File

@ -44,7 +44,7 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.FriendRequestHandler;
import org.thoughtcrime.securesms.loki.GeneralUtilitiesKt;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt;
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
import org.thoughtcrime.securesms.loki.PushMessageSyncSendJob;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
@ -63,6 +63,8 @@ import org.whispersystems.signalservice.loki.api.LokiStorageAPI;
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import kotlin.Unit;
@ -75,24 +77,20 @@ public class MessageSender {
sendBackgroundMessage(context, contactHexEncodedPublicKey);
// Go through the other devices and only send background messages if we're friends or we have received friend request
LokiStorageAPI storageAPI = LokiStorageAPI.Companion.getShared();
storageAPI.getAllDevicePublicKeys(contactHexEncodedPublicKey).success(devices -> {
for (String device : devices) {
// Don't send message to the device we already have sent to
if (device.equals(contactHexEncodedPublicKey)) { continue; }
Recipient recipient = Recipient.from(context, Address.fromSerialized(device), false);
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(recipient);
if (threadID < 0) { continue; }
LokiThreadFriendRequestStatus friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID);
if (friendRequestStatus == LokiThreadFriendRequestStatus.FRIENDS || friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_RECEIVED) {
sendBackgroundMessage(context, device);
}
// TODO: Do we want to send a custom FR Message if we're not friends and we haven't received a friend request?
Set<String> devices = LokiStorageAPI.shared.getAllDevicePublicKeys(contactHexEncodedPublicKey);
for (String device : devices) {
// Don't send message to the device we already have sent to
if (device.equals(contactHexEncodedPublicKey)) { continue; }
Recipient recipient = Recipient.from(context, Address.fromSerialized(device), false);
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(recipient);
if (threadID < 0) { continue; }
LokiThreadFriendRequestStatus friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID);
if (friendRequestStatus == LokiThreadFriendRequestStatus.FRIENDS || friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_RECEIVED) {
sendBackgroundMessage(context, device);
}
return Unit.INSTANCE;
});
// TODO: Do we want to send a custom FR Message if we're not friends and we haven't received a friend request?
}
}
public static void sendBackgroundMessage(Context context, String contactHexEncodedPublicKey) {
@ -198,20 +196,16 @@ public class MessageSender {
final byte[] message,
final int ttl) {
String ourPublicKey = TextSecurePreferences.getLocalNumber(context);
LokiStorageAPI storageAPI = LokiStorageAPI.Companion.getShared();
JobManager jobManager = ApplicationContext.getInstance(context).getJobManager();
Set<String> devices = LokiStorageAPI.shared.getAllDevicePublicKeys(ourPublicKey);
for (String device : devices) {
// Don't send to ourselves
if (device.equals(ourPublicKey)) { continue; }
storageAPI.getAllDevicePublicKeys(ourPublicKey).success(devices -> {
for (String device : devices) {
// Don't send to ourselves
if (device.equals(ourPublicKey)) { continue; }
// Create a send job for our device
Address address = Address.fromSerialized(device);
jobManager.add(new PushMessageSyncSendJob(messageID, address, timestamp, message, ttl));
}
return Unit.INSTANCE;
});
// Create a send job for our device
Address address = Address.fromSerialized(device);
jobManager.add(new PushMessageSyncSendJob(messageID, address, timestamp, message, ttl));
}
}
public static void resendGroupMessage(Context context, MessageRecord messageRecord, Address filterAddress) {
@ -260,7 +254,6 @@ public class MessageSender {
}
private static void sendTextPush(Context context, Recipient recipient, long messageId) {
LokiStorageAPI storageAPI = LokiStorageAPI.Companion.getShared();
JobManager jobManager = ApplicationContext.getInstance(context).getJobManager();
// Just send the message normally if it's a group message
@ -271,39 +264,40 @@ public class MessageSender {
}
// Note to self
boolean isNoteToSelf = MultiDeviceUtilitiesKt.isOneOfOurDevices(context, recipient.getAddress());
boolean isNoteToSelf = MultiDeviceUtilities.isOneOfOurDevices(context, recipient.getAddress());
if (isNoteToSelf) {
jobManager.add(new PushTextSendJob(messageId, recipient.getAddress()));
return;
}
boolean[] hasSentSyncMessage = { false };
boolean hasSentSyncMessage = false;
MultiDeviceUtilitiesKt.getAllDevicePublicKeys(context, recipientPublicKey, storageAPI, (devicePublicKey, isFriend, friendCount) -> {
Util.runOnMain(() -> {
Address address = Address.fromSerialized(devicePublicKey);
long messageIDToUse = recipientPublicKey.equals(devicePublicKey) ? messageId : -1L;
Map<String, Boolean> devices = MultiDeviceUtilities.getAllDevicePublicKeysWithFriendStatus(context, recipientPublicKey);
int friendCount = MultiDeviceUtilities.getFriendCount(context, devices.keySet());
for (Map.Entry<String, Boolean> entry : devices.entrySet()) {
String devicePublicKey = entry.getKey();
boolean isFriend = entry.getValue();
if (isFriend) {
// Send a normal message if the user is friends with the recipient
// We should also send a sync message if we haven't already sent one
boolean shouldSendSyncMessage = !hasSentSyncMessage[0] && MultiDeviceUtilitiesKt.shouldSendSycMessage(context, address);
jobManager.add(new PushTextSendJob(messageId, messageIDToUse, address, shouldSendSyncMessage));
hasSentSyncMessage[0] = shouldSendSyncMessage;
} else {
// Send friend requests to non friends. If the user is friends with any
// of the devices then send out a default friend request message.
boolean isFriendsWithAny = (friendCount > 0);
String defaultFriendRequestMessage = isFriendsWithAny ? "Accept this friend request to enable messages to be synced across devices" : null;
jobManager.add(new PushTextSendJob(messageId, messageIDToUse, address, true, defaultFriendRequestMessage, false));
}
});
return Unit.INSTANCE;
});
Address address = Address.fromSerialized(devicePublicKey);
long messageIDToUse = recipientPublicKey.equals(devicePublicKey) ? messageId : -1L;
if (isFriend) {
// Send a normal message if the user is friends with the recipient
// We should also send a sync message if we haven't already sent one
boolean shouldSendSyncMessage = !hasSentSyncMessage && MultiDeviceUtilities.shouldSendSycMessage(context, address);
jobManager.add(new PushTextSendJob(messageId, messageIDToUse, address, shouldSendSyncMessage));
hasSentSyncMessage = shouldSendSyncMessage;
} else {
// Send friend requests to non friends. If the user is friends with any
// of the devices then send out a default friend request message.
boolean isFriendsWithAny = (friendCount > 0);
String defaultFriendRequestMessage = isFriendsWithAny ? "Accept this friend request to enable messages to be synced across devices" : null;
jobManager.add(new PushTextSendJob(messageId, messageIDToUse, address, true, defaultFriendRequestMessage, false));
}
}
}
private static void sendMediaPush(Context context, Recipient recipient, long messageId) {
LokiStorageAPI storageAPI = LokiStorageAPI.Companion.getShared();
JobManager jobManager = ApplicationContext.getInstance(context).getJobManager();
// Just send the message normally if it's a group message
@ -314,36 +308,37 @@ public class MessageSender {
}
// Note to self
boolean isNoteToSelf = MultiDeviceUtilitiesKt.isOneOfOurDevices(context, recipient.getAddress());
boolean isNoteToSelf = MultiDeviceUtilities.isOneOfOurDevices(context, recipient.getAddress());
if (isNoteToSelf) {
jobManager.add(new PushTextSendJob(messageId, recipient.getAddress()));
return;
}
boolean[] hasSentSyncMessage = { false };
boolean hasSentSyncMessage = false;
MultiDeviceUtilitiesKt.getAllDevicePublicKeys(context, recipientPublicKey, storageAPI, (devicePublicKey, isFriend, friendCount) -> {
Util.runOnMain(() -> {
Address address = Address.fromSerialized(devicePublicKey);
long messageIDToUse = recipientPublicKey.equals(devicePublicKey) ? messageId : -1L;
Map<String, Boolean> devices = MultiDeviceUtilities.getAllDevicePublicKeysWithFriendStatus(context, recipientPublicKey);
int friendCount = MultiDeviceUtilities.getFriendCount(context, devices.keySet());
for (Map.Entry<String, Boolean> entry : devices.entrySet()) {
String devicePublicKey = entry.getKey();
boolean isFriend = entry.getValue();
if (isFriend) {
// Send a normal message if the user is friends with the recipient
// We should also send a sync message if we haven't already sent one
boolean shouldSendSyncMessage = !hasSentSyncMessage[0] && MultiDeviceUtilitiesKt.shouldSendSycMessage(context, address);
PushMediaSendJob.enqueue(context, jobManager, messageId, messageIDToUse, address, shouldSendSyncMessage);
hasSentSyncMessage[0] = shouldSendSyncMessage;
} else {
// Send friend requests to non friends. If the user is friends with any
// of the devices then send out a default friend request message.
boolean isFriendsWithAny = friendCount > 0;
String defaultFriendRequestMessage = isFriendsWithAny ? "Accept this friend request to enable messages to be synced across devices" : null;
PushMediaSendJob.enqueue(context, jobManager, messageId, messageIDToUse, address, true, defaultFriendRequestMessage, false);
}
});
return Unit.INSTANCE;
});
Address address = Address.fromSerialized(devicePublicKey);
long messageIDToUse = recipientPublicKey.equals(devicePublicKey) ? messageId : -1L;
if (isFriend) {
// Send a normal message if the user is friends with the recipient
// We should also send a sync message if we haven't already sent one
boolean shouldSendSyncMessage = !hasSentSyncMessage && MultiDeviceUtilities.shouldSendSycMessage(context, address);
PushMediaSendJob.enqueue(context, jobManager, messageId, messageIDToUse, address, shouldSendSyncMessage);
hasSentSyncMessage = shouldSendSyncMessage;
} else {
// Send friend requests to non friends. If the user is friends with any
// of the devices then send out a default friend request message.
boolean isFriendsWithAny = (friendCount > 0);
String defaultFriendRequestMessage = isFriendsWithAny ? "Accept this friend request to enable messages to be synced across devices" : null;
PushMediaSendJob.enqueue(context, jobManager, messageId, messageIDToUse, address, true, defaultFriendRequestMessage, false);
}
}
}
private static void sendGroupPush(Context context, Recipient recipient, long messageId, Address filterAddress) {