diff --git a/src/org/thoughtcrime/securesms/ApplicationContext.java b/src/org/thoughtcrime/securesms/ApplicationContext.java index cfe36fc81d..963daa56ad 100644 --- a/src/org/thoughtcrime/securesms/ApplicationContext.java +++ b/src/org/thoughtcrime/securesms/ApplicationContext.java @@ -432,9 +432,9 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc public void setUpStorageAPIIfNeeded() { String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this); if (userHexEncodedPublicKey != null && IdentityKeyUtil.hasIdentityKey(this)) { + boolean isDebugMode = BuildConfig.DEBUG; byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize(); LokiAPIDatabaseProtocol database = DatabaseFactory.getLokiAPIDatabase(this); - boolean isDebugMode = BuildConfig.DEBUG; LokiStorageAPI.Companion.configure(isDebugMode, userHexEncodedPublicKey, userPrivateKey, database); } } diff --git a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java index 65b954a782..e49a66a13e 100644 --- a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java +++ b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java @@ -335,7 +335,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA QRCodeDialog.INSTANCE.show(getContext()); break; case PREFERENCE_CATEGORY_LINK_DEVICE: - DeviceLinkingDialog.Companion.show(getContext(), DeviceLinkingView.Mode.Master); + DeviceLinkingDialog.Companion.show(getContext(), DeviceLinkingView.Mode.Master, null); break; case PREFERENCE_CATEGORY_SEED: Analytics.Companion.getShared().track("Seed Modal Shown"); diff --git a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index d30ae74dfd..51d45e6c2d 100644 --- a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -125,7 +125,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { db.execSQL(LokiAPIDatabase.getCreateGroupChatAuthTokenTableCommand()); db.execSQL(LokiAPIDatabase.getCreateLastMessageServerIDTableCommand()); db.execSQL(LokiAPIDatabase.getCreateLastDeletionServerIDTableCommand()); - db.execSQL(LokiAPIDatabase.getCreateMultiDeviceAuthTableCommand()); + db.execSQL(LokiAPIDatabase.getCreatePairingAuthorisationTableCommand()); db.execSQL(LokiPreKeyBundleDatabase.getCreateTableCommand()); db.execSQL(LokiPreKeyRecordDatabase.getCreateTableCommand()); db.execSQL(LokiMessageDatabase.getCreateTableCommand()); @@ -496,7 +496,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { } if (oldVersion < lokiV3) { - db.execSQL(LokiAPIDatabase.getCreateMultiDeviceAuthTableCommand()); + db.execSQL(LokiAPIDatabase.getCreatePairingAuthorisationTableCommand()); } db.setTransactionSuccessful(); diff --git a/src/org/thoughtcrime/securesms/loki/DeviceLinkingDialog.kt b/src/org/thoughtcrime/securesms/loki/DeviceLinkingDialog.kt index 22fedc9866..45d843693a 100644 --- a/src/org/thoughtcrime/securesms/loki/DeviceLinkingDialog.kt +++ b/src/org/thoughtcrime/securesms/loki/DeviceLinkingDialog.kt @@ -12,14 +12,14 @@ import org.whispersystems.signalservice.loki.api.LokiStorageAPI import org.whispersystems.signalservice.loki.api.PairingAuthorisation import org.whispersystems.signalservice.loki.utilities.retryIfNeeded -class DeviceLinkingDialog private constructor(private val context: Context, private val mode: DeviceLinkingView.Mode, private val delegate: DeviceLinkingDialogDelegate? = null): DeviceLinkingViewDelegate, DeviceLinkingSessionListener { +class DeviceLinkingDialog private constructor(private val context: Context, private val mode: DeviceLinkingView.Mode, private val delegate: DeviceLinkingDialogDelegate?) : DeviceLinkingViewDelegate, DeviceLinkingSessionListener { private lateinit var view: DeviceLinkingView private lateinit var dialog: AlertDialog private val userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(context).privateKey.serialize() companion object { - fun show(context: Context, mode: DeviceLinkingView.Mode): DeviceLinkingDialog { return show(context, mode, null) } + fun show(context: Context, mode: DeviceLinkingView.Mode, delegate: DeviceLinkingDialogDelegate?): DeviceLinkingDialog { val dialog = DeviceLinkingDialog(context, mode, delegate) dialog.show() @@ -27,20 +27,18 @@ class DeviceLinkingDialog private constructor(private val context: Context, priv } } - public fun dismiss() { - this.stopListening() - dialog.dismiss() - } - private fun show() { view = DeviceLinkingView(context, mode, this) dialog = AlertDialog.Builder(context).setView(view).show() view.dismiss = { dismiss() } - - this.startListening() + startListening() + } + + public fun dismiss() { + stopListening() + dialog.dismiss() } - // region Private functions private fun startListening() { DeviceLinkingSession.shared.startListeningForLinkingRequests() DeviceLinkingSession.shared.addListener(this) @@ -50,29 +48,20 @@ class DeviceLinkingDialog private constructor(private val context: Context, priv DeviceLinkingSession.shared.stopListeningForLinkingRequests() DeviceLinkingSession.shared.removeListener(this) } - // endregion - // region Dialog View Delegate - override fun authorise(pairing: PairingAuthorisation): Boolean { + override fun sendPairingAuthorizedMessage(pairing: PairingAuthorisation): Boolean { val signedAuthorisation = pairing.sign(PairingAuthorisation.Type.GRANT, userPrivateKey) if (signedAuthorisation == null || signedAuthorisation.type != PairingAuthorisation.Type.GRANT) { - Log.e("Loki", "Failed to sign grant authorisation") + Log.d("Loki", "Failed to sign pairing authorization.") return false } - - // Send authorisation message - retryIfNeeded(3) { - sendAuthorisationMessage(context, pairing.secondaryDevicePublicKey, signedAuthorisation) + retryIfNeeded(8) { + sendPairingAuthorisationMessage(context, pairing.secondaryDevicePublicKey, signedAuthorisation).get() }.fail { - Log.e("Loki", "Failed to send GRANT authorisation to ${pairing.secondaryDevicePublicKey}") + Log.d("Loki", "Failed to send pairing authorization message to ${pairing.secondaryDevicePublicKey}.") } - - // Add the auth to the database DatabaseFactory.getLokiAPIDatabase(context).insertOrUpdatePairingAuthorisation(signedAuthorisation) - - // Update the api - LokiStorageAPI.shared?.updateUserDeviceMappings() - + LokiStorageAPI.shared.updateUserDeviceMappings() return true } @@ -81,24 +70,17 @@ class DeviceLinkingDialog private constructor(private val context: Context, priv } override fun handleDeviceLinkingDialogDismissed() { - // If we cancelled while we were listening for requests on main device, we need to remove any pre key bundles if (mode == DeviceLinkingView.Mode.Master && view.pairingAuthorisation != null) { val authorisation = view.pairingAuthorisation!! - // Remove pre key bundle from the requesting device DatabaseFactory.getLokiPreKeyBundleDatabase(context).removePreKeyBundle(authorisation.secondaryDevicePublicKey) } - delegate?.handleDeviceLinkingDialogDismissed() } - // endregion - // region Loki Device Session Listener override fun requestUserAuthorization(authorisation: PairingAuthorisation) { Util.runOnMain { view.requestUserAuthorization(authorisation) } - - // Stop listening to any more requests DeviceLinkingSession.shared.stopListeningForLinkingRequests() } @@ -106,9 +88,6 @@ class DeviceLinkingDialog private constructor(private val context: Context, priv Util.runOnMain { view.onDeviceLinkAuthorized(authorisation) } - - // Stop listening to any more requests DeviceLinkingSession.shared.stopListeningForLinkingRequests() } - // endregion } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/DeviceLinkingDialogDelegate.kt b/src/org/thoughtcrime/securesms/loki/DeviceLinkingDialogDelegate.kt index 3d5a4a146e..191560220b 100644 --- a/src/org/thoughtcrime/securesms/loki/DeviceLinkingDialogDelegate.kt +++ b/src/org/thoughtcrime/securesms/loki/DeviceLinkingDialogDelegate.kt @@ -1,12 +1,6 @@ package org.thoughtcrime.securesms.loki -import org.whispersystems.signalservice.loki.api.PairingAuthorisation - interface DeviceLinkingDialogDelegate { - fun handleDeviceLinkAuthorized() {} - fun handleDeviceLinkingDialogDismissed() {} -} - -interface DeviceLinkingViewDelegate: DeviceLinkingDialogDelegate { - fun authorise(pairing: PairingAuthorisation): Boolean { return false } + fun handleDeviceLinkAuthorized() { } + fun handleDeviceLinkingDialogDismissed() { } } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/DeviceLinkingView.kt b/src/org/thoughtcrime/securesms/loki/DeviceLinkingView.kt index cdbf28f591..7447bd0b4b 100644 --- a/src/org/thoughtcrime/securesms/loki/DeviceLinkingView.kt +++ b/src/org/thoughtcrime/securesms/loki/DeviceLinkingView.kt @@ -5,7 +5,6 @@ import android.graphics.Color import android.graphics.PorterDuff import android.os.Handler import android.util.AttributeSet -import android.util.Log import android.view.View import android.widget.LinearLayout import kotlinx.android.synthetic.main.view_device_linking.view.* @@ -29,7 +28,7 @@ class DeviceLinkingView private constructor(context: Context, attrs: AttributeSe // region Lifecycle constructor(context: Context, mode: Mode, delegate: DeviceLinkingViewDelegate) : this(context, null, 0, mode, delegate) - private constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0, Mode.Master, object : DeviceLinkingViewDelegate {}) // Just pass in a dummy mode + private constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0, Mode.Master, object : DeviceLinkingViewDelegate { }) // Just pass in a dummy mode private constructor(context: Context) : this(context, null) init { @@ -77,29 +76,17 @@ class DeviceLinkingView private constructor(context: Context, attrs: AttributeSe mnemonicTextView.text = MnemonicCodec(languageFileDirectory).encode(hexEncodedPublicKey).split(" ").slice(0 until 3).joinToString(" ") } authorizeButton.visibility = View.GONE - authorizeButton.setOnClickListener { authorize() } + authorizeButton.setOnClickListener { authorizePairing() } cancelButton.setOnClickListener { cancel() } } // endregion // region Device Linking fun requestUserAuthorization(authorisation: PairingAuthorisation) { - // To be called when a linking request has been received - if (mode != Mode.Master) { - Log.w("Loki", "Received request for pairing authorisation on a slave device") - return - } - - if (authorisation.type != PairingAuthorisation.Type.REQUEST) { - Log.w("Loki", "Received request for GRANT pairing authorisation! It shouldn't be possible!!") - return - } - - if (this.pairingAuthorisation != null) { - Log.e("Loki", "Received request for another pairing authorisation when one was active") - return - } - + if (mode != Mode.Master) { throw IllegalStateException() } + if (authorisation.type != PairingAuthorisation.Type.REQUEST) { throw IllegalStateException() } + if (pairingAuthorisation != null) { return } + pairingAuthorisation = authorisation spinner.visibility = View.GONE val titleTextViewLayoutParams = titleTextView.layoutParams as LayoutParams titleTextViewLayoutParams.topMargin = toPx(16, resources) @@ -110,25 +97,11 @@ class DeviceLinkingView private constructor(context: Context, attrs: AttributeSe val hexEncodedPublicKey = authorisation.secondaryDevicePublicKey.removing05PrefixIfNeeded() mnemonicTextView.text = MnemonicCodec(languageFileDirectory).encode(hexEncodedPublicKey).split(" ").slice(0 until 3).joinToString(" ") authorizeButton.visibility = View.VISIBLE - - this.pairingAuthorisation = authorisation - } - - private fun authorize() { - if (pairingAuthorisation == null || mode != Mode.Master ) { return; } - - // Pass authorisation to delegate and only dismiss if it succeeded - if (delegate.authorise(pairingAuthorisation!!)) { - delegate.handleDeviceLinkAuthorized() - dismiss?.invoke() - } } fun onDeviceLinkAuthorized(authorisation: PairingAuthorisation) { - // To be called when a device link was accepted by the primary device - if (mode == Mode.Master || pairingAuthorisation != null) { return } + if (mode != Mode.Slave || pairingAuthorisation != null) { return } pairingAuthorisation = authorisation - spinner.visibility = View.GONE val titleTextViewLayoutParams = titleTextView.layoutParams as LayoutParams titleTextViewLayoutParams.topMargin = toPx(8, resources) @@ -142,7 +115,6 @@ class DeviceLinkingView private constructor(context: Context, attrs: AttributeSe mnemonicTextView.visibility = View.GONE buttonContainer.visibility = View.GONE cancelButton.visibility = View.GONE - Handler().postDelayed({ delegate.handleDeviceLinkAuthorized() dismiss?.invoke() @@ -151,6 +123,14 @@ class DeviceLinkingView private constructor(context: Context, attrs: AttributeSe // endregion // region Interaction + private fun authorizePairing() { + if (pairingAuthorisation == null || mode != Mode.Master ) { return; } + if (delegate.sendPairingAuthorizedMessage(pairingAuthorisation!!)) { + delegate.handleDeviceLinkAuthorized() + dismiss?.invoke() + } + } + private fun cancel() { delegate.handleDeviceLinkingDialogDismissed() dismiss?.invoke() diff --git a/src/org/thoughtcrime/securesms/loki/DeviceLinkingViewDelegate.kt b/src/org/thoughtcrime/securesms/loki/DeviceLinkingViewDelegate.kt new file mode 100644 index 0000000000..abd8386427 --- /dev/null +++ b/src/org/thoughtcrime/securesms/loki/DeviceLinkingViewDelegate.kt @@ -0,0 +1,9 @@ +package org.thoughtcrime.securesms.loki + +import org.whispersystems.signalservice.loki.api.PairingAuthorisation + +interface DeviceLinkingViewDelegate { + fun handleDeviceLinkAuthorized() { } + fun handleDeviceLinkingDialogDismissed() { } + fun sendPairingAuthorizedMessage(pairing: PairingAuthorisation): Boolean { return false } +} \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/GeneralUtilities.kt b/src/org/thoughtcrime/securesms/loki/GeneralUtilities.kt index fb881d22cf..9d53000c5d 100644 --- a/src/org/thoughtcrime/securesms/loki/GeneralUtilities.kt +++ b/src/org/thoughtcrime/securesms/loki/GeneralUtilities.kt @@ -1,8 +1,14 @@ package org.thoughtcrime.securesms.loki +import android.content.Context import android.content.res.Resources import android.os.Build import android.support.annotation.ColorRes +import org.thoughtcrime.securesms.database.Address +import org.thoughtcrime.securesms.database.DatabaseFactory +import org.thoughtcrime.securesms.recipients.Recipient +import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI +import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus import kotlin.math.roundToInt fun Resources.getColorWithID(@ColorRes id: Int, theme: Resources.Theme?): Int { @@ -16,4 +22,20 @@ fun Resources.getColorWithID(@ColorRes id: Int, theme: Resources.Theme?): Int { fun toPx(dp: Int, resources: Resources): Int { val scale = resources.displayMetrics.density return (dp * scale).roundToInt() +} + +fun isGroupRecipient(recipient: String): Boolean { + return (LokiGroupChatAPI.publicChatServer == recipient) +} + +fun getFriendPublicKeys(context: Context, devicePublicKeys: Set): Set { + val lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context) + return devicePublicKeys.mapNotNull { device -> + val address = Address.fromSerialized(device) + val recipient = Recipient.from(context, address, false) + val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(recipient) + if (threadID < 0) { return@mapNotNull null } + val friendRequestStatus = lokiThreadDatabase.getFriendRequestStatus(threadID) + if (friendRequestStatus == LokiThreadFriendRequestStatus.FRIENDS) device else null + }.toSet() } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/LokiAPIDatabase.kt b/src/org/thoughtcrime/securesms/loki/LokiAPIDatabase.kt index a2d067d575..166cfe3aed 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiAPIDatabase.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiAPIDatabase.kt @@ -47,14 +47,14 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( private val lastDeletionServerIDCacheIndex = "loki_api_last_deletion_server_id_cache_index" private val lastDeletionServerID = "last_deletion_server_id" @JvmStatic val createLastDeletionServerIDTableCommand = "CREATE TABLE $lastDeletionServerIDCache ($lastDeletionServerIDCacheIndex STRING PRIMARY KEY, $lastDeletionServerID INTEGER DEFAULT 0);" - - // Authorisation - private val multiDeviceAuthTable = "loki_multi_device_authorisation" - private val primaryDevice = "primary_device" - private val secondaryDevice = "secondary_device" + // Pairing authorisation cache + private val pairingAuthorisationCache = "loki_pairing_authorisation_cache" + private val primaryDevicePublicKey = "primary_device" + private val secondaryDevicePublicKey = "secondary_device" private val requestSignature = "request_signature" private val grantSignature = "grant_signature" - @JvmStatic val createMultiDeviceAuthTableCommand = "CREATE TABLE $multiDeviceAuthTable($primaryDevice TEXT, $secondaryDevice TEXT, $requestSignature TEXT NULLABLE DEFAULT NULL, $grantSignature TEXT NULLABLE DEFAULT NULL, PRIMARY KEY ($primaryDevice, $secondaryDevice));" + @JvmStatic val createPairingAuthorisationTableCommand = "CREATE TABLE $pairingAuthorisationCache ($primaryDevicePublicKey TEXT, $secondaryDevicePublicKey TEXT, " + + "$requestSignature TEXT NULLABLE DEFAULT NULL, $grantSignature TEXT NULLABLE DEFAULT NULL, PRIMARY KEY ($primaryDevicePublicKey, $secondaryDevicePublicKey));" } override fun getSwarmCache(hexEncodedPublicKey: String): Set? { @@ -154,9 +154,9 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( override fun getPairingAuthorisations(hexEncodedPublicKey: String): List { val database = databaseHelper.readableDatabase - return database.getAll(multiDeviceAuthTable, "$primaryDevice = ? OR $secondaryDevice = ?", arrayOf(hexEncodedPublicKey, hexEncodedPublicKey)) { cursor -> - val primaryDevicePubKey = cursor.getString(primaryDevice) - val secondaryDevicePubKey = cursor.getString(secondaryDevice) + 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) @@ -166,16 +166,16 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( override fun insertOrUpdatePairingAuthorisation(authorisation: PairingAuthorisation) { val database = databaseHelper.writableDatabase val values = ContentValues() - values.put(primaryDevice, authorisation.primaryDevicePublicKey) - values.put(secondaryDevice, authorisation.secondaryDevicePublicKey) + 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(multiDeviceAuthTable, values, "$primaryDevice = ? AND $secondaryDevice = ?", arrayOf(authorisation.primaryDevicePublicKey, authorisation.secondaryDevicePublicKey)) + database.insertOrUpdate(pairingAuthorisationCache, values, "$primaryDevicePublicKey = ? AND $secondaryDevicePublicKey = ?", arrayOf( authorisation.primaryDevicePublicKey, authorisation.secondaryDevicePublicKey )) } override fun removePairingAuthorisations(hexEncodedPublicKey: String) { val database = databaseHelper.readableDatabase - database.delete(multiDeviceAuthTable, "$primaryDevice = ? OR $secondaryDevice = ?", arrayOf(hexEncodedPublicKey, hexEncodedPublicKey)) + database.delete(pairingAuthorisationCache, "$primaryDevicePublicKey = ? OR $secondaryDevicePublicKey = ?", arrayOf( hexEncodedPublicKey, hexEncodedPublicKey )) } } diff --git a/src/org/thoughtcrime/securesms/loki/MultiDeviceUtil.kt b/src/org/thoughtcrime/securesms/loki/MultiDeviceUtil.kt index 54e6cc4b69..825ae9fe9a 100644 --- a/src/org/thoughtcrime/securesms/loki/MultiDeviceUtil.kt +++ b/src/org/thoughtcrime/securesms/loki/MultiDeviceUtil.kt @@ -28,7 +28,7 @@ fun getAllDevices(context: Context, pubKey: String, storageAPI: LokiStorageAPI, devices.remove(ourPubKey) } - val friends = getFriends(context, devices) + val friends = getFriendPublicKeys(context, devices) for (device in devices) { block(device, friends.contains(device), friends.count()) } @@ -80,7 +80,7 @@ fun shouldAutomaticallyBecomeFriendsWithDevice(pubKey: String, context: Context) return deferred.promise } -fun sendAuthorisationMessage(context: Context, contactHexEncodedPublicKey: String, authorisation: PairingAuthorisation): Promise { +fun sendPairingAuthorisationMessage(context: Context, contactHexEncodedPublicKey: String, authorisation: PairingAuthorisation): Promise { val messageSender = ApplicationContext.getInstance(context).communicationModule.provideSignalMessageSender() val address = SignalServiceAddress(contactHexEncodedPublicKey) val message = SignalServiceDataMessage.newBuilder().withBody("").withPairingAuthorisation(authorisation) diff --git a/src/org/thoughtcrime/securesms/loki/SeedActivity.kt b/src/org/thoughtcrime/securesms/loki/SeedActivity.kt index 3d22ad9a87..a51083562e 100644 --- a/src/org/thoughtcrime/securesms/loki/SeedActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/SeedActivity.kt @@ -233,7 +233,7 @@ class SeedActivity : BaseActionBarActivity() { // Send the request to the other user CoroutineScope(Dispatchers.Main).launch { retryIfNeeded(3) { - sendAuthorisationMessage(this@SeedActivity, authorisation.primaryDevicePublicKey, authorisation).get() + sendPairingAuthorisationMessage(this@SeedActivity, authorisation.primaryDevicePublicKey, authorisation).get() }.failUi { dialog.dismiss() resetRegistration() diff --git a/src/org/thoughtcrime/securesms/loki/Util.kt b/src/org/thoughtcrime/securesms/loki/Util.kt deleted file mode 100644 index 9f4e2d50e0..0000000000 --- a/src/org/thoughtcrime/securesms/loki/Util.kt +++ /dev/null @@ -1,25 +0,0 @@ -package org.thoughtcrime.securesms.loki - -import android.content.Context -import org.thoughtcrime.securesms.database.Address -import org.thoughtcrime.securesms.database.DatabaseFactory -import org.thoughtcrime.securesms.recipients.Recipient -import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI -import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus - -fun isGroupChat(pubKey: String): Boolean { - return (LokiGroupChatAPI.publicChatServer == pubKey) -} - -fun getFriends(context: Context, devices: Set): Set { - val lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context) - - return devices.mapNotNull { device -> - val address = Address.fromSerialized(device) - val recipient = Recipient.from(context, address, false) - val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(recipient) - if (threadID < 0) { return@mapNotNull null } - - if (lokiThreadDatabase.getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS) device else null - }.toSet() -} \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/notifications/MarkReadReceiver.java b/src/org/thoughtcrime/securesms/notifications/MarkReadReceiver.java index 0fd7199923..815f716132 100644 --- a/src/org/thoughtcrime/securesms/notifications/MarkReadReceiver.java +++ b/src/org/thoughtcrime/securesms/notifications/MarkReadReceiver.java @@ -20,11 +20,9 @@ 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.LokiThreadDatabase; import org.thoughtcrime.securesms.loki.MultiDeviceUtilKt; import org.thoughtcrime.securesms.service.ExpiringMessageManager; import org.whispersystems.signalservice.loki.api.LokiStorageAPI; -import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus; import java.util.LinkedList; import java.util.List; @@ -91,20 +89,13 @@ public class MarkReadReceiver extends BroadcastReceiver { for (Address address : addressMap.keySet()) { LokiStorageAPI storageAPI = LokiStorageAPI.Companion.getShared(); - if (storageAPI == null) { - Log.w("Loki", "LokiStorageAPI is not initialized!"); - return; - } List timestamps = Stream.of(addressMap.get(address)).map(SyncMessageId::getTimetamp).toList(); - MultiDeviceUtilKt.getAllDevices(context, address.serialize(), storageAPI, (devicePubKey, isFriend, friendCount) -> { + MultiDeviceUtilKt.getAllDevices(context, address.serialize(), storageAPI, (devicePublicKey, isFriend, friendCount) -> { // Loki - This also prevents read receipts from being sent in group chats as they don't maintain a friend request status if (isFriend) { - Address deviceAddress = Address.fromSerialized(devicePubKey); - ApplicationContext.getInstance(context) - .getJobManager() - .add(new SendReadReceiptJob(deviceAddress, timestamps)); + ApplicationContext.getInstance(context).getJobManager().add(new SendReadReceiptJob(Address.fromSerialized(devicePublicKey), timestamps)); } return Unit.INSTANCE; }); diff --git a/src/org/thoughtcrime/securesms/sms/MessageSender.java b/src/org/thoughtcrime/securesms/sms/MessageSender.java index c3e8c56523..2d872e64a2 100644 --- a/src/org/thoughtcrime/securesms/sms/MessageSender.java +++ b/src/org/thoughtcrime/securesms/sms/MessageSender.java @@ -42,8 +42,8 @@ import org.thoughtcrime.securesms.jobs.SmsSendJob; import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository; import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil; import org.thoughtcrime.securesms.logging.Log; +import org.thoughtcrime.securesms.loki.GeneralUtilitiesKt; import org.thoughtcrime.securesms.loki.MultiDeviceUtilKt; -import org.thoughtcrime.securesms.loki.UtilKt; import org.thoughtcrime.securesms.mms.MmsException; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; import org.thoughtcrime.securesms.push.AccountManagerFactory; @@ -211,27 +211,26 @@ public class MessageSender { LokiStorageAPI storageAPI = LokiStorageAPI.Companion.getShared(); JobManager jobManager = ApplicationContext.getInstance(context).getJobManager(); - // Just send the message normally if the storage api is not set or if it's a group message - String recipientPubKey = recipient.getAddress().serialize(); - if (storageAPI == null || UtilKt.isGroupChat(recipientPubKey)) { - if (storageAPI == null) { Log.w("Loki", "LokiStorageAPI is not initialized!"); } + // Just send the message normally if it's a group message + String recipientPublicKey = recipient.getAddress().serialize(); + if (GeneralUtilitiesKt.isGroupRecipient(recipientPublicKey)) { jobManager.add(new PushTextSendJob(messageId, recipient.getAddress())); return; } - MultiDeviceUtilKt.getAllDevices(context, recipientPubKey, storageAPI, (devicePubKey, isFriend, friendCount) -> { - Address deviceAddress = Address.fromSerialized(devicePubKey); - long messageIdToUse = recipientPubKey.equals(devicePubKey) ? messageId : -1L; + MultiDeviceUtilKt.getAllDevices(context, recipientPublicKey, storageAPI, (devicePublicKey, isFriend, friendCount) -> { + Address address = Address.fromSerialized(devicePublicKey); + long messageIDToUse = recipientPublicKey.equals(devicePublicKey) ? messageId : -1L; - // Send a normal message to our friends if (isFriend) { - jobManager.add(new PushTextSendJob(messageId, messageIdToUse, deviceAddress)); + // Send a normal message if the user is friends with the recipient + jobManager.add(new PushTextSendJob(messageId, messageIDToUse, address)); } else { - // Send friend requests to non friends - // If we're friends with one of the devices then send out a default friend request message - boolean isFriendsWithAny = friendCount > 0; - String defaultFriendRequestMessage = isFriendsWithAny ? "This is a friend request for devices linked to " + recipientPubKey : null; - jobManager.add(new PushTextSendJob(messageId, messageIdToUse, deviceAddress, true, defaultFriendRequestMessage)); + // 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)); } return Unit.INSTANCE; @@ -242,26 +241,26 @@ public class MessageSender { LokiStorageAPI storageAPI = LokiStorageAPI.Companion.getShared(); JobManager jobManager = ApplicationContext.getInstance(context).getJobManager(); - // Just send the message normally if the storage api is not set or if it's a group message - String recipientPubKey = recipient.getAddress().serialize(); - if (storageAPI == null || UtilKt.isGroupChat(recipientPubKey)) { - if (storageAPI == null) { Log.w("Loki", "LokiStorageAPI is not initialized!"); } + // Just send the message normally if it's a group message + String recipientPublicKey = recipient.getAddress().serialize(); + if (GeneralUtilitiesKt.isGroupRecipient(recipientPublicKey)) { PushMediaSendJob.enqueue(context, jobManager, messageId, recipient.getAddress()); + return; } - MultiDeviceUtilKt.getAllDevices(context, recipientPubKey, storageAPI, (devicePubKey, isFriend, friendCount) -> { - Address deviceAddress = Address.fromSerialized(devicePubKey); - long messageIdToUse = recipientPubKey.equals(devicePubKey) ? messageId : -1L; + MultiDeviceUtilKt.getAllDevices(context, recipientPublicKey, storageAPI, (devicePublicKey, isFriend, friendCount) -> { + Address address = Address.fromSerialized(devicePublicKey); + long messageIDToUse = recipientPublicKey.equals(devicePublicKey) ? messageId : -1L; - // Send a normal message to our friends if (isFriend) { - PushMediaSendJob.enqueue(context, jobManager, messageId, messageIdToUse, deviceAddress); + // Send a normal message if the user is friends with the recipient + PushMediaSendJob.enqueue(context, jobManager, messageId, messageIDToUse, address); } else { - // Send friend requests to non friends - // If we're friends with one of the devices then send out a default friend request message + // 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 ? "This is a friend request for devices linked to " + recipientPubKey : null; - PushMediaSendJob.enqueue(context, jobManager, messageId, messageIdToUse, deviceAddress, true, defaultFriendRequestMessage); + 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); } return Unit.INSTANCE;