diff --git a/src/org/thoughtcrime/securesms/ApplicationContext.java b/src/org/thoughtcrime/securesms/ApplicationContext.java index 5bcc0d948c..efb1d1fee6 100644 --- a/src/org/thoughtcrime/securesms/ApplicationContext.java +++ b/src/org/thoughtcrime/securesms/ApplicationContext.java @@ -96,14 +96,13 @@ import org.whispersystems.libsignal.logging.SignalProtocolLoggerProvider; import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope; import org.whispersystems.signalservice.internal.push.SignalServiceProtos; import org.whispersystems.signalservice.loki.api.LokiAPIDatabaseProtocol; -import org.whispersystems.signalservice.loki.api.LokiDotNetAPI; +import org.whispersystems.signalservice.loki.api.LokiFileServerAPI; import org.whispersystems.signalservice.loki.api.LokiLongPoller; import org.whispersystems.signalservice.loki.api.LokiP2PAPI; import org.whispersystems.signalservice.loki.api.LokiP2PAPIDelegate; import org.whispersystems.signalservice.loki.api.LokiPublicChat; import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI; import org.whispersystems.signalservice.loki.api.LokiRSSFeed; -import org.whispersystems.signalservice.loki.api.LokiFileServerAPI; import java.security.Security; import java.util.ArrayList; @@ -115,7 +114,6 @@ import java.util.concurrent.TimeUnit; import dagger.ObjectGraph; import kotlin.Unit; import network.loki.messenger.BuildConfig; -import okhttp3.Cache; import static nl.komponents.kovenant.android.KovenantAndroid.startKovenant; import static nl.komponents.kovenant.android.KovenantAndroid.stopKovenant; @@ -184,11 +182,9 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc ProcessLifecycleOwner.get().getLifecycle().addObserver(this); // Loki - Set up P2P API if needed setUpP2PAPI(); - // Loki - Set the cache - LokiDotNetAPI.setCache(new Cache(this.getCacheDir(), OK_HTTP_CACHE_SIZE)); // Loki - Update device mappings if (setUpStorageAPIIfNeeded()) { - LokiFileServerAPI.Companion.getShared().updateUserDeviceMappings(); + LokiFileServerAPI.Companion.getShared().updateUserDeviceLinks(); if (TextSecurePreferences.needsRevocationCheck(this)) { checkNeedsRevocation(); } diff --git a/src/org/thoughtcrime/securesms/DeviceListFragment.java b/src/org/thoughtcrime/securesms/DeviceListFragment.java index 91381c4835..d725522e3d 100644 --- a/src/org/thoughtcrime/securesms/DeviceListFragment.java +++ b/src/org/thoughtcrime/securesms/DeviceListFragment.java @@ -190,7 +190,7 @@ public class DeviceListFragment extends ListFragment private void updateAddDeviceButtonVisibility() { if (addDeviceButton != null) { String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(getContext()); - boolean isDeviceLinkingEnabled = DatabaseFactory.getLokiAPIDatabase(getContext()).getPairingAuthorisations(userHexEncodedPublicKey).isEmpty(); + boolean isDeviceLinkingEnabled = DatabaseFactory.getLokiAPIDatabase(getContext()).getDeviceLinks(userHexEncodedPublicKey).isEmpty(); addDeviceButton.setVisibility(isDeviceLinkingEnabled ? View.VISIBLE : View.INVISIBLE); } } diff --git a/src/org/thoughtcrime/securesms/components/TypingStatusSender.java b/src/org/thoughtcrime/securesms/components/TypingStatusSender.java index 4b7908cbb6..1c851247ea 100644 --- a/src/org/thoughtcrime/securesms/components/TypingStatusSender.java +++ b/src/org/thoughtcrime/securesms/components/TypingStatusSender.java @@ -9,14 +9,13 @@ 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.MultiDeviceUtilities; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.Util; +import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities; import org.whispersystems.signalservice.loki.api.LokiFileServerAPI; import java.util.HashMap; import java.util.Map; -import java.util.Set; import java.util.concurrent.TimeUnit; import kotlin.Unit; @@ -91,7 +90,7 @@ public class TypingStatusSender { ApplicationContext.getInstance(context).getJobManager().add(new TypingSendJob(threadId, typingStarted)); return; } - LokiFileServerAPI.shared.getAllDevicePublicKeys(recipient.getAddress().serialize()).success(devices -> { + LokiDeviceLinkUtilities.INSTANCE.getAllLinkedDeviceHexEncodedPublicKeys(recipient.getAddress().serialize()).success(devices -> { for (String device : devices) { Recipient deviceRecipient = Recipient.from(context, Address.fromSerialized(device), false); long deviceThreadID = threadDatabase.getThreadIdIfExistsFor(deviceRecipient); diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java index 5f586e2f96..5e0d427b57 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -232,10 +232,10 @@ 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.loki.api.DeviceLink; import org.whispersystems.signalservice.loki.api.LokiAPI; +import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities; import org.whispersystems.signalservice.loki.api.LokiPublicChat; -import org.whispersystems.signalservice.loki.api.LokiFileServerAPI; -import org.whispersystems.signalservice.loki.api.PairingAuthorisation; import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestStatus; import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus; import org.whispersystems.signalservice.loki.messaging.Mention; @@ -2290,7 +2290,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity if (threadID != this.threadId) { Recipient threadRecipient = DatabaseFactory.getThreadDatabase(this).getRecipientForThreadId(threadID); if (threadRecipient != null && !threadRecipient.isGroupRecipient()) { - LokiFileServerAPI.shared.getAllDevicePublicKeys(threadRecipient.getAddress().serialize()).success(devices -> { + LokiDeviceLinkUtilities.INSTANCE.getAllLinkedDeviceHexEncodedPublicKeys(threadRecipient.getAddress().serialize()).success(devices -> { // We should update our input if this thread is a part of the other threads device if (devices.contains(recipient.getAddress().serialize())) { this.updateInputPanel(); @@ -3162,11 +3162,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity // region Loki private void updateTitleTextView(GlideRequests glide, Recipient recipient) { String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this); - List deviceLinks = DatabaseFactory.getLokiAPIDatabase(this).getPairingAuthorisations(userHexEncodedPublicKey); + Set deviceLinks = DatabaseFactory.getLokiAPIDatabase(this).getDeviceLinks(userHexEncodedPublicKey); HashSet userLinkedDeviceHexEncodedPublicKeys = new HashSet<>(); - for (PairingAuthorisation deviceLink : deviceLinks) { - userLinkedDeviceHexEncodedPublicKeys.add(deviceLink.getPrimaryDevicePublicKey().toLowerCase()); - userLinkedDeviceHexEncodedPublicKeys.add(deviceLink.getSecondaryDevicePublicKey().toLowerCase()); + for (DeviceLink deviceLink : deviceLinks) { + userLinkedDeviceHexEncodedPublicKeys.add(deviceLink.getMasterHexEncodedPublicKey().toLowerCase()); + userLinkedDeviceHexEncodedPublicKeys.add(deviceLink.getSlaveHexEncodedPublicKey().toLowerCase()); } userLinkedDeviceHexEncodedPublicKeys.add(userHexEncodedPublicKey.toLowerCase()); if (recipient == null) { diff --git a/src/org/thoughtcrime/securesms/database/loaders/DeviceListLoader.java b/src/org/thoughtcrime/securesms/database/loaders/DeviceListLoader.java index e5abc7d886..7a7a67d535 100644 --- a/src/org/thoughtcrime/securesms/database/loaders/DeviceListLoader.java +++ b/src/org/thoughtcrime/securesms/database/loaders/DeviceListLoader.java @@ -11,13 +11,14 @@ import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.loki.redesign.utilities.MnemonicUtilities; import org.thoughtcrime.securesms.util.AsyncLoader; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.signalservice.loki.api.LokiFileServerAPI; +import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities; import org.whispersystems.signalservice.loki.crypto.MnemonicCodec; import java.io.File; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Set; public class DeviceListLoader extends AsyncLoader> { @@ -33,7 +34,7 @@ public class DeviceListLoader extends AsyncLoader> { public List loadInBackground() { try { String ourPublicKey = TextSecurePreferences.getLocalNumber(getContext()); - List secondaryDevicePublicKeys = LokiFileServerAPI.shared.getSecondaryDevicePublicKeys(ourPublicKey).get(); + Set secondaryDevicePublicKeys = LokiDeviceLinkUtilities.INSTANCE.getSlaveHexEncodedPublicKeys(ourPublicKey).get(); List devices = Stream.of(secondaryDevicePublicKeys).map(this::mapToDevice).toList(); Collections.sort(devices, new DeviceComparator()); return devices; diff --git a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java index 3ba89fe908..d1f37ce390 100644 --- a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java +++ b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java @@ -36,7 +36,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import org.whispersystems.signalservice.api.messages.SignalServiceGroup; import org.whispersystems.signalservice.api.messages.SignalServiceGroup.Type; import org.whispersystems.signalservice.api.push.SignalServiceAddress; -import org.whispersystems.signalservice.loki.api.LokiFileServerAPI; +import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities; import org.whispersystems.signalservice.loki.utilities.PromiseUtil; import java.util.Collections; @@ -318,7 +318,7 @@ public class GroupMessageProcessor { try { String masterHexEncodedPublicKey = hexEncodedPublicKey.equalsIgnoreCase(ourPublicKey) ? TextSecurePreferences.getMasterHexEncodedPublicKey(context) - : PromiseUtil.timeout(LokiFileServerAPI.shared.getPrimaryDevicePublicKey(hexEncodedPublicKey), 5000).get(); + : PromiseUtil.timeout(LokiDeviceLinkUtilities.INSTANCE.getMasterHexEncodedPublicKey(hexEncodedPublicKey), 5000).get(); return masterHexEncodedPublicKey != null ? masterHexEncodedPublicKey : hexEncodedPublicKey; } catch (Exception e) { return hexEncodedPublicKey; @@ -329,7 +329,7 @@ public class GroupMessageProcessor { String ourNumber = TextSecurePreferences.getLocalNumber(context); for (String member : members) { // Make sure we have session with all of the members secondary devices - LokiFileServerAPI.shared.getAllDevicePublicKeys(member).success(devices -> { + LokiDeviceLinkUtilities.INSTANCE.getAllLinkedDeviceHexEncodedPublicKeys(member).success(devices -> { if (devices.contains(ourNumber)) { return Unit.INSTANCE; } for (String device : devices) { SignalProtocolAddress protocolAddress = new SignalProtocolAddress(device, SignalServiceAddress.DEFAULT_DEVICE_ID); diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 0507e8c0f0..6d0f70316d 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -68,13 +68,13 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreview; import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.loki.FriendRequestHandler; -import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIUtilities; import org.thoughtcrime.securesms.loki.LokiMessageDatabase; -import org.thoughtcrime.securesms.loki.redesign.messaging.LokiPreKeyBundleDatabase; -import org.thoughtcrime.securesms.loki.redesign.messaging.LokiPreKeyRecordDatabase; import org.thoughtcrime.securesms.loki.LokiThreadDatabase; import org.thoughtcrime.securesms.loki.MultiDeviceUtilities; import org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity; +import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIUtilities; +import org.thoughtcrime.securesms.loki.redesign.messaging.LokiPreKeyBundleDatabase; +import org.thoughtcrime.securesms.loki.redesign.messaging.LokiPreKeyRecordDatabase; import org.thoughtcrime.securesms.mms.IncomingMediaMessage; import org.thoughtcrime.securesms.mms.MmsException; import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage; @@ -129,10 +129,11 @@ import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOper import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage; import org.whispersystems.signalservice.api.messages.shared.SharedContact; import org.whispersystems.signalservice.api.push.SignalServiceAddress; +import org.whispersystems.signalservice.loki.api.DeviceLink; import org.whispersystems.signalservice.loki.api.DeviceLinkingSession; import org.whispersystems.signalservice.loki.api.LokiAPI; +import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities; import org.whispersystems.signalservice.loki.api.LokiFileServerAPI; -import org.whispersystems.signalservice.loki.api.PairingAuthorisation; import org.whispersystems.signalservice.loki.crypto.LokiServiceCipher; import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestStatus; import org.whispersystems.signalservice.loki.messaging.LokiServiceMessage; @@ -1102,20 +1103,20 @@ public class PushDecryptJob extends BaseJob implements InjectableType { } } - private boolean isValidPairingMessage(@NonNull PairingAuthorisation authorisation) { + private boolean isValidPairingMessage(@NonNull DeviceLink authorisation) { boolean isSecondaryDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context) != null; String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context); - boolean isRequest = (authorisation.getType() == PairingAuthorisation.Type.REQUEST); + boolean isRequest = (authorisation.getType() == DeviceLink.Type.REQUEST); if (authorisation.getRequestSignature() == null) { Log.d("Loki", "Ignoring pairing request message without a request signature."); return false; } else if (isRequest && isSecondaryDevice) { Log.d("Loki", "Ignoring unexpected pairing request message (the device is already paired as a secondary device)."); return false; - } else if (isRequest && !authorisation.getPrimaryDevicePublicKey().equals(userHexEncodedPublicKey)) { + } else if (isRequest && !authorisation.getMasterHexEncodedPublicKey().equals(userHexEncodedPublicKey)) { Log.d("Loki", "Ignoring pairing request message addressed to another user."); return false; - } else if (isRequest && authorisation.getSecondaryDevicePublicKey().equals(userHexEncodedPublicKey)) { + } else if (isRequest && authorisation.getSlaveHexEncodedPublicKey().equals(userHexEncodedPublicKey)) { Log.d("Loki", "Ignoring pairing request message from self."); return false; } @@ -1127,16 +1128,16 @@ public class PushDecryptJob extends BaseJob implements InjectableType { ApplicationContext.getInstance(context).getJobManager().add(new RetrieveProfileAvatarJob(primaryDevice, url)); } - private void handlePairingMessage(@NonNull PairingAuthorisation authorisation, @NonNull SignalServiceContent content) { + private void handlePairingMessage(@NonNull DeviceLink authorisation, @NonNull SignalServiceContent content) { String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context); - if (authorisation.getType() == PairingAuthorisation.Type.REQUEST) { + if (authorisation.getType() == DeviceLink.Type.REQUEST) { handlePairingRequestMessage(authorisation, content); - } else if (authorisation.getSecondaryDevicePublicKey().equals(userHexEncodedPublicKey)) { + } else if (authorisation.getSlaveHexEncodedPublicKey().equals(userHexEncodedPublicKey)) { handlePairingAuthorisationMessage(authorisation, content); } } - private void handlePairingRequestMessage(@NonNull PairingAuthorisation authorisation, @NonNull SignalServiceContent content) { + private void handlePairingRequestMessage(@NonNull DeviceLink authorisation, @NonNull SignalServiceContent content) { boolean isValid = isValidPairingMessage(authorisation); DeviceLinkingSession linkingSession = DeviceLinkingSession.Companion.getShared(); if (isValid && linkingSession.isListeningForLinkingRequests()) { @@ -1146,7 +1147,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { } } - private void handlePairingAuthorisationMessage(@NonNull PairingAuthorisation authorisation, @NonNull SignalServiceContent content) { + private void handlePairingAuthorisationMessage(@NonNull DeviceLink authorisation, @NonNull SignalServiceContent content) { // Prepare boolean isSecondaryDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context) != null; if (isSecondaryDevice) { @@ -1162,23 +1163,23 @@ public class PushDecryptJob extends BaseJob implements InjectableType { Log.d("Loki", "Ignoring pairing authorisation message."); return; } - if (authorisation.getType() != PairingAuthorisation.Type.GRANT) { return; } - Log.d("Loki", "Received pairing authorisation message from: " + authorisation.getPrimaryDevicePublicKey() + "."); + if (authorisation.getType() != DeviceLink.Type.AUTHORIZATION) { return; } + Log.d("Loki", "Received pairing authorisation message from: " + authorisation.getMasterHexEncodedPublicKey() + "."); // Save PreKeyBundle if for whatever reason we got one storePreKeyBundleIfNeeded(content); // Process DeviceLinkingSession.Companion.getShared().processLinkingAuthorization(authorisation); // Store the primary device's public key String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context); - DatabaseFactory.getLokiAPIDatabase(context).removePairingAuthorisations(userHexEncodedPublicKey); - DatabaseFactory.getLokiAPIDatabase(context).insertOrUpdatePairingAuthorisation(authorisation); - TextSecurePreferences.setMasterHexEncodedPublicKey(context, authorisation.getPrimaryDevicePublicKey()); + DatabaseFactory.getLokiAPIDatabase(context).clearDeviceLinks(userHexEncodedPublicKey); + DatabaseFactory.getLokiAPIDatabase(context).addDeviceLink(authorisation); + TextSecurePreferences.setMasterHexEncodedPublicKey(context, authorisation.getMasterHexEncodedPublicKey()); TextSecurePreferences.setMultiDevice(context, true); // Send a background message to the primary device - MessageSender.sendBackgroundMessage(context, authorisation.getPrimaryDevicePublicKey()); + MessageSender.sendBackgroundMessage(context, authorisation.getMasterHexEncodedPublicKey()); // Propagate the updates to the file server LokiFileServerAPI storageAPI = LokiFileServerAPI.Companion.getShared(); - storageAPI.updateUserDeviceMappings(); + storageAPI.updateUserDeviceLinks(); // Update display names if (content.senderDisplayName.isPresent() && content.senderDisplayName.get().length() > 0) { TextSecurePreferences.setProfileName(context, content.senderDisplayName.get()); @@ -1245,7 +1246,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { private void handleSessionRequestIfNeeded(@NonNull SignalServiceContent content) { if (content.isFriendRequest() && isSessionRequest(content)) { // Check if the session request from a member in one of our groups or our friend - LokiFileServerAPI.shared.getPrimaryDevicePublicKey(content.getSender()).success(primaryDevicePublicKey -> { + LokiDeviceLinkUtilities.INSTANCE.getMasterHexEncodedPublicKey(content.getSender()).success(primaryDevicePublicKey -> { String sender = primaryDevicePublicKey != null ? primaryDevicePublicKey : content.getSender(); long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, Address.fromSerialized(sender), false)); LokiThreadFriendRequestStatus threadFriendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID); @@ -1284,7 +1285,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { // Allow profile sharing with contact DatabaseFactory.getRecipientDatabase(context).setProfileSharing(contactID, true); // Update the last message if needed - LokiFileServerAPI.shared.getPrimaryDevicePublicKey(pubKey).success(primaryDevice -> { + LokiDeviceLinkUtilities.INSTANCE.getMasterHexEncodedPublicKey(pubKey).success(primaryDevice -> { Util.runOnMain(() -> { long primaryDeviceThreadID = primaryDevice == null ? threadID : DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, Address.fromSerialized(primaryDevice), false)); FriendRequestHandler.updateLastFriendRequestMessage(context, primaryDeviceThreadID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED); @@ -1799,7 +1800,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { */ private Recipient getPrimaryDeviceRecipient(String pubKey) { try { - String primaryDevice = PromiseUtil.timeout(LokiFileServerAPI.shared.getPrimaryDevicePublicKey(pubKey), 5000).get(); + String primaryDevice = PromiseUtil.timeout(LokiDeviceLinkUtilities.INSTANCE.getMasterHexEncodedPublicKey(pubKey), 5000).get(); String publicKey = (primaryDevice != null) ? primaryDevice : pubKey; // 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); diff --git a/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java index 1c07fd611a..ef9fa207ac 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java @@ -50,8 +50,8 @@ import org.whispersystems.signalservice.api.messages.SignalServiceGroup; import org.whispersystems.signalservice.api.messages.shared.SharedContact; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext; +import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities; import org.whispersystems.signalservice.loki.api.LokiPublicChat; -import org.whispersystems.signalservice.loki.api.LokiFileServerAPI; import org.whispersystems.signalservice.loki.utilities.PromiseUtil; import java.io.IOException; @@ -368,7 +368,7 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType { if (!member.isPhone() || member.serialize().equalsIgnoreCase(localNumber)) { continue; } try { - List secondaryDevices = PromiseUtil.timeout(LokiFileServerAPI.shared.getSecondaryDevicePublicKeys(member.serialize()), 5000).get(); + Set secondaryDevices = PromiseUtil.timeout(LokiDeviceLinkUtilities.INSTANCE.getSlaveHexEncodedPublicKeys(member.serialize()), 5000).get(); memberSet.addAll(Stream.of(secondaryDevices).map(string -> { // Loki - Calling .map(Address::fromSerialized) is causing errors, thus we use the long method :( return Address.fromSerialized(string); diff --git a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java index 13de89022b..322642bc7b 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java @@ -22,7 +22,6 @@ 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.MultiDeviceUtilities; import org.thoughtcrime.securesms.mms.MmsException; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; import org.thoughtcrime.securesms.recipients.Recipient; @@ -43,13 +42,12 @@ 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.LokiFileServerAPI; +import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities; import org.whispersystems.signalservice.loki.messaging.LokiSyncMessage; import org.whispersystems.signalservice.loki.utilities.PromiseUtil; import java.io.FileNotFoundException; import java.io.IOException; -import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -292,7 +290,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 = PromiseUtil.get(LokiFileServerAPI.shared.getPrimaryDevicePublicKey(address.getNumber()), null); + String primaryDevice = PromiseUtil.get(LokiDeviceLinkUtilities.INSTANCE.getMasterHexEncodedPublicKey(address.getNumber()), null); 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); diff --git a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java index dfa291436d..95d6cc8908 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java @@ -14,7 +14,6 @@ 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.MultiDeviceUtilities; import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.service.ExpiringMessageManager; @@ -30,7 +29,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.LokiFileServerAPI; +import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities; import org.whispersystems.signalservice.loki.messaging.LokiSyncMessage; import org.whispersystems.signalservice.loki.utilities.PromiseUtil; @@ -237,7 +236,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 = PromiseUtil.get(LokiFileServerAPI.shared.getPrimaryDevicePublicKey(address.getNumber()), null); + String primaryDevice = PromiseUtil.get(LokiDeviceLinkUtilities.INSTANCE.getMasterHexEncodedPublicKey(address.getNumber()), null); 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); diff --git a/src/org/thoughtcrime/securesms/loki/MultiDeviceUtilities.kt b/src/org/thoughtcrime/securesms/loki/MultiDeviceUtilities.kt index ebdcff428e..d5c256f52b 100644 --- a/src/org/thoughtcrime/securesms/loki/MultiDeviceUtilities.kt +++ b/src/org/thoughtcrime/securesms/loki/MultiDeviceUtilities.kt @@ -20,8 +20,9 @@ import org.thoughtcrime.securesms.sms.MessageSender import org.thoughtcrime.securesms.util.TextSecurePreferences import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage import org.whispersystems.signalservice.api.push.SignalServiceAddress +import org.whispersystems.signalservice.loki.api.DeviceLink +import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities import org.whispersystems.signalservice.loki.api.LokiFileServerAPI -import org.whispersystems.signalservice.loki.api.PairingAuthorisation import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus import org.whispersystems.signalservice.loki.utilities.recover import org.whispersystems.signalservice.loki.utilities.retryIfNeeded @@ -32,12 +33,12 @@ fun checkForRevocation(context: Context) { val primaryDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context) ?: return val ourDevice = TextSecurePreferences.getLocalNumber(context) - LokiFileServerAPI.shared.fetchDeviceMappings(primaryDevice).bind { mappings -> - val ourMapping = mappings.find { it.secondaryDevicePublicKey == ourDevice } + LokiFileServerAPI.shared.getDeviceLinks(primaryDevice, true).bind { mappings -> + val ourMapping = mappings.find { it.slaveHexEncodedPublicKey == ourDevice } if (ourMapping != null) throw Error("Device has not been revoked") // remove pairing authorisations for our device - DatabaseFactory.getLokiAPIDatabase(context).removePairingAuthorisations(ourDevice) - LokiFileServerAPI.shared.updateUserDeviceMappings() + DatabaseFactory.getLokiAPIDatabase(context).clearDeviceLinks(ourDevice) + LokiFileServerAPI.shared.updateUserDeviceLinks() }.successUi { TextSecurePreferences.setNeedsRevocationCheck(context, false) ApplicationContext.getInstance(context).clearData() @@ -49,7 +50,7 @@ fun checkForRevocation(context: Context) { fun getAllDeviceFriendRequestStatuses(context: Context, hexEncodedPublicKey: String): Promise, Exception> { val lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context) - return LokiFileServerAPI.shared.getAllDevicePublicKeys(hexEncodedPublicKey).map { keys -> + return LokiDeviceLinkUtilities.getAllLinkedDeviceHexEncodedPublicKeys(hexEncodedPublicKey).map { keys -> val map = mutableMapOf() for (devicePublicKey in keys) { val device = Recipient.from(context, Address.fromSerialized(devicePublicKey), false) @@ -63,7 +64,7 @@ fun getAllDeviceFriendRequestStatuses(context: Context, hexEncodedPublicKey: Str fun getAllDevicePublicKeysWithFriendStatus(context: Context, hexEncodedPublicKey: String): Promise, Unit> { val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context) - return LokiFileServerAPI.shared.getAllDevicePublicKeys(hexEncodedPublicKey).map { keys -> + return LokiDeviceLinkUtilities.getAllLinkedDeviceHexEncodedPublicKeys(hexEncodedPublicKey).map { keys -> val devices = keys.toMutableSet() if (hexEncodedPublicKey != userHexEncodedPublicKey) { devices.remove(userHexEncodedPublicKey) @@ -92,7 +93,7 @@ fun shouldAutomaticallyBecomeFriendsWithDevice(publicKey: String, context: Conte return Promise.of(true) } - return LokiFileServerAPI.shared.getPrimaryDevicePublicKey(publicKey).bind { primaryDevicePublicKey -> + return LokiDeviceLinkUtilities.getMasterHexEncodedPublicKey(publicKey).bind { primaryDevicePublicKey -> // If the public key doesn't have any other devices then go through regular friend request logic if (primaryDevicePublicKey == null) { return@bind Promise.of(false) @@ -108,12 +109,12 @@ fun shouldAutomaticallyBecomeFriendsWithDevice(publicKey: String, context: Conte } } -fun sendPairingAuthorisationMessage(context: Context, contactHexEncodedPublicKey: String, authorisation: PairingAuthorisation): Promise { +fun sendPairingAuthorisationMessage(context: Context, contactHexEncodedPublicKey: String, authorisation: DeviceLink): Promise { val messageSender = ApplicationContext.getInstance(context).communicationModule.provideSignalMessageSender() val address = SignalServiceAddress(contactHexEncodedPublicKey) val message = SignalServiceDataMessage.newBuilder().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) { + if (authorisation.type == DeviceLink.Type.REQUEST) { val preKeyBundle = DatabaseFactory.getLokiPreKeyBundleDatabase(context).generatePreKeyBundle(address.number) message.asFriendRequest(true).withPreKeyBundle(preKeyBundle) } else { @@ -139,17 +140,17 @@ fun sendPairingAuthorisationMessage(context: Context, contactHexEncodedPublicKey } } -fun signAndSendPairingAuthorisationMessage(context: Context, pairingAuthorisation: PairingAuthorisation) { +fun signAndSendPairingAuthorisationMessage(context: Context, pairingAuthorisation: DeviceLink) { val userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(context).privateKey.serialize() - val signedPairingAuthorisation = pairingAuthorisation.sign(PairingAuthorisation.Type.GRANT, userPrivateKey) - if (signedPairingAuthorisation == null || signedPairingAuthorisation.type != PairingAuthorisation.Type.GRANT) { + val signedPairingAuthorisation = pairingAuthorisation.sign(DeviceLink.Type.AUTHORIZATION, userPrivateKey) + if (signedPairingAuthorisation == null || signedPairingAuthorisation.type != DeviceLink.Type.AUTHORIZATION) { Log.d("Loki", "Failed to sign pairing authorization.") return } - DatabaseFactory.getLokiAPIDatabase(context).insertOrUpdatePairingAuthorisation(signedPairingAuthorisation) + DatabaseFactory.getLokiAPIDatabase(context).addDeviceLink(signedPairingAuthorisation) TextSecurePreferences.setMultiDevice(context, true) - val address = Address.fromSerialized(pairingAuthorisation.secondaryDevicePublicKey); + val address = Address.fromSerialized(pairingAuthorisation.slaveHexEncodedPublicKey) val sendPromise = retryIfNeeded(8) { sendPairingAuthorisationMessage(context, address.serialize(), signedPairingAuthorisation) @@ -157,7 +158,7 @@ fun signAndSendPairingAuthorisationMessage(context: Context, pairingAuthorisatio Log.d("Loki", "Failed to send pairing authorization message to ${address.serialize()}.") } - val updatePromise = LokiFileServerAPI.shared.updateUserDeviceMappings().fail { + val updatePromise = LokiFileServerAPI.shared.updateUserDeviceLinks().fail { Log.d("Loki", "Failed to update device mapping") } @@ -177,7 +178,7 @@ fun isOneOfOurDevices(context: Context, address: Address): Promise + return LokiDeviceLinkUtilities.getAllLinkedDeviceHexEncodedPublicKeys(ourPublicKey).map { devices -> devices.contains(address.serialize()) } } diff --git a/src/org/thoughtcrime/securesms/loki/redesign/activities/CreateClosedGroupLoader.kt b/src/org/thoughtcrime/securesms/loki/redesign/activities/CreateClosedGroupLoader.kt index 620d47b5c6..2c07fe0772 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/activities/CreateClosedGroupLoader.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/activities/CreateClosedGroupLoader.kt @@ -12,9 +12,9 @@ class CreateClosedGroupLoader(context: Context) : AsyncLoader>(cont val threadDatabase = DatabaseFactory.getThreadDatabase(context) val lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context) val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context) - val deviceLinks = DatabaseFactory.getLokiAPIDatabase(context).getPairingAuthorisations(userHexEncodedPublicKey) + val deviceLinks = DatabaseFactory.getLokiAPIDatabase(context).getDeviceLinks(userHexEncodedPublicKey) val userLinkedDeviceHexEncodedPublicKeys = deviceLinks.flatMap { - listOf( it.primaryDevicePublicKey.toLowerCase(), it.secondaryDevicePublicKey.toLowerCase() ) + listOf( it.masterHexEncodedPublicKey.toLowerCase(), it.slaveHexEncodedPublicKey.toLowerCase() ) }.toMutableSet() userLinkedDeviceHexEncodedPublicKeys.add(userHexEncodedPublicKey.toLowerCase()) val cursor = threadDatabase.conversationList diff --git a/src/org/thoughtcrime/securesms/loki/redesign/activities/LandingActivity.kt b/src/org/thoughtcrime/securesms/loki/redesign/activities/LandingActivity.kt index 2daa93d81d..46477e7159 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/activities/LandingActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/activities/LandingActivity.kt @@ -26,7 +26,7 @@ import org.whispersystems.curve25519.Curve25519 import org.whispersystems.libsignal.ecc.Curve import org.whispersystems.libsignal.ecc.ECKeyPair import org.whispersystems.libsignal.util.KeyHelper -import org.whispersystems.signalservice.loki.api.PairingAuthorisation +import org.whispersystems.signalservice.loki.api.DeviceLink import org.whispersystems.signalservice.loki.utilities.hexEncodedPublicKey import org.whispersystems.signalservice.loki.utilities.retryIfNeeded @@ -92,7 +92,7 @@ class LandingActivity : BaseActionBarActivity(), LinkDeviceSlaveModeDialogDelega TextSecurePreferences.setLocalNumber(this, userHexEncodedPublicKey) TextSecurePreferences.setHasSeenWelcomeScreen(this, true) TextSecurePreferences.setPromptedPushRegistration(this, true) - val authorisation = PairingAuthorisation(hexEncodedPublicKey, userHexEncodedPublicKey).sign(PairingAuthorisation.Type.REQUEST, keyPair!!.privateKey.serialize()) + val authorisation = DeviceLink(hexEncodedPublicKey, userHexEncodedPublicKey).sign(DeviceLink.Type.REQUEST, keyPair!!.privateKey.serialize()) if (authorisation == null) { Log.d("Loki", "Failed to sign device link request.") reset() @@ -107,13 +107,13 @@ class LandingActivity : BaseActionBarActivity(), LinkDeviceSlaveModeDialogDelega linkDeviceDialog.show(supportFragmentManager, "Link Device Dialog") AsyncTask.execute { retryIfNeeded(8) { - sendPairingAuthorisationMessage(this@LandingActivity, authorisation.primaryDevicePublicKey, authorisation) + sendPairingAuthorisationMessage(this@LandingActivity, authorisation.masterHexEncodedPublicKey, authorisation) } } } - override fun onDeviceLinkRequestAuthorized(authorization: PairingAuthorisation) { - TextSecurePreferences.setMasterHexEncodedPublicKey(this, authorization.primaryDevicePublicKey) + override fun onDeviceLinkRequestAuthorized(deviceLink: DeviceLink) { + TextSecurePreferences.setMasterHexEncodedPublicKey(this, deviceLink.masterHexEncodedPublicKey) val intent = Intent(this, HomeActivity::class.java) show(intent) finish() diff --git a/src/org/thoughtcrime/securesms/loki/redesign/activities/LinkedDevicesActivity.kt b/src/org/thoughtcrime/securesms/loki/redesign/activities/LinkedDevicesActivity.kt index 5cc7a152ed..42292648f8 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/activities/LinkedDevicesActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/activities/LinkedDevicesActivity.kt @@ -20,8 +20,8 @@ import org.thoughtcrime.securesms.loki.signAndSendPairingAuthorisationMessage import org.thoughtcrime.securesms.sms.MessageSender import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.Util +import org.whispersystems.signalservice.loki.api.DeviceLink import org.whispersystems.signalservice.loki.api.LokiFileServerAPI -import org.whispersystems.signalservice.loki.api.PairingAuthorisation class LinkedDevicesActivity : PassphraseRequiredActionBarActivity, LoaderManager.LoaderCallbacks>, DeviceClickListener, EditDeviceNameDialogDelegate, LinkDeviceMasterModeDialogDelegate { private var devices = listOf() @@ -119,14 +119,14 @@ class LinkedDevicesActivity : PassphraseRequiredActionBarActivity, LoaderManager val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this) val database = DatabaseFactory.getLokiAPIDatabase(this) database.removePairingAuthorisation(userHexEncodedPublicKey, slaveDeviceHexEncodedPublicKey) - LokiFileServerAPI.shared.updateUserDeviceMappings().success { + LokiFileServerAPI.shared.updateUserDeviceLinks().success { MessageSender.sendUnpairRequest(this, slaveDeviceHexEncodedPublicKey) } LoaderManager.getInstance(this).restartLoader(0, null, this) Toast.makeText(this, "Your device was unlinked successfully", Toast.LENGTH_LONG).show() } - override fun onDeviceLinkRequestAuthorized(authorization: PairingAuthorisation) { + override fun onDeviceLinkRequestAuthorized(authorization: DeviceLink) { AsyncTask.execute { signAndSendPairingAuthorisationMessage(this, authorization) Util.runOnMain { diff --git a/src/org/thoughtcrime/securesms/loki/redesign/activities/LinkedDevicesLoader.kt b/src/org/thoughtcrime/securesms/loki/redesign/activities/LinkedDevicesLoader.kt index a2519801d5..87dcdb528e 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/activities/LinkedDevicesLoader.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/activities/LinkedDevicesLoader.kt @@ -6,7 +6,7 @@ import org.thoughtcrime.securesms.devicelist.Device import org.thoughtcrime.securesms.loki.redesign.utilities.MnemonicUtilities import org.thoughtcrime.securesms.util.AsyncLoader import org.thoughtcrime.securesms.util.TextSecurePreferences -import org.whispersystems.signalservice.loki.api.LokiFileServerAPI +import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities import org.whispersystems.signalservice.loki.crypto.MnemonicCodec import java.io.File @@ -20,7 +20,7 @@ class LinkedDevicesLoader(context: Context) : AsyncLoader>(context) override fun loadInBackground(): List? { try { val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context) - val slaveDeviceHexEncodedPublicKeys = LokiFileServerAPI.shared.getSecondaryDevicePublicKeys(userHexEncodedPublicKey).get() + val slaveDeviceHexEncodedPublicKeys = LokiDeviceLinkUtilities.getSlaveHexEncodedPublicKeys(userHexEncodedPublicKey).get() return slaveDeviceHexEncodedPublicKeys.map { hexEncodedPublicKey -> val shortID = MnemonicUtilities.getFirst3Words(mnemonicCodec, hexEncodedPublicKey) val name = DatabaseFactory.getLokiUserDatabase(context).getDisplayName(hexEncodedPublicKey) diff --git a/src/org/thoughtcrime/securesms/loki/redesign/dialogs/LinkDeviceMasterModeDialog.kt b/src/org/thoughtcrime/securesms/loki/redesign/dialogs/LinkDeviceMasterModeDialog.kt index 94f6c6de80..10d3468178 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/dialogs/LinkDeviceMasterModeDialog.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/dialogs/LinkDeviceMasterModeDialog.kt @@ -17,15 +17,15 @@ import org.thoughtcrime.securesms.loki.redesign.utilities.QRCodeUtilities import org.thoughtcrime.securesms.loki.toPx import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.Util +import org.whispersystems.signalservice.loki.api.DeviceLink import org.whispersystems.signalservice.loki.api.DeviceLinkingSession import org.whispersystems.signalservice.loki.api.DeviceLinkingSessionListener -import org.whispersystems.signalservice.loki.api.PairingAuthorisation import org.whispersystems.signalservice.loki.crypto.MnemonicCodec class LinkDeviceMasterModeDialog : DialogFragment(), DeviceLinkingSessionListener { private val languageFileDirectory by lazy { MnemonicUtilities.getLanguageFileDirectory(context!!) } private lateinit var contentView: View - private var authorization: PairingAuthorisation? = null + private var authorization: DeviceLink? = null var delegate: LinkDeviceMasterModeDialogDelegate? = null override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { @@ -45,8 +45,8 @@ class LinkDeviceMasterModeDialog : DialogFragment(), DeviceLinkingSessionListene return result } - override fun requestUserAuthorization(authorization: PairingAuthorisation) { - if (authorization.type != PairingAuthorisation.Type.REQUEST || authorization.primaryDevicePublicKey != TextSecurePreferences.getLocalNumber(context!!) || this.authorization != null) { return } + override fun requestUserAuthorization(authorization: DeviceLink) { + if (authorization.type != DeviceLink.Type.REQUEST || authorization.masterHexEncodedPublicKey != TextSecurePreferences.getLocalNumber(context!!) || this.authorization != null) { return } Util.runOnMain { this.authorization = authorization contentView.qrCodeImageView.visibility = View.GONE @@ -56,7 +56,7 @@ class LinkDeviceMasterModeDialog : DialogFragment(), DeviceLinkingSessionListene contentView.titleTextView.text = "Linking Request Received" contentView.explanationTextView.text = "Please check that the words below match those shown on your other device" contentView.mnemonicTextView.visibility = View.VISIBLE - contentView.mnemonicTextView.text = MnemonicUtilities.getFirst3Words(MnemonicCodec(languageFileDirectory), authorization.secondaryDevicePublicKey) + contentView.mnemonicTextView.text = MnemonicUtilities.getFirst3Words(MnemonicCodec(languageFileDirectory), authorization.slaveHexEncodedPublicKey) contentView.authorizeButton.visibility = View.VISIBLE } } @@ -73,7 +73,7 @@ class LinkDeviceMasterModeDialog : DialogFragment(), DeviceLinkingSessionListene DeviceLinkingSession.shared.stopListeningForLinkingRequests() DeviceLinkingSession.shared.removeListener(this) if (authorization != null) { - DatabaseFactory.getLokiPreKeyBundleDatabase(context).removePreKeyBundle(authorization!!.secondaryDevicePublicKey) + DatabaseFactory.getLokiPreKeyBundleDatabase(context).removePreKeyBundle(authorization!!.slaveHexEncodedPublicKey) } dismiss() delegate?.onDeviceLinkCanceled() @@ -82,6 +82,6 @@ class LinkDeviceMasterModeDialog : DialogFragment(), DeviceLinkingSessionListene interface LinkDeviceMasterModeDialogDelegate { - fun onDeviceLinkRequestAuthorized(authorization: PairingAuthorisation) + fun onDeviceLinkRequestAuthorized(authorization: DeviceLink) fun onDeviceLinkCanceled() } diff --git a/src/org/thoughtcrime/securesms/loki/redesign/dialogs/LinkDeviceSlaveModeDialog.kt b/src/org/thoughtcrime/securesms/loki/redesign/dialogs/LinkDeviceSlaveModeDialog.kt index 7f80c704a3..d42cabaffe 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/dialogs/LinkDeviceSlaveModeDialog.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/dialogs/LinkDeviceSlaveModeDialog.kt @@ -15,15 +15,15 @@ import network.loki.messenger.R import org.thoughtcrime.securesms.loki.redesign.utilities.MnemonicUtilities import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.Util +import org.whispersystems.signalservice.loki.api.DeviceLink import org.whispersystems.signalservice.loki.api.DeviceLinkingSession import org.whispersystems.signalservice.loki.api.DeviceLinkingSessionListener -import org.whispersystems.signalservice.loki.api.PairingAuthorisation import org.whispersystems.signalservice.loki.crypto.MnemonicCodec class LinkDeviceSlaveModeDialog : DialogFragment(), DeviceLinkingSessionListener { private val languageFileDirectory by lazy { MnemonicUtilities.getLanguageFileDirectory(context!!) } private lateinit var contentView: View - private var authorization: PairingAuthorisation? = null + private var authorization: DeviceLink? = null var delegate: LinkDeviceSlaveModeDialogDelegate? = null override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { @@ -40,8 +40,8 @@ class LinkDeviceSlaveModeDialog : DialogFragment(), DeviceLinkingSessionListener return result } - override fun onDeviceLinkRequestAuthorized(authorization: PairingAuthorisation) { - if (authorization.type != PairingAuthorisation.Type.GRANT || authorization.secondaryDevicePublicKey != TextSecurePreferences.getLocalNumber(context!!) || this.authorization != null) { return } + override fun onDeviceLinkRequestAuthorized(authorization: DeviceLink) { + if (authorization.type != DeviceLink.Type.AUTHORIZATION || authorization.slaveHexEncodedPublicKey != TextSecurePreferences.getLocalNumber(context!!) || this.authorization != null) { return } Util.runOnMain { this.authorization = authorization DeviceLinkingSession.shared.stopListeningForLinkingRequests() @@ -71,6 +71,6 @@ class LinkDeviceSlaveModeDialog : DialogFragment(), DeviceLinkingSessionListener interface LinkDeviceSlaveModeDialogDelegate { - fun onDeviceLinkRequestAuthorized(authorization: PairingAuthorisation) + fun onDeviceLinkRequestAuthorized(authorization: DeviceLink) fun onDeviceLinkCanceled() } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/redesign/messaging/LokiAPIDatabase.kt b/src/org/thoughtcrime/securesms/loki/redesign/messaging/LokiAPIDatabase.kt index d3aa589aa8..8991e9be32 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/messaging/LokiAPIDatabase.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/messaging/LokiAPIDatabase.kt @@ -7,9 +7,9 @@ import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper import org.thoughtcrime.securesms.loki.redesign.utilities.* import org.thoughtcrime.securesms.util.Base64 import org.thoughtcrime.securesms.util.TextSecurePreferences +import org.whispersystems.signalservice.loki.api.DeviceLink import org.whispersystems.signalservice.loki.api.LokiAPIDatabaseProtocol import org.whispersystems.signalservice.loki.api.LokiAPITarget -import org.whispersystems.signalservice.loki.api.PairingAuthorisation // TODO: Clean this up a bit @@ -179,28 +179,28 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( database.delete(lastDeletionServerIDCache,"$lastDeletionServerIDCacheIndex = ?", wrap(index)) } - override fun getPairingAuthorisations(hexEncodedPublicKey: String): List { + override fun getDeviceLinks(hexEncodedPublicKey: String): Set { val database = databaseHelper.readableDatabase return database.getAll(pairingAuthorisationCache, "$primaryDevicePublicKey = ? OR $secondaryDevicePublicKey = ?", arrayOf( hexEncodedPublicKey, hexEncodedPublicKey )) { cursor -> val primaryDevicePubKey = cursor.getString(primaryDevicePublicKey) val secondaryDevicePubKey = cursor.getString(secondaryDevicePublicKey) val requestSignature: ByteArray? = if (cursor.isNull(cursor.getColumnIndexOrThrow(requestSignature))) null else cursor.getBase64EncodedData(requestSignature) val grantSignature: ByteArray? = if (cursor.isNull(cursor.getColumnIndexOrThrow(grantSignature))) null else cursor.getBase64EncodedData(grantSignature) - PairingAuthorisation(primaryDevicePubKey, secondaryDevicePubKey, requestSignature, grantSignature) - } + DeviceLink(primaryDevicePubKey, secondaryDevicePubKey, requestSignature, grantSignature) + }.toSet() } - override fun insertOrUpdatePairingAuthorisation(authorisation: PairingAuthorisation) { + override fun addDeviceLink(deviceLink: DeviceLink) { val database = databaseHelper.writableDatabase val values = ContentValues() - values.put(primaryDevicePublicKey, authorisation.primaryDevicePublicKey) - values.put(secondaryDevicePublicKey, authorisation.secondaryDevicePublicKey) - if (authorisation.requestSignature != null) { values.put(requestSignature, Base64.encodeBytes(authorisation.requestSignature)) } - if (authorisation.grantSignature != null) { values.put(grantSignature, Base64.encodeBytes(authorisation.grantSignature)) } - database.insertOrUpdate(pairingAuthorisationCache, values, "$primaryDevicePublicKey = ? AND $secondaryDevicePublicKey = ?", arrayOf( authorisation.primaryDevicePublicKey, authorisation.secondaryDevicePublicKey )) + values.put(primaryDevicePublicKey, deviceLink.masterHexEncodedPublicKey) + values.put(secondaryDevicePublicKey, deviceLink.slaveHexEncodedPublicKey) + if (deviceLink.requestSignature != null) { values.put(requestSignature, Base64.encodeBytes(deviceLink.requestSignature)) } + if (deviceLink.authorizationSignature != null) { values.put(grantSignature, Base64.encodeBytes(deviceLink.authorizationSignature)) } + database.insertOrUpdate(pairingAuthorisationCache, values, "$primaryDevicePublicKey = ? AND $secondaryDevicePublicKey = ?", arrayOf( deviceLink.masterHexEncodedPublicKey, deviceLink.slaveHexEncodedPublicKey )) } - override fun removePairingAuthorisations(hexEncodedPublicKey: String) { + override fun clearDeviceLinks(hexEncodedPublicKey: String) { val database = databaseHelper.writableDatabase database.delete(pairingAuthorisationCache, "$primaryDevicePublicKey = ? OR $secondaryDevicePublicKey = ?", arrayOf( hexEncodedPublicKey, hexEncodedPublicKey )) } diff --git a/src/org/thoughtcrime/securesms/loki/redesign/messaging/LokiPublicChatPoller.kt b/src/org/thoughtcrime/securesms/loki/redesign/messaging/LokiPublicChatPoller.kt index fd618562c6..327b382c4a 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/messaging/LokiPublicChatPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/messaging/LokiPublicChatPoller.kt @@ -21,10 +21,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage import org.whispersystems.signalservice.api.messages.SignalServiceGroup import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage import org.whispersystems.signalservice.api.push.SignalServiceAddress -import org.whispersystems.signalservice.loki.api.LokiPublicChat -import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI -import org.whispersystems.signalservice.loki.api.LokiPublicChatMessage -import org.whispersystems.signalservice.loki.api.LokiFileServerAPI +import org.whispersystems.signalservice.loki.api.* import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus import org.whispersystems.signalservice.loki.utilities.successBackground import java.security.MessageDigest @@ -156,7 +153,7 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki fun pollForNewMessages() { fun processIncomingMessage(message: LokiPublicChatMessage) { // If the sender of the current message is not a secondary device, we need to set the display name in the database - val primaryDevice = LokiFileServerAPI.shared.getPrimaryDevicePublicKey(message.hexEncodedPublicKey).get() + val primaryDevice = LokiDeviceLinkUtilities.getMasterHexEncodedPublicKey(message.hexEncodedPublicKey).get() if (primaryDevice == null) { val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})" DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.hexEncodedPublicKey, senderDisplayName) @@ -171,9 +168,9 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki } // Update profile avatar if needed val senderRecipient = Recipient.from(context, Address.fromSerialized(senderPublicKey), false) - if (message.avatar != null && message.avatar!!.url.isNotEmpty()) { - val profileKey = message.avatar!!.profileKey - val url = message.avatar!!.url + if (message.profilePicture != null && message.profilePicture!!.url.isNotEmpty()) { + val profileKey = message.profilePicture!!.profileKey + val url = message.profilePicture!!.url if (senderRecipient.profileKey == null || !MessageDigest.isEqual(senderRecipient.profileKey, profileKey)) { val database = DatabaseFactory.getRecipientDatabase(context) database.setProfileKey(senderRecipient, profileKey) @@ -204,9 +201,9 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki } // If we got a message from our master device then make sure our mappings stay in sync val recipient = Recipient.from(context, Address.fromSerialized(message.hexEncodedPublicKey), false) - if (recipient.isOurMasterDevice && message.avatar != null) { - val profileKey = message.avatar!!.profileKey - val url = message.avatar!!.url + if (recipient.isOurMasterDevice && message.profilePicture != null) { + val profileKey = message.profilePicture!!.profileKey + val url = message.profilePicture!!.url if (recipient.profileKey == null || !MessageDigest.isEqual(recipient.profileKey, profileKey)) { val database = DatabaseFactory.getRecipientDatabase(context) database.setProfileKey(recipient, profileKey) @@ -220,16 +217,16 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki val userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(context).privateKey.serialize() val database = DatabaseFactory.getLokiAPIDatabase(context) LokiFileServerAPI.configure(false, userHexEncodedPublicKey, userPrivateKey, database) - LokiFileServerAPI.shared.getAllDevicePublicKeys(userHexEncodedPublicKey).bind { devices -> + LokiDeviceLinkUtilities.getAllLinkedDeviceHexEncodedPublicKeys(userHexEncodedPublicKey).bind { devices -> userDevices = devices api.getMessages(group.channel, group.server) }.bind { messages -> if (messages.isNotEmpty()) { // We need to fetch device mappings for all the devices we don't have uniqueDevices = messages.map { it.hexEncodedPublicKey }.toSet() - val devicesToUpdate = uniqueDevices.filter { !userDevices.contains(it) && LokiFileServerAPI.shared.hasCacheExpired(it) } + val devicesToUpdate = uniqueDevices.filter { !userDevices.contains(it) && LokiFileServerAPI.shared.hasDeviceLinkCacheExpired(hexEncodedPublicKey = it) } if (devicesToUpdate.isNotEmpty()) { - return@bind LokiFileServerAPI.shared.getDeviceMappings(devicesToUpdate.toSet()).then { messages } + return@bind LokiFileServerAPI.shared.getDeviceLinks(devicesToUpdate.toSet()).then { messages } } } Promise.of(messages) @@ -238,7 +235,7 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki val newDisplayNameUpdatees = uniqueDevices.mapNotNull { // This will return null if current device is primary // So if it's non-null then we know the device is a secondary device - val primaryDevice = LokiFileServerAPI.shared.getPrimaryDevicePublicKey(it).get() + val primaryDevice = LokiDeviceLinkUtilities.getMasterHexEncodedPublicKey(it).get() primaryDevice }.toSet() // Fetch the display names of the primary devices diff --git a/src/org/thoughtcrime/securesms/loki/redesign/utilities/MentionUtilities.kt b/src/org/thoughtcrime/securesms/loki/redesign/utilities/MentionUtilities.kt index 4a29eef131..a425262411 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/utilities/MentionUtilities.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/utilities/MentionUtilities.kt @@ -53,7 +53,7 @@ object MentionUtilities { } } val result = SpannableString(text) - val userLinkedDeviceHexEncodedPublicKeys = DatabaseFactory.getLokiAPIDatabase(context).getPairingAuthorisations(userHexEncodedPublicKey).flatMap { listOf( it.primaryDevicePublicKey, it.secondaryDevicePublicKey ) }.toMutableSet() + val userLinkedDeviceHexEncodedPublicKeys = DatabaseFactory.getLokiAPIDatabase(context).getDeviceLinks(userHexEncodedPublicKey).flatMap { listOf( it.masterHexEncodedPublicKey, it.slaveHexEncodedPublicKey ) }.toMutableSet() userLinkedDeviceHexEncodedPublicKeys.add(userHexEncodedPublicKey) for (mention in mentions) { if (!userLinkedDeviceHexEncodedPublicKeys.contains(mention.second)) { continue } diff --git a/src/org/thoughtcrime/securesms/sms/MessageSender.java b/src/org/thoughtcrime/securesms/sms/MessageSender.java index 4dfa91f4c3..d8c8e20fc5 100644 --- a/src/org/thoughtcrime/securesms/sms/MessageSender.java +++ b/src/org/thoughtcrime/securesms/sms/MessageSender.java @@ -60,7 +60,7 @@ import org.thoughtcrime.securesms.util.Util; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.push.ContactTokenDetails; -import org.whispersystems.signalservice.loki.api.LokiFileServerAPI; +import org.whispersystems.signalservice.loki.api.LokiDeviceLinkUtilities; import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus; import org.whispersystems.signalservice.loki.utilities.PromiseUtil; @@ -99,7 +99,7 @@ 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 - LokiFileServerAPI.shared.getAllDevicePublicKeys(contactHexEncodedPublicKey).success(devices -> { + LokiDeviceLinkUtilities.INSTANCE.getAllLinkedDeviceHexEncodedPublicKeys(contactHexEncodedPublicKey).success(devices -> { Util.runOnMain(() -> { for (String device : devices) { // Don't send message to the device we already have sent to @@ -234,7 +234,7 @@ public class MessageSender { final int ttl) { String ourPublicKey = TextSecurePreferences.getLocalNumber(context); JobManager jobManager = ApplicationContext.getInstance(context).getJobManager(); - LokiFileServerAPI.shared.getAllDevicePublicKeys(ourPublicKey).success(devices -> { + LokiDeviceLinkUtilities.INSTANCE.getAllLinkedDeviceHexEncodedPublicKeys(ourPublicKey).success(devices -> { Util.runOnMain(() -> { for (String device : devices) { // Don't send to ourselves