crypto: Allow the direct start of the short SAS flow
This commit is contained in:
		
							parent
							
								
									85e4b5eb49
								
							
						
					
					
						commit
						d24c94d0f9
					
				@ -49,7 +49,7 @@ import org.matrix.android.sdk.internal.session.sync.model.ToDeviceSyncResponse
 | 
			
		||||
import timber.log.Timber
 | 
			
		||||
import uniffi.olm.CryptoStoreErrorException
 | 
			
		||||
import uniffi.olm.DecryptionErrorException
 | 
			
		||||
import uniffi.olm.Device
 | 
			
		||||
import uniffi.olm.Device as InnerDevice
 | 
			
		||||
import uniffi.olm.DeviceLists
 | 
			
		||||
import uniffi.olm.KeyRequestPair
 | 
			
		||||
import uniffi.olm.Logger
 | 
			
		||||
@ -98,7 +98,7 @@ fun setRustLogger() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Convert a Rust Device into a Kotlin CryptoDeviceInfo */
 | 
			
		||||
private fun toCryptoDeviceInfo(device: Device): CryptoDeviceInfo {
 | 
			
		||||
private fun toCryptoDeviceInfo(device: InnerDevice): CryptoDeviceInfo {
 | 
			
		||||
    val keys = device.keys.map { (keyId, key) -> "$keyId:$device.deviceId" to key }.toMap()
 | 
			
		||||
 | 
			
		||||
    return CryptoDeviceInfo(
 | 
			
		||||
@ -128,6 +128,36 @@ internal class DeviceUpdateObserver {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
internal class Device(
 | 
			
		||||
        private val machine: uniffi.olm.OlmMachine,
 | 
			
		||||
        private var inner: InnerDevice,
 | 
			
		||||
        private val sender: RequestSender,
 | 
			
		||||
        private val listeners: ArrayList<VerificationService.Listener>,
 | 
			
		||||
) {
 | 
			
		||||
    @Throws(CryptoStoreErrorException::class)
 | 
			
		||||
    suspend fun startVerification(): SasVerification? {
 | 
			
		||||
        val result = withContext(Dispatchers.IO) {
 | 
			
		||||
            machine.startSasWithDevice(inner.userId, inner.deviceId)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return if (result != null) {
 | 
			
		||||
            this.sender.sendVerificationRequest(result.request)
 | 
			
		||||
            SasVerification(
 | 
			
		||||
                    this.machine, result.sas, this.sender, this.listeners,
 | 
			
		||||
            )
 | 
			
		||||
        } else {
 | 
			
		||||
            null
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Throws(CryptoStoreErrorException::class)
 | 
			
		||||
    suspend fun markAsTrusted() {
 | 
			
		||||
        withContext(Dispatchers.IO) {
 | 
			
		||||
            machine.markDeviceAsTrusted(inner.userId, inner.deviceId)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
internal class QrCodeVerification(
 | 
			
		||||
        private val machine: uniffi.olm.OlmMachine,
 | 
			
		||||
        private var inner: QrCode,
 | 
			
		||||
@ -670,7 +700,7 @@ internal class OlmMachine(
 | 
			
		||||
        runBlocking { inner.discardRoomKey(roomId) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getVerificationRequests(userId: String): List<uniffi.olm.VerificationRequest> {
 | 
			
		||||
    fun getVerificationRequests(userId: String): List<VerificationRequest> {
 | 
			
		||||
        return this.inner.getVerificationRequests(userId)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,6 @@ import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_REC
 | 
			
		||||
import org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_SAS
 | 
			
		||||
import timber.log.Timber
 | 
			
		||||
import uniffi.olm.OlmMachine
 | 
			
		||||
import uniffi.olm.Sas
 | 
			
		||||
import uniffi.olm.VerificationRequest
 | 
			
		||||
 | 
			
		||||
internal class VerificationRequest(
 | 
			
		||||
@ -66,6 +65,21 @@ internal class VerificationRequest(
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun isCanceled(): Boolean {
 | 
			
		||||
        refreshData()
 | 
			
		||||
        return this.inner.isCancelled
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun isDone(): Boolean {
 | 
			
		||||
        refreshData()
 | 
			
		||||
        return this.inner.isDone
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun isReady(): Boolean {
 | 
			
		||||
        refreshData()
 | 
			
		||||
        return this.inner.isReady
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal fun startQrVerification(): QrCodeVerification? {
 | 
			
		||||
        val qrcode = this.machine.startQrVerification(this.inner.otherUserId, this.inner.flowId)
 | 
			
		||||
 | 
			
		||||
@ -99,7 +113,10 @@ internal class VerificationRequest(
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val request = this.machine.acceptVerificationRequest(
 | 
			
		||||
                this.inner.otherUserId, this.inner.flowId, stringMethods)
 | 
			
		||||
            this.inner.otherUserId,
 | 
			
		||||
            this.inner.flowId,
 | 
			
		||||
            stringMethods
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        if (request != null) {
 | 
			
		||||
            this.sender.sendVerificationRequest(request)
 | 
			
		||||
@ -116,29 +133,14 @@ internal class VerificationRequest(
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun isCanceled(): Boolean {
 | 
			
		||||
        refreshData()
 | 
			
		||||
        return this.inner.isCancelled
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun isDone(): Boolean {
 | 
			
		||||
        refreshData()
 | 
			
		||||
        return this.inner.isDone
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun isReady(): Boolean {
 | 
			
		||||
        refreshData()
 | 
			
		||||
        return this.inner.isReady
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun startSasVerification(): Sas? {
 | 
			
		||||
    suspend fun startSasVerification(): SasVerification? {
 | 
			
		||||
        refreshData()
 | 
			
		||||
 | 
			
		||||
        return withContext(Dispatchers.IO) {
 | 
			
		||||
            val result = machine.startSasVerification(inner.otherUserId, inner.flowId)
 | 
			
		||||
            if (result != null) {
 | 
			
		||||
                sender.sendVerificationRequest(result.request)
 | 
			
		||||
                result.sas
 | 
			
		||||
                SasVerification(machine, result.sas, sender, listeners)
 | 
			
		||||
            } else {
 | 
			
		||||
                null
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -20,7 +20,9 @@ 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
 | 
			
		||||
@ -30,6 +32,7 @@ import org.matrix.android.sdk.api.session.events.model.EventType
 | 
			
		||||
import org.matrix.android.sdk.api.session.events.model.toModel
 | 
			
		||||
import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent
 | 
			
		||||
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
 | 
			
		||||
@ -39,13 +42,13 @@ import org.matrix.android.sdk.internal.session.SessionScope
 | 
			
		||||
import timber.log.Timber
 | 
			
		||||
import uniffi.olm.Verification
 | 
			
		||||
 | 
			
		||||
private fun getFlowId(event: Event): String? {
 | 
			
		||||
    @JsonClass(generateAdapter = true)
 | 
			
		||||
    data class ToDeviceVerificationEvent(
 | 
			
		||||
            @Json(name = "sender") val sender: String?,
 | 
			
		||||
            @Json(name = "transaction_id") val transactionId: String,
 | 
			
		||||
    )
 | 
			
		||||
@JsonClass(generateAdapter = true)
 | 
			
		||||
data class ToDeviceVerificationEvent(
 | 
			
		||||
        @Json(name = "sender") val sender: String?,
 | 
			
		||||
        @Json(name = "transaction_id") val transactionId: String,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
private fun getFlowId(event: Event): String? {
 | 
			
		||||
    return if (event.eventId != null) {
 | 
			
		||||
        val relatesTo = event.content.toModel<MessageRelationContent>()?.relatesTo
 | 
			
		||||
        relatesTo?.eventId
 | 
			
		||||
@ -186,9 +189,24 @@ internal class RustVerificationService(
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun markedLocallyAsManuallyVerified(userId: String, deviceID: String) {
 | 
			
		||||
        // TODO this doesn't seem to be used anymore?
 | 
			
		||||
        runBlocking { olmMachine.markDeviceAsTrusted(userId, deviceID) }
 | 
			
		||||
        runBlocking {
 | 
			
		||||
            val device = getDevice(userId, deviceID)
 | 
			
		||||
            device?.markAsTrusted()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onPotentiallyInterestingEventRoomFailToDecrypt(event: Event) {
 | 
			
		||||
@ -200,9 +218,14 @@ internal class RustVerificationService(
 | 
			
		||||
            tid: String,
 | 
			
		||||
    ): VerificationTransaction? {
 | 
			
		||||
        val verification = this.olmMachine.getVerification(otherUserId, tid) ?: return null
 | 
			
		||||
 | 
			
		||||
        return when (verification) {
 | 
			
		||||
            is Verification.QrCodeV1 -> QrCodeVerification(this.olmMachine.inner(), verification.qrcode, this.requestSender, this.listeners)
 | 
			
		||||
            is Verification.SasV1    -> SasVerification(this.olmMachine.inner(), verification.sas, this.requestSender, this.listeners)
 | 
			
		||||
            is Verification.QrCodeV1 -> {
 | 
			
		||||
                QrCodeVerification(this.olmMachine.inner(), verification.qrcode, this.requestSender, this.listeners)
 | 
			
		||||
            }
 | 
			
		||||
            is Verification.SasV1    -> {
 | 
			
		||||
                SasVerification(this.olmMachine.inner(), verification.sas, this.requestSender, this.listeners)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -235,7 +258,8 @@ internal class RustVerificationService(
 | 
			
		||||
            tid: String?
 | 
			
		||||
    ): PendingVerificationRequest? {
 | 
			
		||||
        // This is only used in `RoomDetailViewModel` to resume the verification.
 | 
			
		||||
        TODO()
 | 
			
		||||
        // We don't support resuming in the rust-sdk, at least for now, so let's return null here.
 | 
			
		||||
        return null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun requestKeyVerification(
 | 
			
		||||
@ -303,27 +327,34 @@ internal class RustVerificationService(
 | 
			
		||||
    ): String? {
 | 
			
		||||
        // should check if already one (and cancel it)
 | 
			
		||||
        return if (method == VerificationMethod.SAS) {
 | 
			
		||||
            val request = transactionId?.let { this.getVerificationRequest(otherUserId, it) }
 | 
			
		||||
            if (transactionId != null) {
 | 
			
		||||
                val request = this.getVerificationRequest(otherUserId, transactionId)
 | 
			
		||||
 | 
			
		||||
            if (request != null) {
 | 
			
		||||
                runBlocking {
 | 
			
		||||
                    val sas = request.startSasVerification()
 | 
			
		||||
                    val sas = request?.startSasVerification()
 | 
			
		||||
 | 
			
		||||
                    if (sas != null) {
 | 
			
		||||
                        val sasTransaction = SasVerification(olmMachine.inner(), sas, requestSender, listeners)
 | 
			
		||||
                        dispatchTxAdded(sasTransaction)
 | 
			
		||||
                        sasTransaction.transactionId
 | 
			
		||||
                        dispatchTxAdded(sas)
 | 
			
		||||
                        sas.transactionId
 | 
			
		||||
                    } else {
 | 
			
		||||
                        null
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                // This should start the short SAS flow, the one that doesn't start with
 | 
			
		||||
                // This starts the short SAS flow, the one that doesn't start with
 | 
			
		||||
                // a `m.key.verification.request`, Element web stopped doing this, might
 | 
			
		||||
                // be wise do do so as well
 | 
			
		||||
                // DeviceListBottomSheetViewModel triggers this, interestingly the method that
 | 
			
		||||
                // triggers this is called `manuallyVerify()`
 | 
			
		||||
                TODO()
 | 
			
		||||
                runBlocking {
 | 
			
		||||
                    val sas = getDevice(otherUserId, otherDeviceId)?.startVerification()
 | 
			
		||||
                    if (sas != null) {
 | 
			
		||||
                        dispatchTxAdded(sas)
 | 
			
		||||
                        sas.transactionId
 | 
			
		||||
                    } else {
 | 
			
		||||
                        null
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            throw IllegalArgumentException("Unknown verification method")
 | 
			
		||||
 | 
			
		||||
@ -758,6 +758,30 @@ impl OlmMachine {
 | 
			
		||||
            })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn start_sas_with_device(
 | 
			
		||||
        &self,
 | 
			
		||||
        user_id: &str,
 | 
			
		||||
        device_id: &str,
 | 
			
		||||
    ) -> Result<Option<StartSasResult>, CryptoStoreError> {
 | 
			
		||||
        let user_id = UserId::try_from(user_id)?;
 | 
			
		||||
 | 
			
		||||
        Ok(
 | 
			
		||||
            if let Some(device) = self
 | 
			
		||||
                .runtime
 | 
			
		||||
                .block_on(self.inner.get_device(&user_id, device_id.into()))?
 | 
			
		||||
            {
 | 
			
		||||
                let (sas, request) = self.runtime.block_on(device.start_verification())?;
 | 
			
		||||
 | 
			
		||||
                Some(StartSasResult {
 | 
			
		||||
                    sas: sas.into(),
 | 
			
		||||
                    request: request.into(),
 | 
			
		||||
                })
 | 
			
		||||
            } else {
 | 
			
		||||
                None
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn start_sas_verification(
 | 
			
		||||
        &self,
 | 
			
		||||
        user_id: &str,
 | 
			
		||||
 | 
			
		||||
@ -199,6 +199,8 @@ interface OlmMachine {
 | 
			
		||||
        sequence<string> methods
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    [Throws=CryptoStoreError]
 | 
			
		||||
    StartSasResult? start_sas_with_device([ByRef] string user_id, [ByRef] string device_id);
 | 
			
		||||
    [Throws=CryptoStoreError]
 | 
			
		||||
    StartSasResult? start_sas_verification([ByRef] string user_id, [ByRef] string flow_id);
 | 
			
		||||
    [Throws=CryptoStoreError]
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,7 @@ use ruma::{
 | 
			
		||||
 | 
			
		||||
use matrix_sdk_crypto::{
 | 
			
		||||
    IncomingResponse, OutgoingRequest, OutgoingVerificationRequest as SdkVerificationRequest,
 | 
			
		||||
    ToDeviceRequest, RoomMessageRequest,
 | 
			
		||||
    RoomMessageRequest, ToDeviceRequest,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub enum OutgoingVerificationRequest {
 | 
			
		||||
@ -39,11 +39,7 @@ pub enum OutgoingVerificationRequest {
 | 
			
		||||
impl From<SdkVerificationRequest> for OutgoingVerificationRequest {
 | 
			
		||||
    fn from(r: SdkVerificationRequest) -> Self {
 | 
			
		||||
        match r {
 | 
			
		||||
            SdkVerificationRequest::ToDevice(r) => Self::ToDevice {
 | 
			
		||||
                request_id: r.txn_id_string(),
 | 
			
		||||
                event_type: r.event_type.to_string(),
 | 
			
		||||
                body: serde_json::to_string(&r.messages).expect("Can't serialize to-device body"),
 | 
			
		||||
            },
 | 
			
		||||
            SdkVerificationRequest::ToDevice(r) => r.into(),
 | 
			
		||||
            SdkVerificationRequest::InRoom(r) => Self::InRoom {
 | 
			
		||||
                request_id: r.txn_id.to_string(),
 | 
			
		||||
                room_id: r.room_id.to_string(),
 | 
			
		||||
@ -55,6 +51,16 @@ impl From<SdkVerificationRequest> for OutgoingVerificationRequest {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<ToDeviceRequest> for OutgoingVerificationRequest {
 | 
			
		||||
    fn from(r: ToDeviceRequest) -> Self {
 | 
			
		||||
        Self::ToDevice {
 | 
			
		||||
            request_id: r.txn_id_string(),
 | 
			
		||||
            event_type: r.event_type.to_string(),
 | 
			
		||||
            body: serde_json::to_string(&r.messages).expect("Can't serialize to-device body"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub enum Request {
 | 
			
		||||
    ToDevice {
 | 
			
		||||
        request_id: String,
 | 
			
		||||
@ -138,8 +144,7 @@ impl From<&RoomMessageRequest> for Request {
 | 
			
		||||
            request_id: r.txn_id.to_string(),
 | 
			
		||||
            room_id: r.room_id.to_string(),
 | 
			
		||||
            event_type: r.content.event_type().to_string(),
 | 
			
		||||
            content: serde_json::to_string(&r.content)
 | 
			
		||||
                .expect("Can't serialize message content"),
 | 
			
		||||
            content: serde_json::to_string(&r.content).expect("Can't serialize message content"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user