Glue some things together again

This commit is contained in:
nielsandriesse 2020-05-14 12:11:42 +10:00
parent 281d921849
commit 27b5a93161
4 changed files with 97 additions and 29 deletions

View File

@ -20,8 +20,8 @@ import org.thoughtcrime.securesms.BaseActionBarActivity
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragment
import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragmentDelegate
import org.thoughtcrime.securesms.loki.protocol.SyncMessagesProtocol
import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities
import org.thoughtcrime.securesms.sms.MessageSender
class JoinPublicChatActivity : PassphraseRequiredActionBarActivity(), ScanQRCodeWrapperFragmentDelegate {
private val adapter = JoinPublicChatActivityAdapter(this)
@ -66,10 +66,9 @@ class JoinPublicChatActivity : PassphraseRequiredActionBarActivity(), ScanQRCode
return Toast.makeText(this, "Invalid URL", Toast.LENGTH_SHORT).show()
}
showLoader()
val channel: Long = 1
OpenGroupUtilities.addGroup(this, url, channel).success {
MessageSender.syncAllOpenGroups(this)
SyncMessagesProtocol.syncAllOpenGroups(this@JoinPublicChatActivity)
}.successUi {
finish()
}.failUi {

View File

@ -15,7 +15,8 @@ import org.thoughtcrime.securesms.database.IdentityDatabase
import org.thoughtcrime.securesms.logging.Log
import org.thoughtcrime.securesms.loki.dialogs.LinkDeviceSlaveModeDialog
import org.thoughtcrime.securesms.loki.dialogs.LinkDeviceSlaveModeDialogDelegate
import org.thoughtcrime.securesms.loki.sendDeviceLinkMessage
import org.thoughtcrime.securesms.loki.protocol.LokiSessionResetImplementation
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol
import org.thoughtcrime.securesms.loki.utilities.push
import org.thoughtcrime.securesms.loki.utilities.setUpActionBarSessionLogo
import org.thoughtcrime.securesms.loki.utilities.show
@ -26,7 +27,12 @@ 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.protocol.friendrequests.FriendRequestProtocol
import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager
import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol
import org.whispersystems.signalservice.loki.protocol.multidevice.DeviceLink
import org.whispersystems.signalservice.loki.protocol.sessionmanagement.SessionManagementProtocol
import org.whispersystems.signalservice.loki.protocol.syncmessages.SyncMessagesProtocol
import org.whispersystems.signalservice.loki.utilities.hexEncodedPublicKey
import org.whispersystems.signalservice.loki.utilities.retryIfNeeded
@ -100,6 +106,17 @@ class LandingActivity : BaseActionBarActivity(), LinkDeviceSlaveModeDialogDelega
}
val application = ApplicationContext.getInstance(this)
application.startPollingIfNeeded()
val apiDB = DatabaseFactory.getLokiAPIDatabase(this)
val threadDB = DatabaseFactory.getLokiThreadDatabase(this)
val userDB = DatabaseFactory.getLokiUserDatabase(this)
val userPublicKey = TextSecurePreferences.getLocalNumber(this)
val sessionResetImpl = LokiSessionResetImplementation(this)
FriendRequestProtocol.configureIfNeeded(apiDB, userPublicKey)
MentionsManager.configureIfNeeded(userPublicKey, threadDB, userDB)
SessionMetaProtocol.configureIfNeeded(apiDB, userPublicKey)
org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol.configureIfNeeded(apiDB)
SessionManagementProtocol.configureIfNeeded(sessionResetImpl, threadDB, application)
SyncMessagesProtocol.configureIfNeeded(apiDB, userPublicKey)
application.setUpP2PAPIIfNeeded()
application.setUpStorageAPIIfNeeded()
val linkDeviceDialog = LinkDeviceSlaveModeDialog()
@ -107,7 +124,7 @@ class LandingActivity : BaseActionBarActivity(), LinkDeviceSlaveModeDialogDelega
linkDeviceDialog.show(supportFragmentManager, "Link Device Dialog")
AsyncTask.execute {
retryIfNeeded(8) {
sendDeviceLinkMessage(this@LandingActivity, deviceLink.masterHexEncodedPublicKey, deviceLink)
MultiDeviceProtocol.sendDeviceLinkMessage(this@LandingActivity, deviceLink.masterHexEncodedPublicKey, deviceLink)
}
}
}

View File

@ -1,6 +1,5 @@
package org.thoughtcrime.securesms.loki.activities
import android.os.AsyncTask
import android.os.Bundle
import android.support.v4.app.LoaderManager
import android.support.v4.content.Loader
@ -15,17 +14,20 @@ import network.loki.messenger.R
import nl.komponents.kovenant.functional.bind
import nl.komponents.kovenant.ui.failUi
import nl.komponents.kovenant.ui.successUi
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.database.Address
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.devicelist.Device
import org.thoughtcrime.securesms.loki.dialogs.*
import org.thoughtcrime.securesms.loki.signAndSendDeviceLinkMessage
import org.thoughtcrime.securesms.sms.MessageSender
import org.thoughtcrime.securesms.loki.protocol.EphemeralMessage
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol
import org.thoughtcrime.securesms.loki.protocol.PushEphemeralMessageSendJob
import org.thoughtcrime.securesms.loki.protocol.SyncMessagesProtocol
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.loki.protocol.multidevice.DeviceLink
import org.whispersystems.signalservice.loki.api.LokiAPI
import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI
import org.whispersystems.signalservice.loki.protocol.multidevice.DeviceLink
import java.util.*
import kotlin.concurrent.schedule
@ -121,41 +123,42 @@ class LinkedDevicesActivity : PassphraseRequiredActionBarActivity, LoaderManager
bottomSheet.show(supportFragmentManager, bottomSheet.tag)
}
private fun unlinkDevice(slaveDeviceHexEncodedPublicKey: String) {
val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this)
val database = DatabaseFactory.getLokiAPIDatabase(this)
val deviceLinks = database.getDeviceLinks(userHexEncodedPublicKey)
val deviceLink = deviceLinks.find { it.masterHexEncodedPublicKey == userHexEncodedPublicKey && it.slaveHexEncodedPublicKey == slaveDeviceHexEncodedPublicKey }
private fun unlinkDevice(slaveDevicePublicKey: String) {
val userPublicKey = TextSecurePreferences.getLocalNumber(this)
val apiDB = DatabaseFactory.getLokiAPIDatabase(this)
val deviceLinks = apiDB.getDeviceLinks(userPublicKey)
val deviceLink = deviceLinks.find { it.masterHexEncodedPublicKey == userPublicKey && it.slaveHexEncodedPublicKey == slaveDevicePublicKey }
if (deviceLink == null) {
return Toast.makeText(this, "Couldn't unlink device.", Toast.LENGTH_LONG).show()
}
LokiFileServerAPI.shared.setDeviceLinks(setOf()).successUi {
AsyncTask.execute {
DatabaseFactory.getLokiAPIDatabase(this).clearDeviceLinks(userHexEncodedPublicKey)
deviceLinks.forEach { deviceLink ->
DatabaseFactory.getLokiPreKeyBundleDatabase(this).removePreKeyBundle(deviceLink.slaveHexEncodedPublicKey)
}
MessageSender.sendUnpairRequest(this, slaveDeviceHexEncodedPublicKey)
DatabaseFactory.getLokiAPIDatabase(this).clearDeviceLinks(userPublicKey)
deviceLinks.forEach { deviceLink ->
DatabaseFactory.getLokiPreKeyBundleDatabase(this).removePreKeyBundle(deviceLink.slaveHexEncodedPublicKey)
val sessionStore = TextSecureSessionStore(this@LinkedDevicesActivity)
sessionStore.deleteAllSessions(deviceLink.slaveHexEncodedPublicKey)
}
val unlinkingRequest = EphemeralMessage.createUnlinkingRequest(slaveDevicePublicKey)
ApplicationContext.getInstance(this@LinkedDevicesActivity).jobManager.add(PushEphemeralMessageSendJob(unlinkingRequest))
LoaderManager.getInstance(this).restartLoader(0, null, this)
Toast.makeText(this, "Your device was unlinked successfully", Toast.LENGTH_LONG).show()
}.fail {
}.failUi {
Toast.makeText(this, "Couldn't unlink device.", Toast.LENGTH_LONG).show()
}
}
override fun onDeviceLinkRequestAuthorized(deviceLink: DeviceLink) {
LokiFileServerAPI.shared.addDeviceLink(deviceLink).bind(LokiAPI.sharedContext) {
signAndSendDeviceLinkMessage(this, deviceLink)
}.successUi {
LoaderManager.getInstance(this).restartLoader(0, null, this)
MultiDeviceProtocol.signAndSendDeviceLinkMessage(this, deviceLink)
}.success {
TextSecurePreferences.setMultiDevice(this, true)
Timer().schedule(4000) {
MessageSender.syncAllGroups(this@LinkedDevicesActivity)
MessageSender.syncAllContacts(this@LinkedDevicesActivity, Address.fromSerialized(deviceLink.slaveHexEncodedPublicKey))
MessageSender.syncAllOpenGroups(this@LinkedDevicesActivity)
SyncMessagesProtocol.syncAllClosedGroups(this@LinkedDevicesActivity)
SyncMessagesProtocol.syncAllOpenGroups(this@LinkedDevicesActivity)
Timer().schedule(4000) { // Not the best way to do this but the idea is to wait for the closed groups sync to go through first
SyncMessagesProtocol.syncAllContacts(this@LinkedDevicesActivity)
}
}.successUi {
LoaderManager.getInstance(this).restartLoader(0, null, this)
}.fail {
LokiFileServerAPI.shared.removeDeviceLink(deviceLink) // If this fails we have a problem
DatabaseFactory.getLokiPreKeyBundleDatabase(this).removePreKeyBundle(deviceLink.slaveHexEncodedPublicKey)

View File

@ -2,16 +2,23 @@ package org.thoughtcrime.securesms.loki.protocol
import android.content.Context
import android.util.Log
import nl.komponents.kovenant.Promise
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil
import org.thoughtcrime.securesms.database.Address
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.jobs.PushMediaSendJob
import org.thoughtcrime.securesms.jobs.PushSendJob
import org.thoughtcrime.securesms.jobs.PushTextSendJob
import org.thoughtcrime.securesms.loki.utilities.Broadcaster
import org.thoughtcrime.securesms.loki.utilities.recipient
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.messages.SignalServiceContent
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage
import org.whispersystems.signalservice.api.push.SignalServiceAddress
import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI
import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol
import org.whispersystems.signalservice.loki.protocol.multidevice.DeviceLink
@ -19,6 +26,7 @@ import org.whispersystems.signalservice.loki.protocol.multidevice.DeviceLinkingS
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
import org.whispersystems.signalservice.loki.protocol.todo.LokiMessageFriendRequestStatus
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus
import org.whispersystems.signalservice.loki.utilities.retryIfNeeded
object MultiDeviceProtocol {
@ -94,6 +102,47 @@ object MultiDeviceProtocol {
}
}
fun sendDeviceLinkMessage(context: Context, publicKey: String, deviceLink: DeviceLink): Promise<Unit, Exception> {
val messageSender = ApplicationContext.getInstance(context).communicationModule.provideSignalMessageSender()
val address = SignalServiceAddress(publicKey)
val message = SignalServiceDataMessage.newBuilder().withDeviceLink(deviceLink)
// A request should include a pre key bundle. An authorization should be a normal message.
if (deviceLink.type == DeviceLink.Type.REQUEST) {
val preKeyBundle = DatabaseFactory.getLokiPreKeyBundleDatabase(context).generatePreKeyBundle(address.number)
message.asFriendRequest(true).withPreKeyBundle(preKeyBundle)
} else {
// Include the user's profile key so that the slave device can get the user's profile picture
message.withProfileKey(ProfileKeyUtil.getProfileKey(context))
}
return try {
Log.d("Loki", "Sending device link message to: $publicKey.")
val udAccess = UnidentifiedAccessUtil.getAccessFor(context, recipient(context, publicKey))
val result = messageSender.sendMessage(0, address, udAccess, message.build())
if (result.success == null) {
val exception = when {
result.isNetworkFailure -> "Failed to send device link message due to a network error."
else -> "Failed to send device link message."
}
throw Exception(exception)
}
Promise.ofSuccess(Unit)
} catch (e: Exception) {
Log.d("Loki", "Failed to send device link message to: $publicKey due to error: $e.")
Promise.ofFail(e)
}
}
fun signAndSendDeviceLinkMessage(context: Context, deviceLink: DeviceLink): Promise<Unit, Exception> {
val userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(context).privateKey.serialize()
val signedDeviceLink = deviceLink.sign(DeviceLink.Type.AUTHORIZATION, userPrivateKey)
if (signedDeviceLink == null || signedDeviceLink.type != DeviceLink.Type.AUTHORIZATION) {
return Promise.ofFail(Exception("Failed to sign device link."))
}
return retryIfNeeded(8) {
sendDeviceLinkMessage(context, deviceLink.slaveHexEncodedPublicKey, signedDeviceLink)
}
}
@JvmStatic
fun handleDeviceLinkMessageIfNeeded(context: Context, deviceLink: DeviceLink, content: SignalServiceContent) {
val userPublicKey = TextSecurePreferences.getLocalNumber(context)