matrix-sdk: Expose an API to start SAS verifications.
parent
42a4ad60e8
commit
7cb25361b2
|
@ -36,7 +36,12 @@ use tracing::{error, info, instrument};
|
||||||
use matrix_sdk_base::{BaseClient, BaseClientConfig, Room, Session, StateStore};
|
use matrix_sdk_base::{BaseClient, BaseClientConfig, Room, Session, StateStore};
|
||||||
|
|
||||||
#[cfg(feature = "encryption")]
|
#[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::{
|
use matrix_sdk_common::{
|
||||||
identifiers::ServerName,
|
identifiers::ServerName,
|
||||||
instant::{Duration, Instant},
|
instant::{Duration, Instant},
|
||||||
|
@ -52,7 +57,7 @@ use crate::{
|
||||||
events::{room::message::MessageEventContent, EventType},
|
events::{room::message::MessageEventContent, EventType},
|
||||||
http_client::{DefaultHttpClient, HttpClient, HttpSend},
|
http_client::{DefaultHttpClient, HttpClient, HttpSend},
|
||||||
identifiers::{EventId, RoomId, RoomIdOrAliasId, UserId},
|
identifiers::{EventId, RoomId, RoomIdOrAliasId, UserId},
|
||||||
Endpoint, EventEmitter, Result,
|
Endpoint, Error, EventEmitter, Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "encryption")]
|
#[cfg(feature = "encryption")]
|
||||||
|
@ -1082,13 +1087,26 @@ impl Client {
|
||||||
pub async fn send<Request>(&self, request: Request) -> Result<Request::IncomingResponse>
|
pub async fn send<Request>(&self, request: Request) -> Result<Request::IncomingResponse>
|
||||||
where
|
where
|
||||||
Request: Endpoint + Debug,
|
Request: Endpoint + Debug,
|
||||||
crate::Error: From<FromHttpResponseError<Request::ResponseError>>,
|
Error: From<FromHttpResponseError<Request::ResponseError>>,
|
||||||
{
|
{
|
||||||
self.http_client
|
self.http_client
|
||||||
.send(request, self.base_client.session().clone())
|
.send(request, self.base_client.session().clone())
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn send_to_device(
|
||||||
|
&self,
|
||||||
|
request: OwnedToDeviceRequest,
|
||||||
|
) -> Result<send_event_to_device::Response> {
|
||||||
|
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.
|
/// 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
|
/// 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 {
|
for request in self.base_client.outgoing_to_device_requests().await {
|
||||||
let request = ToDeviceRequest {
|
let txn_id = request.txn_id.clone();
|
||||||
event_type: req.event_type,
|
|
||||||
txn_id: &req.txn_id,
|
|
||||||
messages: req.messages,
|
|
||||||
};
|
|
||||||
|
|
||||||
if self.send(request).await.is_ok() {
|
if self.send_to_device(request).await.is_ok() {
|
||||||
self.base_client
|
self.base_client
|
||||||
.mark_to_device_request_as_sent(&req.txn_id)
|
.mark_to_device_request_as_sent(&txn_id)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1307,14 +1321,8 @@ impl Client {
|
||||||
.await
|
.await
|
||||||
.expect("Keys don't need to be uploaded");
|
.expect("Keys don't need to be uploaded");
|
||||||
|
|
||||||
for req in requests.drain(..) {
|
for request in requests.drain(..) {
|
||||||
let request = ToDeviceRequest {
|
self.send_to_device(request).await?;
|
||||||
event_type: req.event_type,
|
|
||||||
txn_id: &req.txn_id,
|
|
||||||
messages: req.messages,
|
|
||||||
};
|
|
||||||
|
|
||||||
let _response: send_event_to_device::Response = self.send(request).await?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1406,7 +1414,6 @@ impl Client {
|
||||||
/// Get a `Sas` verification object with the given flow id.
|
/// Get a `Sas` verification object with the given flow id.
|
||||||
#[cfg(feature = "encryption")]
|
#[cfg(feature = "encryption")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "encryption")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "encryption")))]
|
||||||
#[instrument]
|
|
||||||
pub async fn get_verification(&self, flow_id: &str) -> Option<Sas> {
|
pub async fn get_verification(&self, flow_id: &str) -> Option<Sas> {
|
||||||
self.base_client
|
self.base_client
|
||||||
.get_verification(flow_id)
|
.get_verification(flow_id)
|
||||||
|
@ -1418,6 +1425,33 @@ impl Client {
|
||||||
homeserver: self.homeserver.clone(),
|
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<Sas> {
|
||||||
|
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)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -51,7 +51,7 @@ use matrix_sdk_common::{
|
||||||
identifiers::{DeviceId, DeviceKeyAlgorithm},
|
identifiers::{DeviceId, DeviceKeyAlgorithm},
|
||||||
};
|
};
|
||||||
#[cfg(feature = "encryption")]
|
#[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;
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
@ -1849,6 +1849,7 @@ impl BaseClient {
|
||||||
/// Get a `Sas` verification object with the given flow id.
|
/// Get a `Sas` verification object with the given flow id.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
///
|
||||||
/// * `flow_id` - The unique id that identifies a interactive verification
|
/// * `flow_id` - The unique id that identifies a interactive verification
|
||||||
/// flow. For in-room verifications this will be the event id of the
|
/// flow. For in-room verifications this will be the event id of the
|
||||||
/// *m.key.verification.request* event that started the flow, for the
|
/// *m.key.verification.request* event that started the flow, for the
|
||||||
|
@ -1863,6 +1864,24 @@ impl BaseClient {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|o| o.get_verification(flow_id))
|
.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)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -1057,6 +1057,19 @@ impl OlmMachine {
|
||||||
self.verification_machine.get_sas(flow_id)
|
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.
|
/// 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
|
/// This will decrypt to-device events but will not touch events in the room
|
||||||
|
|
|
@ -25,7 +25,7 @@ use matrix_sdk_common::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::sas::{content_to_request, Sas};
|
use super::sas::{content_to_request, Sas};
|
||||||
use crate::{Account, CryptoStore, CryptoStoreError};
|
use crate::{Account, CryptoStore, CryptoStoreError, Device};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct VerificationMachine {
|
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<Sas> {
|
pub fn get_sas(&self, transaction_id: &str) -> Option<Sas> {
|
||||||
#[allow(clippy::map_clone)]
|
#[allow(clippy::map_clone)]
|
||||||
self.verifications.get(transaction_id).map(|s| s.clone())
|
self.verifications.get(transaction_id).map(|s| s.clone())
|
||||||
|
|
Loading…
Reference in New Issue