From cbed5be8106226f094a316b73d61eaec7318bf0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Wed, 21 Jul 2021 16:25:28 +0200 Subject: [PATCH] crypto: Move most of the getters of verification objecs into the olm machine --- .../internal/crypto/DefaultCryptoService.kt | 4 +- .../android/sdk/internal/crypto/OlmMachine.kt | 87 +++++++++++++++---- .../verification/RustVerificationService.kt | 87 ++++++------------- 3 files changed, 96 insertions(+), 82 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt index 118d550e65..b295e484bf 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt @@ -392,7 +392,7 @@ internal class DefaultCryptoService @Inject constructor( try { setRustLogger() - val machine = OlmMachine(userId, deviceId!!, dataDir, deviceObserver) + val machine = OlmMachine(userId, deviceId!!, dataDir, deviceObserver, sender) olmMachine = machine verificationService = RustVerificationService(machine, this.sender) Timber.v( @@ -482,7 +482,7 @@ internal class DefaultCryptoService @Inject constructor( override fun getDeviceInfo(userId: String, deviceId: String?): CryptoDeviceInfo? { return if (userId.isNotEmpty() && !deviceId.isNullOrEmpty()) { runBlocking { - this@DefaultCryptoService.olmMachine?.getDevice(userId, deviceId) + this@DefaultCryptoService.olmMachine?.getCryptoDeviceInfo(userId, deviceId) } } else { null diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt index 4ae46fd2d5..6a1c3de291 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt @@ -26,6 +26,8 @@ import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.listeners.ProgressListener import org.matrix.android.sdk.api.session.crypto.MXCryptoError +import org.matrix.android.sdk.api.session.crypto.verification.VerificationService +import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction import org.matrix.android.sdk.api.session.events.model.Content import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.util.JsonDict @@ -49,8 +51,7 @@ import uniffi.olm.OlmMachine as InnerMachine import uniffi.olm.ProgressListener as RustProgressListener import uniffi.olm.Request import uniffi.olm.RequestType -import uniffi.olm.Verification -import uniffi.olm.VerificationRequest +import uniffi.olm.Verification as InnerVerification import uniffi.olm.setLogger class CryptoLogger : Logger { @@ -122,10 +123,12 @@ internal class OlmMachine( user_id: String, device_id: String, path: File, - deviceObserver: DeviceUpdateObserver + deviceObserver: DeviceUpdateObserver, + private val requestSender: RequestSender, ) { private val inner: InnerMachine = InnerMachine(user_id, device_id, path.toString()) private val deviceUpdateObserver = deviceObserver + internal val verificationListeners = ArrayList() /** Get our own user ID. */ fun userId(): String { @@ -429,17 +432,26 @@ internal class OlmMachine( * @return The Device if it found one. */ @Throws(CryptoStoreErrorException::class) - suspend fun getDevice(userId: String, deviceId: String): CryptoDeviceInfo? = - withContext(Dispatchers.IO) { - // Our own device isn't part of our store on the rust side, return it - // using our ownDevice method - if (userId == userId() && deviceId == deviceId()) { - ownDevice() - } else { - val device = inner.getDevice(userId, deviceId) - if (device != null) toCryptoDeviceInfo(device) else null - } - } + suspend fun getCryptoDeviceInfo(userId: String, deviceId: String): CryptoDeviceInfo? { + return if (userId == userId() && deviceId == deviceId()) { + // Our own device isn't part of our store on the Rust side, return it + // using our ownDevice method + ownDevice() + } else { + val device = getRawDevice(userId, deviceId) ?: return null + toCryptoDeviceInfo(device) + } + } + + private suspend fun getRawDevice(userId: String, deviceId: String): InnerDevice? = + withContext(Dispatchers.IO) { + inner.getDevice(userId, deviceId) + } + + suspend fun getDevice(userId: String, deviceId: String): Device? { + val device = this.getRawDevice(userId, deviceId) ?: return null + return Device(this.inner, device, this.requestSender, this.verificationListeners) + } /** * Get all devices of an user. @@ -546,19 +558,58 @@ internal class OlmMachine( * @return The list of VerificationRequests that we share with the given user */ fun getVerificationRequests(userId: String): List { - return this.inner.getVerificationRequests(userId) + return this.inner.getVerificationRequests(userId).map { + VerificationRequest( + this.inner, + it, + this.requestSender, + this.verificationListeners, + ) + } } /** Get a verification request for the given user with the given flow ID */ fun getVerificationRequest(userId: String, flowId: String): VerificationRequest? { - return this.inner.getVerificationRequest(userId, flowId) + val request = this.inner.getVerificationRequest(userId, flowId) + + return if (request != null) { + VerificationRequest( + this.inner, + request, + requestSender, + this.verificationListeners, + ) + } else { + null + } } /** Get an active verification for the given user and given flow ID * * This can return a SAS verification or a QR code verification */ - fun getVerification(userId: String, flowId: String): Verification? { - return this.inner.getVerification(userId, flowId) + fun getVerification(userId: String, flowId: String): VerificationTransaction? { + return when (val verification = this.inner.getVerification(userId, flowId)) { + is uniffi.olm.Verification.QrCodeV1 -> { + val request = this.getVerificationRequest(userId, flowId) ?: return null + QrCodeVerification(inner, request, verification.qrcode, requestSender, verificationListeners) + } + is uniffi.olm.Verification.SasV1 -> { + SasVerification(inner, verification.sas, requestSender, verificationListeners) + } + null -> { + // This branch exists because scanning a QR code is tied to the QrCodeVerification, + // i.e. instead of branching into a scanned QR code verification from the verification request, + // like it's done for SAS verifications, the public API expects us to create an empty dummy + // QrCodeVerification object that gets populated once a QR code is scanned. + val request = getVerificationRequest(userId, flowId) ?: return null + + if (request.canScanQrCodes()) { + QrCodeVerification(inner, request, null, requestSender, verificationListeners) + } else { + null + } + } + } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/RustVerificationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/RustVerificationService.kt index 2a11b6f540..babecfea70 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/RustVerificationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/RustVerificationService.kt @@ -20,9 +20,7 @@ import android.os.Handler import android.os.Looper import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod import org.matrix.android.sdk.api.session.crypto.verification.VerificationService @@ -34,7 +32,6 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageRelationCont import org.matrix.android.sdk.api.session.room.model.message.MessageType import org.matrix.android.sdk.internal.crypto.Device import org.matrix.android.sdk.internal.crypto.OlmMachine -import org.matrix.android.sdk.internal.crypto.QrCodeVerification import org.matrix.android.sdk.internal.crypto.RequestSender import org.matrix.android.sdk.internal.crypto.SasVerification import org.matrix.android.sdk.internal.crypto.VerificationRequest @@ -43,14 +40,15 @@ import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_QR_ import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_RECIPROCATE import org.matrix.android.sdk.internal.crypto.model.rest.toValue import timber.log.Timber -import uniffi.olm.Verification +/** A helper class to deserialize to-device `m.key.verification.*` events to fetch the transaction id out */ @JsonClass(generateAdapter = true) internal data class ToDeviceVerificationEvent( @Json(name = "sender") val sender: String?, @Json(name = "transaction_id") val transactionId: String, ) +/** Helper method to fetch the unique ID of the verification event */ private fun getFlowId(event: Event): String? { return if (event.eventId != null) { val relatesTo = event.content.toModel()?.relatesTo @@ -61,6 +59,7 @@ private fun getFlowId(event: Event): String? { } } +/** Convert a list of VerificationMethod into a list of strings that can be passed to the Rust side */ internal fun prepareMethods(methods: List): List { val stringMethods: MutableList = methods.map { it.toValue() }.toMutableList() @@ -77,23 +76,22 @@ internal class RustVerificationService( private val requestSender: RequestSender, ) : VerificationService { private val uiHandler = Handler(Looper.getMainLooper()) - private var listeners = ArrayList() override fun addListener(listener: VerificationService.Listener) { uiHandler.post { - if (!listeners.contains(listener)) { - listeners.add(listener) + if (!this.olmMachine.verificationListeners.contains(listener)) { + this.olmMachine.verificationListeners.add(listener) } } } override fun removeListener(listener: VerificationService.Listener) { - uiHandler.post { listeners.remove(listener) } + uiHandler.post { this.olmMachine.verificationListeners.remove(listener) } } private fun dispatchTxAdded(tx: VerificationTransaction) { uiHandler.post { - listeners.forEach { + this.olmMachine.verificationListeners.forEach { try { it.transactionCreated(tx) } catch (e: Throwable) { @@ -105,7 +103,7 @@ internal class RustVerificationService( private fun dispatchTxUpdated(tx: VerificationTransaction) { uiHandler.post { - listeners.forEach { + this.olmMachine.verificationListeners.forEach { try { it.transactionUpdated(tx) } catch (e: Throwable) { @@ -118,7 +116,7 @@ internal class RustVerificationService( private fun dispatchRequestAdded(tx: PendingVerificationRequest) { Timber.v("## SAS dispatchRequestAdded txId:${tx.transactionId} $tx") uiHandler.post { - listeners.forEach { + this.olmMachine.verificationListeners.forEach { try { it.verificationRequestCreated(tx) } catch (e: Throwable) { @@ -188,30 +186,11 @@ internal class RustVerificationService( } private fun getVerificationRequest(otherUserId: String, transactionId: String): VerificationRequest? { - val request = this.olmMachine.getVerificationRequest(otherUserId, transactionId) - - return if (request != null) { - VerificationRequest( - this.olmMachine.inner(), - request, - requestSender, - listeners, - ) - } else { - null - } + return this.olmMachine.getVerificationRequest(otherUserId, transactionId) } private suspend fun getDevice(userId: String, deviceID: String): Device? { - val device = withContext(Dispatchers.IO) { - olmMachine.inner().getDevice(userId, deviceID) - } - - return if (device != null) { - Device(this.olmMachine.inner(), device, this.requestSender, this.listeners) - } else { - null - } + return this.olmMachine.getDevice(userId, deviceID) } override fun markedLocallyAsManuallyVerified(userId: String, deviceID: String) { @@ -230,40 +209,14 @@ internal class RustVerificationService( otherUserId: String, tid: String, ): VerificationTransaction? { - return when (val verification = this.olmMachine.getVerification(otherUserId, tid)) { - is Verification.QrCodeV1 -> { - val request = getVerificationRequest(otherUserId, tid) ?: return null - QrCodeVerification(this.olmMachine.inner(), request, verification.qrcode, this.requestSender, this.listeners) - } - is Verification.SasV1 -> { - SasVerification(this.olmMachine.inner(), verification.sas, this.requestSender, this.listeners) - } - null -> { - // This branch exists because scanning a QR code is tied to the QrCodeVerification, - // i.e. instead of branching into a scanned QR code verification from the verification request, - // like it's done for SAS verifications, the public API expects us to create an empty dummy - // QrCodeVerification object that gets populated once a QR code is scanned. - val request = getVerificationRequest(otherUserId, tid) ?: return null - - if (request.canScanQrCodes()) { - QrCodeVerification(this.olmMachine.inner(), request, null, this.requestSender, this.listeners) - } else { - null - } - } - } + return this.olmMachine.getVerification(otherUserId, tid) } override fun getExistingVerificationRequests( otherUserId: String ): List { return this.olmMachine.getVerificationRequests(otherUserId).map { - VerificationRequest( - this.olmMachine.inner(), - it, - this.requestSender, - this.listeners, - ).toPendingVerificationRequest() + it.toPendingVerificationRequest() } } @@ -314,7 +267,12 @@ internal class RustVerificationService( requestSender.sendVerificationRequest(result!!.request) } - return VerificationRequest(this.olmMachine.inner(), result!!.verification, this.requestSender, this.listeners).toPendingVerificationRequest() + return VerificationRequest( + this.olmMachine.inner(), + result!!.verification, + this.requestSender, + this.olmMachine.verificationListeners + ).toPendingVerificationRequest() } override fun requestKeyVerificationInDMs( @@ -332,7 +290,12 @@ internal class RustVerificationService( } val innerRequest = this.olmMachine.inner().requestVerification(otherUserId, roomId, eventID, stringMethods)!! - return VerificationRequest(this.olmMachine.inner(), innerRequest, this.requestSender, this.listeners).toPendingVerificationRequest() + return VerificationRequest( + this.olmMachine.inner(), + innerRequest, + this.requestSender, + this.olmMachine.verificationListeners + ).toPendingVerificationRequest() } override fun readyPendingVerification(