Somewhat simplify device linking UI

This commit is contained in:
Niels Andriesse 2019-10-08 14:28:30 +11:00
parent a44c3fcd57
commit ac9c9f534e
6 changed files with 45 additions and 56 deletions

View File

@ -2,22 +2,16 @@ package org.thoughtcrime.securesms.loki
import android.content.Context
import android.support.v7.app.AlertDialog
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.logging.Log
import org.thoughtcrime.securesms.util.Util
import org.whispersystems.signalservice.loki.api.DeviceLinkingSession
import org.whispersystems.signalservice.loki.api.DeviceLinkingSessionListener
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?) : 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, delegate: DeviceLinkingDialogDelegate?): DeviceLinkingDialog {
@ -31,42 +25,18 @@ class DeviceLinkingDialog private constructor(private val context: Context, priv
view = DeviceLinkingView(context, mode, this)
dialog = AlertDialog.Builder(context).setView(view).show()
view.dismiss = { dismiss() }
startListening()
}
public fun dismiss() {
stopListening()
dialog.dismiss()
}
private fun startListening() {
DeviceLinkingSession.shared.startListeningForLinkingRequests()
DeviceLinkingSession.shared.addListener(this)
}
private fun stopListening() {
private fun dismiss() {
DeviceLinkingSession.shared.stopListeningForLinkingRequests()
DeviceLinkingSession.shared.removeListener(this)
dialog.dismiss()
}
override fun sendPairingAuthorizedMessage(pairing: PairingAuthorisation): Boolean {
val signedAuthorisation = pairing.sign(PairingAuthorisation.Type.GRANT, userPrivateKey)
if (signedAuthorisation == null || signedAuthorisation.type != PairingAuthorisation.Type.GRANT) {
Log.d("Loki", "Failed to sign pairing authorization.")
return false
}
retryIfNeeded(8) {
sendPairingAuthorisationMessage(context, pairing.secondaryDevicePublicKey, signedAuthorisation).get()
}.fail {
Log.d("Loki", "Failed to send pairing authorization message to ${pairing.secondaryDevicePublicKey}.")
}
DatabaseFactory.getLokiAPIDatabase(context).insertOrUpdatePairingAuthorisation(signedAuthorisation)
LokiStorageAPI.shared.updateUserDeviceMappings()
return true
}
override fun handleDeviceLinkAuthorized(pairing: PairingAuthorisation) {
delegate?.handleDeviceLinkAuthorized(pairing)
override fun handleDeviceLinkAuthorized(pairingAuthorisation: PairingAuthorisation) {
delegate?.handleDeviceLinkAuthorized(pairingAuthorisation)
}
override fun handleDeviceLinkingDialogDismissed() {
@ -77,6 +47,10 @@ class DeviceLinkingDialog private constructor(private val context: Context, priv
delegate?.handleDeviceLinkingDialogDismissed()
}
override fun sendPairingAuthorizedMessage(pairingAuthorisation: PairingAuthorisation) {
delegate?.sendPairingAuthorizedMessage(pairingAuthorisation)
}
override fun requestUserAuthorization(authorisation: PairingAuthorisation) {
Util.runOnMain {
view.requestUserAuthorization(authorisation)

View File

@ -4,6 +4,7 @@ import org.whispersystems.signalservice.loki.api.PairingAuthorisation
interface DeviceLinkingDialogDelegate {
fun handleDeviceLinkAuthorized(pairing: PairingAuthorisation) { }
fun handleDeviceLinkAuthorized(pairingAuthorisation: PairingAuthorisation) { }
fun handleDeviceLinkingDialogDismissed() { }
fun sendPairingAuthorizedMessage(pairingAuthorisation: PairingAuthorisation) { }
}

View File

@ -82,11 +82,9 @@ class DeviceLinkingView private constructor(context: Context, attrs: AttributeSe
// endregion
// region Device Linking
fun requestUserAuthorization(authorisation: PairingAuthorisation) {
if (mode != Mode.Master) { throw IllegalStateException() }
if (authorisation.type != PairingAuthorisation.Type.REQUEST) { throw IllegalStateException() }
if (pairingAuthorisation != null) { return }
pairingAuthorisation = authorisation
fun requestUserAuthorization(pairingAuthorisation: PairingAuthorisation) {
if (mode != Mode.Master || pairingAuthorisation.type != PairingAuthorisation.Type.REQUEST || this.pairingAuthorisation != null) { return }
this.pairingAuthorisation = pairingAuthorisation
spinner.visibility = View.GONE
val titleTextViewLayoutParams = titleTextView.layoutParams as LayoutParams
titleTextViewLayoutParams.topMargin = toPx(16, resources)
@ -94,14 +92,14 @@ class DeviceLinkingView private constructor(context: Context, attrs: AttributeSe
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.secondaryDevicePublicKey.removing05PrefixIfNeeded()
val hexEncodedPublicKey = pairingAuthorisation.secondaryDevicePublicKey.removing05PrefixIfNeeded()
mnemonicTextView.text = MnemonicCodec(languageFileDirectory).encode(hexEncodedPublicKey).split(" ").slice(0 until 3).joinToString(" ")
authorizeButton.visibility = View.VISIBLE
}
fun onDeviceLinkAuthorized(authorisation: PairingAuthorisation) {
if (mode != Mode.Slave || pairingAuthorisation != null) { return }
pairingAuthorisation = authorisation
fun onDeviceLinkAuthorized(pairingAuthorisation: PairingAuthorisation) {
if (mode != Mode.Slave || pairingAuthorisation.type != PairingAuthorisation.Type.GRANT || this.pairingAuthorisation != null) { return }
this.pairingAuthorisation = pairingAuthorisation
spinner.visibility = View.GONE
val titleTextViewLayoutParams = titleTextView.layoutParams as LayoutParams
titleTextViewLayoutParams.topMargin = toPx(8, resources)
@ -116,7 +114,7 @@ class DeviceLinkingView private constructor(context: Context, attrs: AttributeSe
buttonContainer.visibility = View.GONE
cancelButton.visibility = View.GONE
Handler().postDelayed({
delegate.handleDeviceLinkAuthorized(authorisation)
delegate.handleDeviceLinkAuthorized(pairingAuthorisation)
dismiss?.invoke()
}, 4000)
}
@ -124,11 +122,11 @@ class DeviceLinkingView private constructor(context: Context, attrs: AttributeSe
// region Interaction
private fun authorizePairing() {
if (pairingAuthorisation == null || mode != Mode.Master ) { return; }
if (delegate.sendPairingAuthorizedMessage(pairingAuthorisation!!)) {
delegate.handleDeviceLinkAuthorized(pairingAuthorisation!!)
dismiss?.invoke()
}
val pairingAuthorisation = this.pairingAuthorisation
if (mode != Mode.Master || pairingAuthorisation == null) { return; }
delegate.sendPairingAuthorizedMessage(pairingAuthorisation)
delegate.handleDeviceLinkAuthorized(pairingAuthorisation)
dismiss?.invoke()
}
private fun cancel() {

View File

@ -4,7 +4,7 @@ import org.whispersystems.signalservice.loki.api.PairingAuthorisation
interface DeviceLinkingViewDelegate {
fun handleDeviceLinkAuthorized(pairing: PairingAuthorisation) { }
fun handleDeviceLinkAuthorized(pairingAuthorisation: PairingAuthorisation) { }
fun handleDeviceLinkingDialogDismissed() { }
fun sendPairingAuthorizedMessage(pairing: PairingAuthorisation): Boolean { return false }
fun sendPairingAuthorizedMessage(pairingAuthorisation: PairingAuthorisation) { }
}

View File

@ -57,7 +57,6 @@ fun shouldAutomaticallyBecomeFriendsWithDevice(publicKey: String, context: Conte
}
deferred.resolve(lokiThreadDatabase.getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS)
}
return deferred.promise
}

View File

@ -25,6 +25,7 @@ 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.LokiStorageAPI
import org.whispersystems.signalservice.loki.api.PairingAuthorisation
import org.whispersystems.signalservice.loki.crypto.MnemonicCodec
import org.whispersystems.signalservice.loki.utilities.Analytics
@ -217,10 +218,10 @@ class SeedActivity : BaseActionBarActivity(), DeviceLinkingDialogDelegate {
}
}
override fun handleDeviceLinkAuthorized(pairing: PairingAuthorisation) {
override fun handleDeviceLinkAuthorized(pairingAuthorisation: PairingAuthorisation) {
Analytics.shared.track("Device Linked Successfully")
if (pairing.secondaryDevicePublicKey == TextSecurePreferences.getLocalNumber(this)) {
TextSecurePreferences.setMasterHexEncodedPublicKey(this, pairing.primaryDevicePublicKey)
if (pairingAuthorisation.secondaryDevicePublicKey == TextSecurePreferences.getLocalNumber(this)) {
TextSecurePreferences.setMasterHexEncodedPublicKey(this, pairingAuthorisation.primaryDevicePublicKey)
}
startActivity(Intent(this, ConversationListActivity::class.java))
finish()
@ -230,6 +231,22 @@ class SeedActivity : BaseActionBarActivity(), DeviceLinkingDialogDelegate {
resetForRegistration()
}
override fun sendPairingAuthorizedMessage(pairingAuthorisation: PairingAuthorisation) {
val userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).privateKey.serialize()
val signedPairingAuthorisation = pairingAuthorisation.sign(PairingAuthorisation.Type.GRANT, userPrivateKey)
if (signedPairingAuthorisation == null || signedPairingAuthorisation.type != PairingAuthorisation.Type.GRANT) {
Log.d("Loki", "Failed to sign pairing authorization.")
return
}
retryIfNeeded(8) {
sendPairingAuthorisationMessage(this, pairingAuthorisation.secondaryDevicePublicKey, signedPairingAuthorisation).get()
}.fail {
Log.d("Loki", "Failed to send pairing authorization message to ${pairingAuthorisation.secondaryDevicePublicKey}.")
}
DatabaseFactory.getLokiAPIDatabase(this).insertOrUpdatePairingAuthorisation(signedPairingAuthorisation)
LokiStorageAPI.shared.updateUserDeviceMappings()
}
private fun resetForRegistration() {
IdentityKeyUtil.delete(this, IdentityKeyUtil.lokiSeedKey)
TextSecurePreferences.removeLocalRegistrationId(this)