diff --git a/matrix_sdk/src/client.rs b/matrix_sdk/src/client.rs index e7233fa5..a0413162 100644 --- a/matrix_sdk/src/client.rs +++ b/matrix_sdk/src/client.rs @@ -36,7 +36,12 @@ use tracing::{error, info, instrument}; use matrix_sdk_base::{BaseClient, BaseClientConfig, Room, Session, StateStore}; #[cfg(feature = "encryption")] -use matrix_sdk_common::api::r0::to_device::send_event_to_device::Request as ToDeviceRequest; +use matrix_sdk_base::Device; + +#[cfg(feature = "encryption")] +use matrix_sdk_common::api::r0::to_device::send_event_to_device::{ + IncomingRequest as OwnedToDeviceRequest, Request as ToDeviceRequest, +}; use matrix_sdk_common::{ identifiers::ServerName, instant::{Duration, Instant}, @@ -52,7 +57,7 @@ use crate::{ events::{room::message::MessageEventContent, EventType}, http_client::{DefaultHttpClient, HttpClient, HttpSend}, identifiers::{EventId, RoomId, RoomIdOrAliasId, UserId}, - Endpoint, EventEmitter, Result, + Endpoint, Error, EventEmitter, Result, }; #[cfg(feature = "encryption")] @@ -1082,13 +1087,26 @@ impl Client { pub async fn send(&self, request: Request) -> Result where Request: Endpoint + Debug, - crate::Error: From>, + Error: From>, { self.http_client .send(request, self.base_client.session().clone()) .await } + async fn send_to_device( + &self, + request: OwnedToDeviceRequest, + ) -> Result { + let request = ToDeviceRequest { + event_type: request.event_type, + txn_id: &request.txn_id, + messages: request.messages, + }; + + self.send(request).await + } + /// Synchronize the client's state with the latest state on the server. /// /// If a `StateStore` is provided and this is the initial sync state will @@ -1217,16 +1235,12 @@ impl Client { } } - for req in self.base_client.outgoing_to_device_requests().await { - let request = ToDeviceRequest { - event_type: req.event_type, - txn_id: &req.txn_id, - messages: req.messages, - }; + for request in self.base_client.outgoing_to_device_requests().await { + let txn_id = request.txn_id.clone(); - if self.send(request).await.is_ok() { + if self.send_to_device(request).await.is_ok() { self.base_client - .mark_to_device_request_as_sent(&req.txn_id) + .mark_to_device_request_as_sent(&txn_id) .await; } } @@ -1307,14 +1321,8 @@ impl Client { .await .expect("Keys don't need to be uploaded"); - for req in requests.drain(..) { - let request = ToDeviceRequest { - event_type: req.event_type, - txn_id: &req.txn_id, - messages: req.messages, - }; - - let _response: send_event_to_device::Response = self.send(request).await?; + for request in requests.drain(..) { + self.send_to_device(request).await?; } Ok(()) @@ -1406,7 +1414,6 @@ impl Client { /// Get a `Sas` verification object with the given flow id. #[cfg(feature = "encryption")] #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] - #[instrument] pub async fn get_verification(&self, flow_id: &str) -> Option { self.base_client .get_verification(flow_id) @@ -1418,6 +1425,33 @@ impl Client { homeserver: self.homeserver.clone(), }) } + + /// Start a interactive verification with the given `Device`. + /// + /// # Arguments + /// + /// * `device` - The device which we would like to start an interactive + /// verification with. + /// + /// Returns a `Sas` that represents the interactive verification flow. + #[cfg(feature = "encryption")] + #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] + pub async fn start_verification(&self, device: Device) -> Result { + let (sas, request) = self + .base_client + .start_verification(device) + .await + .ok_or(Error::AuthenticationRequired)?; + + self.send_to_device(request).await?; + + Ok(Sas { + inner: sas, + session: self.base_client.session().clone(), + http_client: self.http_client.clone(), + homeserver: self.homeserver.clone(), + }) + } } #[cfg(test)] diff --git a/matrix_sdk_base/src/client.rs b/matrix_sdk_base/src/client.rs index fc26e0a7..c7fd3152 100644 --- a/matrix_sdk_base/src/client.rs +++ b/matrix_sdk_base/src/client.rs @@ -51,7 +51,7 @@ use matrix_sdk_common::{ identifiers::{DeviceId, DeviceKeyAlgorithm}, }; #[cfg(feature = "encryption")] -use matrix_sdk_crypto::{CryptoStore, OlmError, OlmMachine, OneTimeKeys, Sas}; +use matrix_sdk_crypto::{CryptoStore, Device, OlmError, OlmMachine, OneTimeKeys, Sas}; use zeroize::Zeroizing; #[cfg(not(target_arch = "wasm32"))] @@ -1849,6 +1849,7 @@ impl BaseClient { /// Get a `Sas` verification object with the given flow id. /// /// # Arguments + /// /// * `flow_id` - The unique id that identifies a interactive verification /// flow. For in-room verifications this will be the event id of the /// *m.key.verification.request* event that started the flow, for the @@ -1863,6 +1864,24 @@ impl BaseClient { .as_ref() .and_then(|o| o.get_verification(flow_id)) } + + /// Start a interactive verification with the given `Device`. + /// + /// # Arguments + /// + /// * `device` - The device which we would like to start an interactive + /// verification with. + /// + /// Returns a `Sas` object and to-device request that needs to be sent out. + #[cfg(feature = "encryption")] + #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] + pub async fn start_verification(&self, device: Device) -> Option<(Sas, OwnedToDeviceRequest)> { + self.olm + .lock() + .await + .as_ref() + .and_then(|o| Some(o.start_verification(device))) + } } #[cfg(test)] diff --git a/matrix_sdk_crypto/src/machine.rs b/matrix_sdk_crypto/src/machine.rs index 73adde35..7cad462b 100644 --- a/matrix_sdk_crypto/src/machine.rs +++ b/matrix_sdk_crypto/src/machine.rs @@ -1057,6 +1057,19 @@ impl OlmMachine { self.verification_machine.get_sas(flow_id) } + /// Start a interactive verification with the given `Device`. + /// + /// # Arguments + /// + /// * `device` - The device which we would like to start an interactive + /// verification with. + /// + /// + /// Returns a `Sas` object and to-device request that needs to be sent out. + pub fn start_verification(&self, device: Device) -> (Sas, OwnedToDeviceRequest) { + self.verification_machine.start_sas(device) + } + /// Handle a sync response and update the internal state of the Olm machine. /// /// This will decrypt to-device events but will not touch events in the room diff --git a/matrix_sdk_crypto/src/verification/machine.rs b/matrix_sdk_crypto/src/verification/machine.rs index cea74359..d9ad17ab 100644 --- a/matrix_sdk_crypto/src/verification/machine.rs +++ b/matrix_sdk_crypto/src/verification/machine.rs @@ -25,7 +25,7 @@ use matrix_sdk_common::{ }; use super::sas::{content_to_request, Sas}; -use crate::{Account, CryptoStore, CryptoStoreError}; +use crate::{Account, CryptoStore, CryptoStoreError, Device}; #[derive(Clone, Debug)] pub struct VerificationMachine { @@ -45,6 +45,17 @@ impl VerificationMachine { } } + pub fn start_sas(&self, device: Device) -> (Sas, OwnedToDeviceRequest) { + let (sas, content) = Sas::start(self.account.clone(), device.clone(), self.store.clone()); + let request = content_to_request( + device.user_id(), + device.device_id(), + AnyToDeviceEventContent::KeyVerificationStart(content), + ); + + (sas, request) + } + pub fn get_sas(&self, transaction_id: &str) -> Option { #[allow(clippy::map_clone)] self.verifications.get(transaction_id).map(|s| s.clone())