From 373b9b38f657b43613ca3d2fe5147b14a2e59f2f Mon Sep 17 00:00:00 2001 From: Mikunj Date: Tue, 1 Oct 2019 16:12:37 +1000 Subject: [PATCH] Moved pairing logic into dialog. Refactor. --- .../ApplicationPreferencesActivity.java | 2 +- .../securesms/loki/DeviceLinkingDialog.kt | 216 +++++------------- .../loki/DeviceLinkingDialogDelegate.kt | 11 +- .../securesms/loki/DeviceLinkingView.kt | 165 +++++++++++++ .../securesms/loki/SeedActivity.kt | 42 +++- .../thoughtcrime/securesms/loki/Utilities.kt | 25 ++ 6 files changed, 293 insertions(+), 168 deletions(-) create mode 100644 src/org/thoughtcrime/securesms/loki/DeviceLinkingView.kt create mode 100644 src/org/thoughtcrime/securesms/loki/Utilities.kt diff --git a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java index 49390c5be8..4f867b19f2 100644 --- a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java +++ b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java @@ -328,7 +328,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA QRCodeDialog.INSTANCE.show(getContext()); break; case PREFERENCE_CATEGORY_LINK_DEVICE: - DeviceLinkingDialog.INSTANCE.show(getContext(), DeviceLinkingView.Mode.Master); + DeviceLinkingDialog.Companion.show(getContext(), DeviceLinkingView.Mode.Master); break; case PREFERENCE_CATEGORY_SEED: File languageFileDirectory = new File(getContext().getApplicationInfo().dataDir); diff --git a/src/org/thoughtcrime/securesms/loki/DeviceLinkingDialog.kt b/src/org/thoughtcrime/securesms/loki/DeviceLinkingDialog.kt index a05c27d846..de36dc5780 100644 --- a/src/org/thoughtcrime/securesms/loki/DeviceLinkingDialog.kt +++ b/src/org/thoughtcrime/securesms/loki/DeviceLinkingDialog.kt @@ -1,148 +1,61 @@ package org.thoughtcrime.securesms.loki import android.content.Context -import android.graphics.Color -import android.graphics.PorterDuff -import android.os.Handler import android.support.v7.app.AlertDialog -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.* -import network.loki.messenger.R import org.thoughtcrime.securesms.crypto.IdentityKeyUtil import org.thoughtcrime.securesms.database.DatabaseFactory -import org.thoughtcrime.securesms.util.TextSecurePreferences -import org.w3c.dom.Text +import org.thoughtcrime.securesms.logging.Log import org.whispersystems.signalservice.loki.api.LokiDeviceLinkingSession +import org.whispersystems.signalservice.loki.api.LokiDeviceLinkingSessionListener import org.whispersystems.signalservice.loki.api.LokiPairingAuthorisation import org.whispersystems.signalservice.loki.api.LokiStorageAPI -import org.whispersystems.signalservice.loki.crypto.MnemonicCodec -import org.whispersystems.signalservice.loki.utilities.removing05PrefixIfNeeded -import java.io.File -import java.io.FileOutputStream -object DeviceLinkingDialog { +class DeviceLinkingDialog private constructor(private val context: Context, private val mode: DeviceLinkingView.Mode, private val delegate: DeviceLinkingDialogDelegate? = null): DeviceLinkingViewDelegate, LokiDeviceLinkingSessionListener { + private lateinit var view: DeviceLinkingView - fun show(context: Context, mode: DeviceLinkingView.Mode) { - val view = DeviceLinkingView(context, mode) + private val userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(context).privateKey.serialize() + + companion object { + fun show(context: Context, mode: DeviceLinkingView.Mode) { show(context, mode, null) } + fun show(context: Context, mode: DeviceLinkingView.Mode, delegate: DeviceLinkingDialogDelegate?) { + val dialog = DeviceLinkingDialog(context, mode, delegate) + dialog.show() + } + } + + private fun show() { + view = DeviceLinkingView(context, mode, this) val dialog = AlertDialog.Builder(context).setView(view).show() - view.dismiss = { dialog.dismiss() } - } -} - -class DeviceLinkingView private constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, private val mode: Mode) : LinearLayout(context, attrs, defStyleAttr) { - private var delegate: DeviceLinkingDialogDelegate? = null - private lateinit var languageFileDirectory: File - var dismiss: (() -> Unit)? = null - private var pairingAuthorisation: LokiPairingAuthorisation? = null - - // region Types - enum class Mode { Master, Slave } - // endregion - - // region Lifecycle - constructor(context: Context, mode: Mode) : this(context, null, 0, mode) - private constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0, Mode.Master) // Just pass in a dummy mode - private constructor(context: Context) : this(context, null) - - init { - if (mode == Mode.Slave) { - if (delegate == null) { throw IllegalStateException("Missing delegate for device linking dialog in slave mode.") } + view.dismiss = { + this.stopListening() + dialog.dismiss() } - setUpLanguageFileDirectory() - setUpViewHierarchy() + + this.startListening() + } + + // region Private functions + private fun startListening() { LokiDeviceLinkingSession.shared.startListeningForLinkingRequests() + LokiDeviceLinkingSession.shared.addListener(this) } - private fun setUpLanguageFileDirectory() { - val languages = listOf( "english", "japanese", "portuguese", "spanish" ) - val directory = File(context.applicationInfo.dataDir) - for (language in languages) { - val fileName = "$language.txt" - if (directory.list().contains(fileName)) { continue } - val inputStream = context.assets.open("mnemonic/$fileName") - val file = File(directory, fileName) - val outputStream = FileOutputStream(file) - val buffer = ByteArray(1024) - while (true) { - val count = inputStream.read(buffer) - if (count < 0) { break } - outputStream.write(buffer, 0, count) - } - inputStream.close() - outputStream.close() - } - languageFileDirectory = directory - } - - private fun setUpViewHierarchy() { - inflate(context, R.layout.view_device_linking, this) - spinner.indeterminateDrawable.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN) - val titleID = when (mode) { - Mode.Master -> R.string.view_device_linking_title_1 - Mode.Slave -> R.string.view_device_linking_title_2 - } - titleTextView.text = resources.getString(titleID) - val explanationID = when (mode) { - Mode.Master -> R.string.view_device_linking_explanation_1 - Mode.Slave -> R.string.view_device_linking_explanation_2 - } - explanationTextView.text = resources.getString(explanationID) - mnemonicTextView.visibility = if (mode == Mode.Master) View.GONE else View.VISIBLE - if (mode == Mode.Slave) { - val hexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context).removing05PrefixIfNeeded() - mnemonicTextView.text = MnemonicCodec(languageFileDirectory).encode(hexEncodedPublicKey).split(" ").slice(0 until 3).joinToString(" ") - } - authorizeButton.visibility = View.GONE - authorizeButton.setOnClickListener { authorizeDeviceLink() } - cancelButton.setOnClickListener { cancel() } + private fun stopListening() { + LokiDeviceLinkingSession.shared.stopListeningForLinkingRequests() + LokiDeviceLinkingSession.shared.removeListener(this) } // endregion - // region Device Linking - private fun requestUserAuthorization(authorisation: LokiPairingAuthorisation) { - // To be called by DeviceLinkingSession when a linking request has been received - if (this.pairingAuthorisation != null) { - Log.e("Loki", "Received request for another pairing authorisation when one was active") - return - } - - if (!authorisation.verify()) { - Log.w("Loki", "Received authorisation but it was not valid.") - return - } - - this.pairingAuthorisation = authorisation - - // Stop listening to any more requests - LokiDeviceLinkingSession.shared.stopListeningForLinkingRequests() - - spinner.visibility = View.GONE - val titleTextViewLayoutParams = titleTextView.layoutParams as LayoutParams - titleTextViewLayoutParams.topMargin = toPx(16, resources) - titleTextView.layoutParams = titleTextViewLayoutParams - titleTextView.text = resources.getString(R.string.view_device_linking_title_3) - explanationTextView.text = resources.getString(R.string.view_device_linking_explanation_2) - mnemonicTextView.visibility = View.VISIBLE - val hexEncodedPublicKey = authorisation.secondaryDevicePubKey.removing05PrefixIfNeeded() - mnemonicTextView.text = MnemonicCodec(languageFileDirectory).encode(hexEncodedPublicKey).split(" ").slice(0 until 3).joinToString(" ") - authorizeButton.visibility = View.VISIBLE - } - - private fun authorizeDeviceLink() { - if (pairingAuthorisation == null) { return; } - - val authorisation = pairingAuthorisation!! - val userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(context).privateKey.serialize() - val signedAuthorisation = authorisation.sign(LokiPairingAuthorisation.Type.GRANT, userPrivateKey) + // region Dialog View Delegate + override fun authorise(pairing: LokiPairingAuthorisation): Boolean { + val signedAuthorisation = pairing.sign(LokiPairingAuthorisation.Type.GRANT, userPrivateKey) if (signedAuthorisation == null) { Log.e("Loki", "Failed to sign grant authorisation") - return + return false } - // TODO: Send authorisation message + // Send authorisation message + sendAuthorisationMessage(context, pairing.secondaryDevicePubKey, signedAuthorisation) // Add the auth to the database DatabaseFactory.getLokiAPIDatabase(context).insertOrUpdatePairingAuthorisation(signedAuthorisation) @@ -150,49 +63,38 @@ class DeviceLinkingView private constructor(context: Context, attrs: AttributeSe // Update the api LokiStorageAPI.shared?.updateOurDeviceMappings() - dismiss() + return true } - private fun handleDeviceLinkAuthorized() { // TODO: deviceLink parameter - // To be called by DeviceLinkingSession when a device link has been authorized - // Pairings get automatically added to the database when we receive them - LokiDeviceLinkingSession.shared.stopListeningForLinkingRequests() - - spinner.visibility = View.GONE - val titleTextViewLayoutParams = titleTextView.layoutParams as LayoutParams - titleTextViewLayoutParams.topMargin = toPx(8, resources) - titleTextView.layoutParams = titleTextViewLayoutParams - titleTextView.text = resources.getString(R.string.view_device_linking_title_4) - val explanationTextViewLayoutParams = explanationTextView.layoutParams as LayoutParams - explanationTextViewLayoutParams.bottomMargin = toPx(12, resources) - explanationTextView.layoutParams = explanationTextViewLayoutParams - explanationTextView.text = resources.getString(R.string.view_device_linking_explanation_3) - titleTextView.text = resources.getString(R.string.view_device_linking_title_4) - mnemonicTextView.visibility = View.GONE - buttonContainer.visibility = View.GONE - - Handler().postDelayed({ - delegate?.handleDeviceLinkAuthorized() - dismiss() - }, 4000) - } - // endregion - - // region Interaction - private fun dismiss() { - LokiDeviceLinkingSession.shared.stopListeningForLinkingRequests() - dismiss?.invoke() + override fun handleDeviceLinkAuthorized() { + delegate?.handleDeviceLinkAuthorized() } - private fun cancel() { - if (mode == Mode.Master && pairingAuthorisation != null) { - val authorisation = pairingAuthorisation!! + 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.secondaryDevicePubKey) } - delegate?.handleDeviceLinkingDialogDismissed() // Only relevant in slave mode - dismiss() + delegate?.handleDeviceLinkingDialogDismissed() + } + // endregion + + // region Loki Device Session Listener + override fun onDeviceLinkingRequestReceived(authorisation: LokiPairingAuthorisation) { + view.requestUserAuthorization(authorisation) + + // Stop listening to any more requests + LokiDeviceLinkingSession.shared.stopListeningForLinkingRequests() + } + + override fun onDeviceLinkRequestAccepted(authorisation: LokiPairingAuthorisation) { + view.onDeviceLinkAuthorized(authorisation) + + // Stop listening to any more requests + LokiDeviceLinkingSession.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 61e73408cf..8c86b05bd0 100644 --- a/src/org/thoughtcrime/securesms/loki/DeviceLinkingDialogDelegate.kt +++ b/src/org/thoughtcrime/securesms/loki/DeviceLinkingDialogDelegate.kt @@ -1,7 +1,12 @@ package org.thoughtcrime.securesms.loki -interface DeviceLinkingDialogDelegate { +import org.whispersystems.signalservice.loki.api.LokiPairingAuthorisation - fun handleDeviceLinkAuthorized() // TODO: Device link - fun handleDeviceLinkingDialogDismissed() +interface DeviceLinkingDialogDelegate { + fun handleDeviceLinkAuthorized() {} + fun handleDeviceLinkingDialogDismissed() {} +} + +interface DeviceLinkingViewDelegate: DeviceLinkingDialogDelegate { + fun authorise(pairing: LokiPairingAuthorisation): Boolean { return false } } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/DeviceLinkingView.kt b/src/org/thoughtcrime/securesms/loki/DeviceLinkingView.kt new file mode 100644 index 0000000000..0095656413 --- /dev/null +++ b/src/org/thoughtcrime/securesms/loki/DeviceLinkingView.kt @@ -0,0 +1,165 @@ +package org.thoughtcrime.securesms.loki + +import android.content.Context +import android.graphics.Color +import android.graphics.PorterDuff +import android.os.Handler +import android.os.Looper +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.* +import network.loki.messenger.R +import org.thoughtcrime.securesms.ApplicationContext +import org.thoughtcrime.securesms.database.DatabaseFactory +import org.thoughtcrime.securesms.util.TextSecurePreferences +import org.whispersystems.libsignal.util.guava.Optional +import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair +import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage +import org.whispersystems.signalservice.api.push.SignalServiceAddress +import org.whispersystems.signalservice.loki.api.LokiDeviceLinkingSession +import org.whispersystems.signalservice.loki.api.LokiPairingAuthorisation +import org.whispersystems.signalservice.loki.crypto.MnemonicCodec +import org.whispersystems.signalservice.loki.utilities.removing05PrefixIfNeeded +import java.io.File +import java.io.FileOutputStream + +class DeviceLinkingView private constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, private val mode: Mode, private var delegate: DeviceLinkingViewDelegate) : LinearLayout(context, attrs, defStyleAttr) { + private lateinit var languageFileDirectory: File + var dismiss: (() -> Unit)? = null + var pairingAuthorisation: LokiPairingAuthorisation? = null + private set + + // region Types + enum class Mode { Master, Slave } + // endregion + + // 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) : this(context, null) + + init { + setUpLanguageFileDirectory() + setUpViewHierarchy() + } + + private fun setUpLanguageFileDirectory() { + val languages = listOf( "english", "japanese", "portuguese", "spanish" ) + val directory = File(context.applicationInfo.dataDir) + for (language in languages) { + val fileName = "$language.txt" + if (directory.list().contains(fileName)) { continue } + val inputStream = context.assets.open("mnemonic/$fileName") + val file = File(directory, fileName) + val outputStream = FileOutputStream(file) + val buffer = ByteArray(1024) + while (true) { + val count = inputStream.read(buffer) + if (count < 0) { break } + outputStream.write(buffer, 0, count) + } + inputStream.close() + outputStream.close() + } + languageFileDirectory = directory + } + + private fun setUpViewHierarchy() { + inflate(context, R.layout.view_device_linking, this) + spinner.indeterminateDrawable.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN) + val titleID = when (mode) { + Mode.Master -> R.string.view_device_linking_title_1 + Mode.Slave -> R.string.view_device_linking_title_2 + } + titleTextView.text = resources.getString(titleID) + val explanationID = when (mode) { + Mode.Master -> R.string.view_device_linking_explanation_1 + Mode.Slave -> R.string.view_device_linking_explanation_2 + } + explanationTextView.text = resources.getString(explanationID) + mnemonicTextView.visibility = if (mode == Mode.Master) View.GONE else View.VISIBLE + if (mode == Mode.Slave) { + val hexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context).removing05PrefixIfNeeded() + mnemonicTextView.text = MnemonicCodec(languageFileDirectory).encode(hexEncodedPublicKey).split(" ").slice(0 until 3).joinToString(" ") + } + authorizeButton.visibility = View.GONE + authorizeButton.setOnClickListener { authorize() } + cancelButton.setOnClickListener { cancel() } + } + // endregion + + // region Device Linking + fun requestUserAuthorization(authorisation: LokiPairingAuthorisation) { + // 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 != LokiPairingAuthorisation.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 + } + + this.pairingAuthorisation = authorisation + + spinner.visibility = View.GONE + val titleTextViewLayoutParams = titleTextView.layoutParams as LayoutParams + titleTextViewLayoutParams.topMargin = toPx(16, resources) + titleTextView.layoutParams = titleTextViewLayoutParams + titleTextView.text = resources.getString(R.string.view_device_linking_title_3) + explanationTextView.text = resources.getString(R.string.view_device_linking_explanation_2) + mnemonicTextView.visibility = View.VISIBLE + val hexEncodedPublicKey = authorisation.secondaryDevicePubKey.removing05PrefixIfNeeded() + mnemonicTextView.text = MnemonicCodec(languageFileDirectory).encode(hexEncodedPublicKey).split(" ").slice(0 until 3).joinToString(" ") + authorizeButton.visibility = View.VISIBLE + } + + 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: LokiPairingAuthorisation) { + // To be called when a device link was accepted by the primary device + if (mode == Mode.Master || authorisation != pairingAuthorisation) { return } + + spinner.visibility = View.GONE + val titleTextViewLayoutParams = titleTextView.layoutParams as LayoutParams + titleTextViewLayoutParams.topMargin = toPx(8, resources) + titleTextView.layoutParams = titleTextViewLayoutParams + titleTextView.text = resources.getString(R.string.view_device_linking_title_4) + val explanationTextViewLayoutParams = explanationTextView.layoutParams as LayoutParams + explanationTextViewLayoutParams.bottomMargin = toPx(12, resources) + explanationTextView.layoutParams = explanationTextViewLayoutParams + explanationTextView.text = resources.getString(R.string.view_device_linking_explanation_3) + titleTextView.text = resources.getString(R.string.view_device_linking_title_4) + mnemonicTextView.visibility = View.GONE + buttonContainer.visibility = View.GONE + + Handler().postDelayed({ + delegate.handleDeviceLinkAuthorized() + dismiss?.invoke() + }, 4000) + } + // endregion + + // region Interaction + private fun cancel() { + delegate.handleDeviceLinkingDialogDismissed() + dismiss?.invoke() + } + // endregion +} \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/SeedActivity.kt b/src/org/thoughtcrime/securesms/loki/SeedActivity.kt index 3efc94e086..adf1aedc27 100644 --- a/src/org/thoughtcrime/securesms/loki/SeedActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/SeedActivity.kt @@ -16,10 +16,12 @@ import org.thoughtcrime.securesms.crypto.IdentityKeyUtil import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.IdentityDatabase +import org.thoughtcrime.securesms.logging.Log import org.thoughtcrime.securesms.util.Hex import org.thoughtcrime.securesms.util.TextSecurePreferences import org.whispersystems.curve25519.Curve25519 import org.whispersystems.libsignal.util.KeyHelper +import org.whispersystems.signalservice.loki.api.LokiPairingAuthorisation import org.whispersystems.signalservice.loki.crypto.MnemonicCodec import org.whispersystems.signalservice.loki.utilities.Analytics import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation @@ -36,8 +38,6 @@ class SeedActivity : BaseActionBarActivity() { private var mnemonic: String? = null set(newValue) { field = newValue; updateMnemonicTextView() } - private var dialog: ProgressDialog? = null - // region Types enum class Mode { Register, Restore, Link } // endregion @@ -177,7 +177,7 @@ class SeedActivity : BaseActionBarActivity() { } val hexEncodedSeed = Hex.toStringCondensed(seed) IdentityKeyUtil.save(this, IdentityKeyUtil.lokiSeedKey, hexEncodedSeed) - if (seed.count() == 16) seed = seed + seed + if (seed.count() == 16) seed += seed if (mode == Mode.Restore) { IdentityKeyUtil.generateIdentityKeyPair(this, seed) } @@ -197,18 +197,46 @@ class SeedActivity : BaseActionBarActivity() { if (mode == Mode.Link) { TextSecurePreferences.setHasSeenWelcomeScreen(this, true) TextSecurePreferences.setPromptedPushRegistration(this, true) + + // Build the pairing request + val primaryDevicePublicKey = publicKeyEditText.text.trim().toString() + val authorisation = LokiPairingAuthorisation(primaryDevicePublicKey, hexEncodedPublicKey).sign(LokiPairingAuthorisation.Type.REQUEST, keyPair.privateKey.serialize()) + if (authorisation == null) { + Log.w("Loki", "Failed to sign outgoing pairing request :(") + resetRegistration() + return Toast.makeText(application, "Failed to initialise device pairing", Toast.LENGTH_SHORT).show() + } + val application = ApplicationContext.getInstance(this) application.startLongPollingIfNeeded() application.setUpStorageAPIIfNeeded() - // TODO: Show activity view here? + // Show the dialog + DeviceLinkingDialog.show(this, DeviceLinkingView.Mode.Slave, object: DeviceLinkingDialogDelegate { + override fun handleDeviceLinkAuthorized() { + showAccountDetailsView() + } - // TODO: Also need to reset on registration + override fun handleDeviceLinkingDialogDismissed() { + resetRegistration() + Toast.makeText(application, "Cancelled Device Linking", Toast.LENGTH_SHORT).show() + } + }) + // Send the request to the other user + sendAuthorisationMessage(this, authorisation.primaryDevicePubKey, authorisation) } else { - startActivity(Intent(this, AccountDetailsActivity::class.java)) - finish() + showAccountDetailsView() } } + + private fun showAccountDetailsView() { + startActivity(Intent(this, AccountDetailsActivity::class.java)) + finish() + } + + private fun resetRegistration() { + + } // endregion } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/Utilities.kt b/src/org/thoughtcrime/securesms/loki/Utilities.kt new file mode 100644 index 0000000000..efcaa4d1b4 --- /dev/null +++ b/src/org/thoughtcrime/securesms/loki/Utilities.kt @@ -0,0 +1,25 @@ +package org.thoughtcrime.securesms.loki + +import android.content.Context +import android.os.Handler +import android.os.Looper +import org.thoughtcrime.securesms.ApplicationContext +import org.thoughtcrime.securesms.logging.Log +import org.whispersystems.libsignal.util.guava.Optional +import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair +import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage +import org.whispersystems.signalservice.api.push.SignalServiceAddress +import org.whispersystems.signalservice.loki.api.LokiPairingAuthorisation + +fun sendAuthorisationMessage(context: Context, contactHexEncodedPublicKey: String, authorisation: LokiPairingAuthorisation) { + Handler(Looper.getMainLooper()).post { + val messageSender = ApplicationContext.getInstance(context).communicationModule.provideSignalMessageSender() + val address = SignalServiceAddress(contactHexEncodedPublicKey) + val message = SignalServiceDataMessage.newBuilder().withBody("").withPairingAuthorisation(authorisation).build() + try { + messageSender.sendMessage(0, address, Optional.absent(), message) // The message ID doesn't matter + } catch (e: Exception) { + Log.d("Loki", "Failed to send authorisation message to: $contactHexEncodedPublicKey.") + } + } +} \ No newline at end of file