diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/VerificationRequest.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/VerificationRequest.kt index 5e531ec428..540b429db1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/VerificationRequest.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/VerificationRequest.kt @@ -18,7 +18,6 @@ package org.matrix.android.sdk.internal.crypto import android.os.Handler import android.os.Looper -import com.sun.jna.Native.toByteArray import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.session.crypto.verification.CancelCode @@ -30,10 +29,6 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationServic import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf import org.matrix.android.sdk.internal.crypto.crosssigning.toBase64NoPadding import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_QR_CODE_SCAN -import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_QR_CODE_SHOW -import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_RECIPROCATE -import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_SAS -import org.matrix.android.sdk.internal.crypto.model.rest.toValue import org.matrix.android.sdk.internal.crypto.verification.prepareMethods import timber.log.Timber import uniffi.olm.OlmMachine @@ -59,37 +54,74 @@ internal class VerificationRequest( } } + /** Get the flow ID of this verification request + * + * This is either the transaction ID if the verification is happening + * over to-device events, or the event ID of the m.key.verification.request + * event that initiated the flow. + */ internal fun flowId(): String { return this.inner.flowId } + /** The user ID of the other user that is participating in this verification flow */ internal fun otherUser(): String { return this.inner.otherUserId } + /** The device ID of the other user's device that is participating in this verification flow + * + * This will we null if we're initiating the request and the other side + * didn't yet accept the verification flow. + * */ internal fun otherDeviceId(): String? { refreshData() return this.inner.otherDeviceId } + /** Did we initiate this verification flow */ internal fun weStarted(): Boolean { return this.inner.weStarted } + /** Get the id of the room where this verification is happening + * + * Will be null if the verification is not happening inside a room. + */ internal fun roomId(): String? { return this.inner.roomId } + /** Did the non-initiating side respond with a m.key.verification.read event + * + * Once the verification request is ready, we're able to transition into a + * concrete verification flow, i.e. we can show/scan a QR code or start emoji + * verification. + */ internal fun isReady(): Boolean { refreshData() return this.inner.isReady } + /** Did we advertise that we're able to scan QR codes */ internal fun canScanQrCodes(): Boolean { refreshData() return this.inner.ourMethods?.contains(VERIFICATION_METHOD_QR_CODE_SCAN) ?: false } + /** Accept the verification request advertising the given methods as supported + * + * This will send out a m.key.verification.ready event advertising support for + * the given verification methods to the other side. After this method call, the + * verification request will be considered to be ready and will be able to transition + * into concrete verification flows. + * + * The method turns into a noop, if the verification flow has already been accepted + * and is in the ready state, which can be checked with the isRead() method. + * + * @param methods The list of VerificationMethod that we wish to advertise to the other + * side as supported. + */ suspend fun acceptWithMethods(methods: List) { val stringMethods = prepareMethods(methods) @@ -105,6 +137,19 @@ internal class VerificationRequest( } } + /** Transition from a ready verification request into emoji verification + * + * This method will move the verification forward into emoji verification, + * it will send out a m.key.verification.start event with the method set to + * m.sas.v1. + * + * Note: This method will be a noop and return null if the verification request + * isn't considered to be ready, you can check if the request is ready using the + * isReady() method. + * + * @return A freshly created SasVerification object that represents the newly started + * emoji verification, or null if we can't yet transition into emoji verification. + */ internal suspend fun startSasVerification(): SasVerification? { return withContext(Dispatchers.IO) { val result = machine.startSasVerification(inner.otherUserId, inner.flowId) @@ -118,6 +163,19 @@ internal class VerificationRequest( } } + /** Scan a QR code and transition into QR code verification + * + * This method will move the verification forward into QR code verification. + * It will send out a m.key.verification.start event with the method + * set to m.reciprocate.v1. + * + * Note: This method will be a noop and return null if the verification request + * isn't considered to be ready, you can check if the request is ready using the + * isReady() method. + * + * @return A freshly created QrCodeVerification object that represents the newly started + * QR code verification, or null if we can't yet transition into QR code verification. + */ internal suspend fun scanQrCode(data: String): QrCodeVerification? { // TODO again, what's the deal with ISO_8859_1? val byteArray = data.toByteArray(Charsets.ISO_8859_1) @@ -128,6 +186,23 @@ internal class VerificationRequest( return QrCodeVerification(this.machine, this, result.qr, this.sender, this.listeners) } + /** Transition into a QR code verification to display a QR code + * + * This method will move the verification forward into QR code verification. + * It will not send out any event out, it should instead be used to display + * a QR code which then can be scanned out of bound by the other side. + * + * A m.key.verification.start event with the method set to m.reciprocate.v1 + * incoming from the other side will only be accepted if this method is called + * and the QR code verification is successfully initiated. + * + * Note: This method will be a noop and return null if the verification request + * isn't considered to be ready, you can check if the request is ready using the + * isReady() method. + * + * @return A freshly created QrCodeVerification object that represents the newly started + * QR code verification, or null if we can't yet transition into QR code verification. + */ internal fun startQrVerification(): QrCodeVerification? { val qrcode = this.machine.startQrVerification(this.inner.otherUserId, this.inner.flowId) @@ -144,6 +219,16 @@ internal class VerificationRequest( } } + /** Cancel the verification flow + * + * This will send out a m.key.verification.cancel event with the cancel + * code set to m.user. + * + * Cancelling the verification request will also cancel any QrcodeVerification and + * SasVerification objects that are related to this verification request. + * + * The method turns into a noop, if the verification flow has already been cancelled. + */ internal suspend fun cancel() { val request = this.machine.cancelVerification( this.inner.otherUserId, @@ -157,6 +242,7 @@ internal class VerificationRequest( } } + /** Fetch fresh data from the Rust side for our verification flow */ private fun refreshData() { val request = this.machine.getVerificationRequest(this.inner.otherUserId, this.inner.flowId) @@ -165,6 +251,15 @@ internal class VerificationRequest( } } + /** Convert the VerificationRequest into a PendingVerificationRequest + * + * The public interface of the VerificationService dispatches the data class + * PendingVerificationRequest, this method allows us to easily transform this + * request into the data class. It fetches fresh info from the Rust side before + * it does the transform. + * + * @return The PendingVerificationRequest that matches data from this VerificationRequest. + */ internal fun toPendingVerificationRequest(): PendingVerificationRequest { refreshData() val cancelInfo = this.inner.cancelInfo