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 timber.log.Timber
|
||||||
import uniffi.olm.CryptoStoreErrorException
|
import uniffi.olm.CryptoStoreErrorException
|
||||||
import uniffi.olm.DecryptionErrorException
|
import uniffi.olm.DecryptionErrorException
|
||||||
import uniffi.olm.Device
|
import uniffi.olm.Device as InnerDevice
|
||||||
import uniffi.olm.DeviceLists
|
import uniffi.olm.DeviceLists
|
||||||
import uniffi.olm.KeyRequestPair
|
import uniffi.olm.KeyRequestPair
|
||||||
import uniffi.olm.Logger
|
import uniffi.olm.Logger
|
||||||
@ -98,7 +98,7 @@ fun setRustLogger() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Convert a Rust Device into a Kotlin CryptoDeviceInfo */
|
/** 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()
|
val keys = device.keys.map { (keyId, key) -> "$keyId:$device.deviceId" to key }.toMap()
|
||||||
|
|
||||||
return CryptoDeviceInfo(
|
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(
|
internal class QrCodeVerification(
|
||||||
private val machine: uniffi.olm.OlmMachine,
|
private val machine: uniffi.olm.OlmMachine,
|
||||||
private var inner: QrCode,
|
private var inner: QrCode,
|
||||||
@ -670,7 +700,7 @@ internal class OlmMachine(
|
|||||||
runBlocking { inner.discardRoomKey(roomId) }
|
runBlocking { inner.discardRoomKey(roomId) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getVerificationRequests(userId: String): List<uniffi.olm.VerificationRequest> {
|
fun getVerificationRequests(userId: String): List<VerificationRequest> {
|
||||||
return this.inner.getVerificationRequests(userId)
|
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 org.matrix.android.sdk.internal.crypto.model.rest.VERIFICATION_METHOD_SAS
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uniffi.olm.OlmMachine
|
import uniffi.olm.OlmMachine
|
||||||
import uniffi.olm.Sas
|
|
||||||
import uniffi.olm.VerificationRequest
|
import uniffi.olm.VerificationRequest
|
||||||
|
|
||||||
internal class 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? {
|
internal fun startQrVerification(): QrCodeVerification? {
|
||||||
val qrcode = this.machine.startQrVerification(this.inner.otherUserId, this.inner.flowId)
|
val qrcode = this.machine.startQrVerification(this.inner.otherUserId, this.inner.flowId)
|
||||||
|
|
||||||
@ -99,7 +113,10 @@ internal class VerificationRequest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val request = this.machine.acceptVerificationRequest(
|
val request = this.machine.acceptVerificationRequest(
|
||||||
this.inner.otherUserId, this.inner.flowId, stringMethods)
|
this.inner.otherUserId,
|
||||||
|
this.inner.flowId,
|
||||||
|
stringMethods
|
||||||
|
)
|
||||||
|
|
||||||
if (request != null) {
|
if (request != null) {
|
||||||
this.sender.sendVerificationRequest(request)
|
this.sender.sendVerificationRequest(request)
|
||||||
@ -116,29 +133,14 @@ internal class VerificationRequest(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isCanceled(): Boolean {
|
suspend fun startSasVerification(): SasVerification? {
|
||||||
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? {
|
|
||||||
refreshData()
|
refreshData()
|
||||||
|
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
val result = machine.startSasVerification(inner.otherUserId, inner.flowId)
|
val result = machine.startSasVerification(inner.otherUserId, inner.flowId)
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
sender.sendVerificationRequest(result.request)
|
sender.sendVerificationRequest(result.request)
|
||||||
result.sas
|
SasVerification(machine, result.sas, sender, listeners)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,9 @@ import android.os.Handler
|
|||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.runBlocking
|
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.PendingVerificationRequest
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
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.events.model.toModel
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent
|
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.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.OlmMachine
|
||||||
import org.matrix.android.sdk.internal.crypto.QrCodeVerification
|
import org.matrix.android.sdk.internal.crypto.QrCodeVerification
|
||||||
import org.matrix.android.sdk.internal.crypto.RequestSender
|
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 timber.log.Timber
|
||||||
import uniffi.olm.Verification
|
import uniffi.olm.Verification
|
||||||
|
|
||||||
private fun getFlowId(event: Event): String? {
|
@JsonClass(generateAdapter = true)
|
||||||
@JsonClass(generateAdapter = true)
|
data class ToDeviceVerificationEvent(
|
||||||
data class ToDeviceVerificationEvent(
|
@Json(name = "sender") val sender: String?,
|
||||||
@Json(name = "sender") val sender: String?,
|
@Json(name = "transaction_id") val transactionId: String,
|
||||||
@Json(name = "transaction_id") val transactionId: String,
|
)
|
||||||
)
|
|
||||||
|
|
||||||
|
private fun getFlowId(event: Event): String? {
|
||||||
return if (event.eventId != null) {
|
return if (event.eventId != null) {
|
||||||
val relatesTo = event.content.toModel<MessageRelationContent>()?.relatesTo
|
val relatesTo = event.content.toModel<MessageRelationContent>()?.relatesTo
|
||||||
relatesTo?.eventId
|
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) {
|
override fun markedLocallyAsManuallyVerified(userId: String, deviceID: String) {
|
||||||
// TODO this doesn't seem to be used anymore?
|
// 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) {
|
override fun onPotentiallyInterestingEventRoomFailToDecrypt(event: Event) {
|
||||||
@ -200,9 +218,14 @@ internal class RustVerificationService(
|
|||||||
tid: String,
|
tid: String,
|
||||||
): VerificationTransaction? {
|
): VerificationTransaction? {
|
||||||
val verification = this.olmMachine.getVerification(otherUserId, tid) ?: return null
|
val verification = this.olmMachine.getVerification(otherUserId, tid) ?: return null
|
||||||
|
|
||||||
return when (verification) {
|
return when (verification) {
|
||||||
is Verification.QrCodeV1 -> QrCodeVerification(this.olmMachine.inner(), verification.qrcode, this.requestSender, this.listeners)
|
is Verification.QrCodeV1 -> {
|
||||||
is Verification.SasV1 -> SasVerification(this.olmMachine.inner(), verification.sas, this.requestSender, this.listeners)
|
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?
|
tid: String?
|
||||||
): PendingVerificationRequest? {
|
): PendingVerificationRequest? {
|
||||||
// This is only used in `RoomDetailViewModel` to resume the verification.
|
// 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(
|
override fun requestKeyVerification(
|
||||||
@ -303,27 +327,34 @@ internal class RustVerificationService(
|
|||||||
): String? {
|
): String? {
|
||||||
// should check if already one (and cancel it)
|
// should check if already one (and cancel it)
|
||||||
return if (method == VerificationMethod.SAS) {
|
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 {
|
runBlocking {
|
||||||
val sas = request.startSasVerification()
|
val sas = request?.startSasVerification()
|
||||||
|
|
||||||
if (sas != null) {
|
if (sas != null) {
|
||||||
val sasTransaction = SasVerification(olmMachine.inner(), sas, requestSender, listeners)
|
dispatchTxAdded(sas)
|
||||||
dispatchTxAdded(sasTransaction)
|
sas.transactionId
|
||||||
sasTransaction.transactionId
|
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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
|
// a `m.key.verification.request`, Element web stopped doing this, might
|
||||||
// be wise do do so as well
|
// be wise do do so as well
|
||||||
// DeviceListBottomSheetViewModel triggers this, interestingly the method that
|
// DeviceListBottomSheetViewModel triggers this, interestingly the method that
|
||||||
// triggers this is called `manuallyVerify()`
|
// triggers this is called `manuallyVerify()`
|
||||||
TODO()
|
runBlocking {
|
||||||
|
val sas = getDevice(otherUserId, otherDeviceId)?.startVerification()
|
||||||
|
if (sas != null) {
|
||||||
|
dispatchTxAdded(sas)
|
||||||
|
sas.transactionId
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw IllegalArgumentException("Unknown verification method")
|
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(
|
pub fn start_sas_verification(
|
||||||
&self,
|
&self,
|
||||||
user_id: &str,
|
user_id: &str,
|
||||||
|
@ -199,6 +199,8 @@ interface OlmMachine {
|
|||||||
sequence<string> methods
|
sequence<string> methods
|
||||||
);
|
);
|
||||||
|
|
||||||
|
[Throws=CryptoStoreError]
|
||||||
|
StartSasResult? start_sas_with_device([ByRef] string user_id, [ByRef] string device_id);
|
||||||
[Throws=CryptoStoreError]
|
[Throws=CryptoStoreError]
|
||||||
StartSasResult? start_sas_verification([ByRef] string user_id, [ByRef] string flow_id);
|
StartSasResult? start_sas_verification([ByRef] string user_id, [ByRef] string flow_id);
|
||||||
[Throws=CryptoStoreError]
|
[Throws=CryptoStoreError]
|
||||||
|
@ -19,7 +19,7 @@ use ruma::{
|
|||||||
|
|
||||||
use matrix_sdk_crypto::{
|
use matrix_sdk_crypto::{
|
||||||
IncomingResponse, OutgoingRequest, OutgoingVerificationRequest as SdkVerificationRequest,
|
IncomingResponse, OutgoingRequest, OutgoingVerificationRequest as SdkVerificationRequest,
|
||||||
ToDeviceRequest, RoomMessageRequest,
|
RoomMessageRequest, ToDeviceRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub enum OutgoingVerificationRequest {
|
pub enum OutgoingVerificationRequest {
|
||||||
@ -39,11 +39,7 @@ pub enum OutgoingVerificationRequest {
|
|||||||
impl From<SdkVerificationRequest> for OutgoingVerificationRequest {
|
impl From<SdkVerificationRequest> for OutgoingVerificationRequest {
|
||||||
fn from(r: SdkVerificationRequest) -> Self {
|
fn from(r: SdkVerificationRequest) -> Self {
|
||||||
match r {
|
match r {
|
||||||
SdkVerificationRequest::ToDevice(r) => Self::ToDevice {
|
SdkVerificationRequest::ToDevice(r) => r.into(),
|
||||||
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::InRoom(r) => Self::InRoom {
|
SdkVerificationRequest::InRoom(r) => Self::InRoom {
|
||||||
request_id: r.txn_id.to_string(),
|
request_id: r.txn_id.to_string(),
|
||||||
room_id: r.room_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 {
|
pub enum Request {
|
||||||
ToDevice {
|
ToDevice {
|
||||||
request_id: String,
|
request_id: String,
|
||||||
@ -138,8 +144,7 @@ impl From<&RoomMessageRequest> for Request {
|
|||||||
request_id: r.txn_id.to_string(),
|
request_id: r.txn_id.to_string(),
|
||||||
room_id: r.room_id.to_string(),
|
room_id: r.room_id.to_string(),
|
||||||
event_type: r.content.event_type().to_string(),
|
event_type: r.content.event_type().to_string(),
|
||||||
content: serde_json::to_string(&r.content)
|
content: serde_json::to_string(&r.content).expect("Can't serialize message content"),
|
||||||
.expect("Can't serialize message content"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user