crypto: WIP more work on in-room verifications now up to accepting them.
parent
5105629c08
commit
b6e28e2280
|
@ -45,7 +45,7 @@ use matrix_sdk_base::{BaseClient, BaseClientConfig, Room, Session, StateStore};
|
|||
#[cfg(feature = "encryption")]
|
||||
use matrix_sdk_base::crypto::{
|
||||
decrypt_key_export, encrypt_key_export, olm::InboundGroupSession, store::CryptoStoreError,
|
||||
AttachmentEncryptor, OutgoingRequests, ToDeviceRequest,
|
||||
AttachmentEncryptor, OutgoingRequests, RoomMessageRequest, ToDeviceRequest,
|
||||
};
|
||||
|
||||
/// Enum controlling if a loop running callbacks should continue or abort.
|
||||
|
@ -1160,6 +1160,17 @@ impl Client {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn room_send_helper(
|
||||
&self,
|
||||
request: &RoomMessageRequest,
|
||||
) -> Result<send_message_event::Response> {
|
||||
let content = request.content.clone();
|
||||
let txn_id = request.txn_id.into();
|
||||
let room_id = &request.room_id;
|
||||
|
||||
self.room_send(&room_id, content, Some(txn_id)).await
|
||||
}
|
||||
|
||||
/// Send a room message to the homeserver.
|
||||
///
|
||||
/// Returns the parsed response from the server.
|
||||
|
@ -1458,7 +1469,10 @@ impl Client {
|
|||
}
|
||||
|
||||
#[cfg(feature = "encryption")]
|
||||
async fn send_to_device(&self, request: &ToDeviceRequest) -> Result<ToDeviceResponse> {
|
||||
pub(crate) async fn send_to_device(
|
||||
&self,
|
||||
request: &ToDeviceRequest,
|
||||
) -> Result<ToDeviceResponse> {
|
||||
let txn_id_string = request.txn_id_string();
|
||||
let request = RumaToDeviceRequest::new(
|
||||
request.event_type.clone(),
|
||||
|
@ -1737,6 +1751,14 @@ impl Client {
|
|||
.unwrap();
|
||||
}
|
||||
}
|
||||
OutgoingRequests::RoomMessage(request) => {
|
||||
if let Ok(resp) = self.room_send_helper(request).await {
|
||||
self.base_client
|
||||
.mark_request_as_sent(&r.request_id(), &resp)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1891,7 +1913,7 @@ impl Client {
|
|||
.await
|
||||
.map(|sas| Sas {
|
||||
inner: sas,
|
||||
http_client: self.http_client.clone(),
|
||||
client: self.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1953,7 +1975,7 @@ impl Client {
|
|||
|
||||
Ok(device.map(|d| Device {
|
||||
inner: d,
|
||||
http_client: self.http_client.clone(),
|
||||
client: self.clone(),
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -2070,7 +2092,7 @@ impl Client {
|
|||
|
||||
Ok(UserDevices {
|
||||
inner: devices,
|
||||
http_client: self.http_client.clone(),
|
||||
client: self.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -18,18 +18,15 @@ use matrix_sdk_base::crypto::{
|
|||
store::CryptoStoreError, Device as BaseDevice, LocalTrust, ReadOnlyDevice,
|
||||
UserDevices as BaseUserDevices,
|
||||
};
|
||||
use matrix_sdk_common::{
|
||||
api::r0::to_device::send_event_to_device::Request as ToDeviceRequest,
|
||||
identifiers::{DeviceId, DeviceIdBox},
|
||||
};
|
||||
use matrix_sdk_common::identifiers::{DeviceId, DeviceIdBox};
|
||||
|
||||
use crate::{error::Result, http_client::HttpClient, Sas};
|
||||
use crate::{error::Result, Client, Sas};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
/// A device represents a E2EE capable client of an user.
|
||||
pub struct Device {
|
||||
pub(crate) inner: BaseDevice,
|
||||
pub(crate) http_client: HttpClient,
|
||||
pub(crate) client: Client,
|
||||
}
|
||||
|
||||
impl Deref for Device {
|
||||
|
@ -66,14 +63,11 @@ impl Device {
|
|||
/// ```
|
||||
pub async fn start_verification(&self) -> Result<Sas> {
|
||||
let (sas, request) = self.inner.start_verification().await?;
|
||||
let txn_id_string = request.txn_id_string();
|
||||
let request = ToDeviceRequest::new(request.event_type, &txn_id_string, request.messages);
|
||||
|
||||
self.http_client.send(request).await?;
|
||||
self.client.send_to_device(&request).await?;
|
||||
|
||||
Ok(Sas {
|
||||
inner: sas,
|
||||
http_client: self.http_client.clone(),
|
||||
client: self.client.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -102,7 +96,7 @@ impl Device {
|
|||
#[derive(Debug)]
|
||||
pub struct UserDevices {
|
||||
pub(crate) inner: BaseUserDevices,
|
||||
pub(crate) http_client: HttpClient,
|
||||
pub(crate) client: Client,
|
||||
}
|
||||
|
||||
impl UserDevices {
|
||||
|
@ -110,7 +104,7 @@ impl UserDevices {
|
|||
pub fn get(&self, device_id: &DeviceId) -> Option<Device> {
|
||||
self.inner.get(device_id).map(|d| Device {
|
||||
inner: d,
|
||||
http_client: self.http_client.clone(),
|
||||
client: self.client.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -121,11 +115,11 @@ impl UserDevices {
|
|||
|
||||
/// Iterator over all the devices of the user devices.
|
||||
pub fn devices(&self) -> impl Iterator<Item = Device> + '_ {
|
||||
let client = self.http_client.clone();
|
||||
let client = self.client.clone();
|
||||
|
||||
self.inner.devices().map(move |d| Device {
|
||||
inner: d,
|
||||
http_client: client.clone(),
|
||||
client: client.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,26 +12,27 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use matrix_sdk_base::crypto::{ReadOnlyDevice, Sas as BaseSas};
|
||||
use matrix_sdk_common::api::r0::to_device::send_event_to_device::Request as ToDeviceRequest;
|
||||
use matrix_sdk_base::crypto::{OutgoingVerificationRequest, ReadOnlyDevice, Sas as BaseSas};
|
||||
|
||||
use crate::{error::Result, http_client::HttpClient};
|
||||
use crate::{error::Result, Client};
|
||||
|
||||
/// An object controling the interactive verification flow.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Sas {
|
||||
pub(crate) inner: BaseSas,
|
||||
pub(crate) http_client: HttpClient,
|
||||
pub(crate) client: Client,
|
||||
}
|
||||
|
||||
impl Sas {
|
||||
/// Accept the interactive verification flow.
|
||||
pub async fn accept(&self) -> Result<()> {
|
||||
if let Some(req) = self.inner.accept() {
|
||||
let txn_id_string = req.txn_id_string();
|
||||
let request = ToDeviceRequest::new(req.event_type, &txn_id_string, req.messages);
|
||||
|
||||
self.http_client.send(request).await?;
|
||||
match req {
|
||||
OutgoingVerificationRequest::ToDevice(r) => {
|
||||
self.client.send_to_device(&r).await?;
|
||||
}
|
||||
OutgoingVerificationRequest::InRoom(_) => todo!(),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -40,15 +41,12 @@ impl Sas {
|
|||
pub async fn confirm(&self) -> Result<()> {
|
||||
let (to_device, signature) = self.inner.confirm().await?;
|
||||
|
||||
if let Some(req) = to_device {
|
||||
let txn_id_string = req.txn_id_string();
|
||||
let request = ToDeviceRequest::new(req.event_type, &txn_id_string, req.messages);
|
||||
|
||||
self.http_client.send(request).await?;
|
||||
if let Some(request) = to_device {
|
||||
self.client.send_to_device(&request).await?;
|
||||
}
|
||||
|
||||
if let Some(s) = signature {
|
||||
self.http_client.send(s).await?;
|
||||
self.client.send(s).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -56,12 +54,10 @@ impl Sas {
|
|||
|
||||
/// Cancel the interactive verification flow.
|
||||
pub async fn cancel(&self) -> Result<()> {
|
||||
if let Some(req) = self.inner.cancel() {
|
||||
let txn_id_string = req.txn_id_string();
|
||||
let request = ToDeviceRequest::new(req.event_type, &txn_id_string, req.messages);
|
||||
|
||||
self.http_client.send(request).await?;
|
||||
if let Some(request) = self.inner.cancel() {
|
||||
self.client.send_to_device(&request).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ use tracing::warn;
|
|||
use crate::{
|
||||
olm::{InboundGroupSession, PrivateCrossSigningIdentity, Session},
|
||||
store::{Changes, DeviceChanges},
|
||||
OutgoingRequest, OutgoingRequests,
|
||||
OutgoingRequest, OutgoingRequests, OutgoingVerificationRequest,
|
||||
};
|
||||
#[cfg(test)]
|
||||
use crate::{OlmMachine, ReadOnlyAccount};
|
||||
|
@ -97,7 +97,7 @@ impl Device {
|
|||
.start_sas(self.inner.clone())
|
||||
.await?;
|
||||
|
||||
if let OutgoingRequests::ToDeviceRequest(r) = request {
|
||||
if let OutgoingVerificationRequest::ToDevice(r) = request {
|
||||
Ok((sas, r))
|
||||
} else {
|
||||
panic!("Invalid verification request type");
|
||||
|
|
|
@ -51,6 +51,7 @@ pub use machine::OlmMachine;
|
|||
pub use olm::EncryptionSettings;
|
||||
pub(crate) use olm::ReadOnlyAccount;
|
||||
pub use requests::{
|
||||
IncomingResponse, KeysQueryRequest, OutgoingRequest, OutgoingRequests, ToDeviceRequest,
|
||||
IncomingResponse, KeysQueryRequest, OutgoingRequest, OutgoingRequests,
|
||||
OutgoingVerificationRequest, RoomMessageRequest, ToDeviceRequest,
|
||||
};
|
||||
pub use verification::{Sas, VerificationRequest};
|
||||
|
|
|
@ -322,6 +322,7 @@ impl OlmMachine {
|
|||
}
|
||||
|
||||
requests.append(&mut self.outgoing_to_device_requests());
|
||||
requests.append(&mut self.verification_machine.outgoing_room_message_requests());
|
||||
requests.append(&mut self.key_request_machine.outgoing_to_device_requests());
|
||||
|
||||
requests
|
||||
|
@ -360,6 +361,9 @@ impl OlmMachine {
|
|||
IncomingResponse::SignatureUpload(_) => {
|
||||
self.verification_machine.mark_request_as_sent(request_id);
|
||||
}
|
||||
IncomingResponse::RoomMessage(_) => {
|
||||
self.verification_machine.mark_request_as_sent(request_id);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use std::{collections::BTreeMap, sync::Arc, time::Duration};
|
||||
|
||||
use matrix_sdk_common::{
|
||||
|
@ -26,10 +28,11 @@ use matrix_sdk_common::{
|
|||
upload_signing_keys::Response as SigningKeysUploadResponse,
|
||||
CrossSigningKey,
|
||||
},
|
||||
message::send_message_event::Response as RoomMessageResponse,
|
||||
to_device::{send_event_to_device::Response as ToDeviceResponse, DeviceIdOrAllDevices},
|
||||
},
|
||||
events::EventType,
|
||||
identifiers::{DeviceIdBox, UserId},
|
||||
events::{AnyMessageEventContent, EventType},
|
||||
identifiers::{DeviceIdBox, RoomId, UserId},
|
||||
uuid::Uuid,
|
||||
};
|
||||
|
||||
|
@ -120,6 +123,7 @@ pub enum OutgoingRequests {
|
|||
/// Signature upload request, this request is used after a successful device
|
||||
/// or user verification is done.
|
||||
SignatureUpload(SignatureUploadRequest),
|
||||
RoomMessage(RoomMessageRequest),
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -150,6 +154,12 @@ impl From<ToDeviceRequest> for OutgoingRequests {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<RoomMessageRequest> for OutgoingRequests {
|
||||
fn from(request: RoomMessageRequest) -> Self {
|
||||
OutgoingRequests::RoomMessage(request)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SignatureUploadRequest> for OutgoingRequests {
|
||||
fn from(request: SignatureUploadRequest) -> Self {
|
||||
OutgoingRequests::SignatureUpload(request)
|
||||
|
@ -176,6 +186,7 @@ pub enum IncomingResponse<'a> {
|
|||
/// The cross signing keys upload response, marking our private cross
|
||||
/// signing identity as shared.
|
||||
SignatureUpload(&'a SignatureUploadResponse),
|
||||
RoomMessage(&'a RoomMessageResponse),
|
||||
}
|
||||
|
||||
impl<'a> From<&'a KeysUploadResponse> for IncomingResponse<'a> {
|
||||
|
@ -196,6 +207,12 @@ impl<'a> From<&'a ToDeviceResponse> for IncomingResponse<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a RoomMessageResponse> for IncomingResponse<'a> {
|
||||
fn from(response: &'a RoomMessageResponse) -> Self {
|
||||
IncomingResponse::RoomMessage(response)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a KeysClaimResponse> for IncomingResponse<'a> {
|
||||
fn from(response: &'a KeysClaimResponse) -> Self {
|
||||
IncomingResponse::KeysClaim(response)
|
||||
|
@ -230,3 +247,55 @@ impl OutgoingRequest {
|
|||
&self.request
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RoomMessageRequest {
|
||||
/// The room to send the event to.
|
||||
pub room_id: RoomId,
|
||||
|
||||
/// The transaction ID for this event.
|
||||
///
|
||||
/// Clients should generate an ID unique across requests with the
|
||||
/// same access token; it will be used by the server to ensure
|
||||
/// idempotency of requests.
|
||||
pub txn_id: Uuid,
|
||||
|
||||
/// The event content to send.
|
||||
pub content: AnyMessageEventContent,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum OutgoingVerificationRequest {
|
||||
ToDevice(ToDeviceRequest),
|
||||
InRoom(RoomMessageRequest),
|
||||
}
|
||||
|
||||
impl OutgoingVerificationRequest {
|
||||
pub fn request_id(&self) -> Uuid {
|
||||
match self {
|
||||
OutgoingVerificationRequest::ToDevice(t) => t.txn_id,
|
||||
OutgoingVerificationRequest::InRoom(r) => r.txn_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ToDeviceRequest> for OutgoingVerificationRequest {
|
||||
fn from(r: ToDeviceRequest) -> Self {
|
||||
OutgoingVerificationRequest::ToDevice(r)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RoomMessageRequest> for OutgoingVerificationRequest {
|
||||
fn from(r: RoomMessageRequest) -> Self {
|
||||
OutgoingVerificationRequest::InRoom(r)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OutgoingVerificationRequest> for OutgoingRequests {
|
||||
fn from(request: OutgoingVerificationRequest) -> Self {
|
||||
match request {
|
||||
OutgoingVerificationRequest::ToDevice(r) => OutgoingRequests::ToDeviceRequest(r),
|
||||
OutgoingVerificationRequest::InRoom(r) => OutgoingRequests::RoomMessage(r),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,8 @@ use crate::{
|
|||
olm::PrivateCrossSigningIdentity,
|
||||
requests::{OutgoingRequest, ToDeviceRequest},
|
||||
store::{CryptoStore, CryptoStoreError},
|
||||
OutgoingRequests, ReadOnlyAccount, ReadOnlyDevice,
|
||||
OutgoingRequests, OutgoingVerificationRequest, ReadOnlyAccount, ReadOnlyDevice,
|
||||
RoomMessageRequest,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -49,6 +50,7 @@ pub struct VerificationMachine {
|
|||
room_verifications: Arc<DashMap<EventId, Sas>>,
|
||||
requests: Arc<DashMap<EventId, VerificationRequest>>,
|
||||
outgoing_to_device_messages: Arc<DashMap<Uuid, OutgoingRequest>>,
|
||||
outgoing_room_messages: Arc<DashMap<Uuid, OutgoingRequest>>,
|
||||
}
|
||||
|
||||
impl VerificationMachine {
|
||||
|
@ -65,13 +67,14 @@ impl VerificationMachine {
|
|||
requests: DashMap::new().into(),
|
||||
outgoing_to_device_messages: DashMap::new().into(),
|
||||
room_verifications: DashMap::new().into(),
|
||||
outgoing_room_messages: DashMap::new().into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn start_sas(
|
||||
&self,
|
||||
device: ReadOnlyDevice,
|
||||
) -> Result<(Sas, OutgoingRequests), CryptoStoreError> {
|
||||
) -> Result<(Sas, OutgoingVerificationRequest), CryptoStoreError> {
|
||||
let identity = self.store.get_user_identity(device.user_id()).await?;
|
||||
let private_identity = self.private_identity.lock().await.clone();
|
||||
|
||||
|
@ -83,8 +86,13 @@ impl VerificationMachine {
|
|||
identity,
|
||||
);
|
||||
|
||||
let request: OutgoingRequests = match content {
|
||||
OutgoingContent::Room(c) => todo!(),
|
||||
let request = match content {
|
||||
OutgoingContent::Room(r, c) => RoomMessageRequest {
|
||||
room_id: r,
|
||||
txn_id: Uuid::new_v4(),
|
||||
content: c,
|
||||
}
|
||||
.into(),
|
||||
OutgoingContent::ToDevice(c) => {
|
||||
let request = content_to_request(device.user_id(), device.device_id(), c);
|
||||
|
||||
|
@ -127,7 +135,23 @@ impl VerificationMachine {
|
|||
self.outgoing_to_device_messages.insert(request_id, request);
|
||||
}
|
||||
|
||||
OutgoingContent::Room(c) => todo!(),
|
||||
OutgoingContent::Room(r, c) => {
|
||||
let request_id = Uuid::new_v4();
|
||||
|
||||
let request = OutgoingRequest {
|
||||
request: Arc::new(
|
||||
RoomMessageRequest {
|
||||
room_id: r,
|
||||
txn_id: request_id.clone(),
|
||||
content: c,
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
request_id,
|
||||
};
|
||||
|
||||
self.outgoing_room_messages.insert(request_id, request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,9 +162,17 @@ impl VerificationMachine {
|
|||
}
|
||||
|
||||
pub fn mark_request_as_sent(&self, uuid: &Uuid) {
|
||||
self.outgoing_room_messages.remove(uuid);
|
||||
self.outgoing_to_device_messages.remove(uuid);
|
||||
}
|
||||
|
||||
pub fn outgoing_room_message_requests(&self) -> Vec<OutgoingRequest> {
|
||||
self.outgoing_room_messages
|
||||
.iter()
|
||||
.map(|r| (*r).clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn outgoing_to_device_requests(&self) -> Vec<OutgoingRequest> {
|
||||
#[allow(clippy::map_clone)]
|
||||
self.outgoing_to_device_messages
|
||||
|
@ -215,9 +247,23 @@ impl VerificationMachine {
|
|||
Ok(s) => {
|
||||
// TODO we need to queue up the accept event
|
||||
// here.
|
||||
let accept_event = s.accept();
|
||||
info!(
|
||||
"Started a new SAS verification, \
|
||||
automatically accepting because of in-room"
|
||||
);
|
||||
|
||||
let accept_request = s.accept().unwrap();
|
||||
|
||||
self.room_verifications
|
||||
.insert(e.content.relation.event_id.clone(), s);
|
||||
|
||||
self.outgoing_room_messages.insert(
|
||||
accept_request.request_id(),
|
||||
OutgoingRequest {
|
||||
request_id: accept_request.request_id(),
|
||||
request: Arc::new(accept_request.into()),
|
||||
},
|
||||
);
|
||||
}
|
||||
Err(c) => {
|
||||
warn!(
|
||||
|
|
|
@ -93,13 +93,15 @@ impl VerificationRequest {
|
|||
) -> Result<Sas, OutgoingContent> {
|
||||
match &*self.inner.lock().unwrap() {
|
||||
InnerRequest::Ready(s) => s.into_started_sas(
|
||||
event,
|
||||
&event.clone().into_full_event(self.room_id().clone()),
|
||||
self.store.clone(),
|
||||
self.account.clone(),
|
||||
self.private_cross_signing_identity.clone(),
|
||||
device,
|
||||
user_identity,
|
||||
),
|
||||
// TODO cancel here since we got a missmatched message or do
|
||||
// nothing?
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +130,7 @@ impl InnerRequest {
|
|||
|
||||
fn into_started_sas(
|
||||
&mut self,
|
||||
event: &SyncMessageEvent<StartEventContent>,
|
||||
event: &MessageEvent<StartEventContent>,
|
||||
store: Arc<Box<dyn CryptoStore>>,
|
||||
account: ReadOnlyAccount,
|
||||
private_identity: PrivateCrossSigningIdentity,
|
||||
|
@ -299,7 +301,7 @@ struct Ready {
|
|||
impl RequestState<Ready> {
|
||||
fn into_started_sas(
|
||||
&self,
|
||||
event: &SyncMessageEvent<StartEventContent>,
|
||||
event: &MessageEvent<StartEventContent>,
|
||||
store: Arc<Box<dyn CryptoStore>>,
|
||||
account: ReadOnlyAccount,
|
||||
private_identity: PrivateCrossSigningIdentity,
|
||||
|
@ -312,7 +314,7 @@ impl RequestState<Ready> {
|
|||
other_device,
|
||||
store,
|
||||
&event.sender,
|
||||
event.content.clone(),
|
||||
(event.room_id.clone(), event.content.clone()),
|
||||
other_identity,
|
||||
)
|
||||
}
|
||||
|
@ -325,13 +327,14 @@ impl RequestState<Ready> {
|
|||
other_device: ReadOnlyDevice,
|
||||
other_identity: Option<UserIdentities>,
|
||||
) -> (Sas, OutgoingContent) {
|
||||
Sas::start(
|
||||
account,
|
||||
private_identity,
|
||||
other_device,
|
||||
store,
|
||||
other_identity,
|
||||
)
|
||||
todo!()
|
||||
// Sas::start_in_room(
|
||||
// account,
|
||||
// private_identity,
|
||||
// other_device,
|
||||
// store,
|
||||
// other_identity,
|
||||
// )
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,11 +19,13 @@ use std::convert::TryInto;
|
|||
use matrix_sdk_common::{
|
||||
events::{
|
||||
key::verification::{
|
||||
accept::{AcceptEventContent, AcceptToDeviceEventContent},
|
||||
start::{StartEventContent, StartMethod, StartToDeviceEventContent},
|
||||
KeyAgreementProtocol,
|
||||
},
|
||||
AnyMessageEventContent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent,
|
||||
},
|
||||
identifiers::RoomId,
|
||||
CanonicalJsonValue,
|
||||
};
|
||||
|
||||
|
@ -32,28 +34,28 @@ use super::FlowId;
|
|||
#[derive(Clone, Debug)]
|
||||
pub enum StartContent {
|
||||
ToDevice(StartToDeviceEventContent),
|
||||
Room(StartEventContent),
|
||||
Room(RoomId, StartEventContent),
|
||||
}
|
||||
|
||||
impl StartContent {
|
||||
pub fn method(&self) -> &StartMethod {
|
||||
match self {
|
||||
StartContent::ToDevice(c) => &c.method,
|
||||
StartContent::Room(c) => &c.method,
|
||||
StartContent::Room(_, c) => &c.method,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flow_id(&self) -> FlowId {
|
||||
match self {
|
||||
StartContent::ToDevice(c) => FlowId::ToDevice(c.transaction_id.clone()),
|
||||
StartContent::Room(c) => FlowId::InRoom(c.relation.event_id.clone()),
|
||||
StartContent::Room(r, c) => FlowId::InRoom(r.clone(), c.relation.event_id.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_canonical_json(self) -> CanonicalJsonValue {
|
||||
let content = match self {
|
||||
StartContent::Room(c) => serde_json::to_value(c),
|
||||
StartContent::ToDevice(c) => serde_json::to_value(c),
|
||||
StartContent::Room(_, c) => serde_json::to_value(c),
|
||||
};
|
||||
|
||||
content
|
||||
|
@ -63,9 +65,9 @@ impl StartContent {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<StartEventContent> for StartContent {
|
||||
fn from(content: StartEventContent) -> Self {
|
||||
StartContent::Room(content)
|
||||
impl From<(RoomId, StartEventContent)> for StartContent {
|
||||
fn from(tuple: (RoomId, StartEventContent)) -> Self {
|
||||
StartContent::Room(tuple.0, tuple.1)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,16 +77,34 @@ impl From<StartToDeviceEventContent> for StartContent {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum AcceptContent {
|
||||
ToDevice(AcceptToDeviceEventContent),
|
||||
Room(RoomId, AcceptEventContent),
|
||||
}
|
||||
|
||||
impl From<AcceptToDeviceEventContent> for AcceptContent {
|
||||
fn from(content: AcceptToDeviceEventContent) -> Self {
|
||||
AcceptContent::ToDevice(content)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(RoomId, AcceptEventContent)> for AcceptContent {
|
||||
fn from(content: (RoomId, AcceptEventContent)) -> Self {
|
||||
AcceptContent::Room(content.0, content.1)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum OutgoingContent {
|
||||
Room(AnyMessageEventContent),
|
||||
Room(RoomId, AnyMessageEventContent),
|
||||
ToDevice(AnyToDeviceEventContent),
|
||||
}
|
||||
|
||||
impl From<StartContent> for OutgoingContent {
|
||||
fn from(content: StartContent) -> Self {
|
||||
match content {
|
||||
StartContent::Room(c) => AnyMessageEventContent::KeyVerificationStart(c).into(),
|
||||
StartContent::Room(r, c) => (r, AnyMessageEventContent::KeyVerificationStart(c)).into(),
|
||||
StartContent::ToDevice(c) => AnyToDeviceEventContent::KeyVerificationStart(c).into(),
|
||||
}
|
||||
}
|
||||
|
@ -96,8 +116,8 @@ impl From<AnyToDeviceEventContent> for OutgoingContent {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<AnyMessageEventContent> for OutgoingContent {
|
||||
fn from(content: AnyMessageEventContent) -> Self {
|
||||
OutgoingContent::Room(content)
|
||||
impl From<(RoomId, AnyMessageEventContent)> for OutgoingContent {
|
||||
fn from(content: (RoomId, AnyMessageEventContent)) -> Self {
|
||||
OutgoingContent::Room(content.0, content.1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ use matrix_sdk_common::{
|
|||
},
|
||||
AnyToDeviceEvent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent,
|
||||
},
|
||||
identifiers::{EventId, UserId},
|
||||
identifiers::{EventId, RoomId, UserId},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
@ -36,7 +36,7 @@ use crate::{
|
|||
};
|
||||
|
||||
use super::{
|
||||
event_enums::OutgoingContent,
|
||||
event_enums::{AcceptContent, OutgoingContent},
|
||||
sas_state::{
|
||||
Accepted, Canceled, Confirmed, Created, Done, FlowId, KeyReceived, MacReceived, SasState,
|
||||
Started,
|
||||
|
@ -69,11 +69,18 @@ impl InnerSas {
|
|||
|
||||
pub fn start_in_room(
|
||||
event_id: EventId,
|
||||
room_id: RoomId,
|
||||
account: ReadOnlyAccount,
|
||||
other_device: ReadOnlyDevice,
|
||||
other_identity: Option<UserIdentities>,
|
||||
) -> (InnerSas, OutgoingContent) {
|
||||
let sas = SasState::<Created>::new_in_room(event_id, account, other_device, other_identity);
|
||||
let sas = SasState::<Created>::new_in_room(
|
||||
room_id,
|
||||
event_id,
|
||||
account,
|
||||
other_device,
|
||||
other_identity,
|
||||
);
|
||||
let content = sas.as_content();
|
||||
(InnerSas::Created(sas), content)
|
||||
}
|
||||
|
@ -97,7 +104,7 @@ impl InnerSas {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn accept(&self) -> Option<AcceptToDeviceEventContent> {
|
||||
pub fn accept(&self) -> Option<AcceptContent> {
|
||||
if let InnerSas::Started(s) = self {
|
||||
Some(s.as_content())
|
||||
} else {
|
||||
|
|
|
@ -20,6 +20,7 @@ mod sas_state;
|
|||
#[cfg(test)]
|
||||
use std::time::Instant;
|
||||
|
||||
use event_enums::AcceptContent;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tracing::{error, info, trace, warn};
|
||||
|
||||
|
@ -30,15 +31,18 @@ use matrix_sdk_common::{
|
|||
cancel::CancelCode,
|
||||
start::{StartEventContent, StartToDeviceEventContent},
|
||||
},
|
||||
AnyToDeviceEvent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent,
|
||||
AnyMessageEventContent, AnyToDeviceEvent, AnyToDeviceEventContent, MessageEvent,
|
||||
ToDeviceEvent,
|
||||
},
|
||||
identifiers::{DeviceId, EventId, RoomId, UserId},
|
||||
uuid::Uuid,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::SignatureError,
|
||||
identities::{LocalTrust, ReadOnlyDevice, UserIdentities},
|
||||
olm::PrivateCrossSigningIdentity,
|
||||
requests::{OutgoingVerificationRequest, RoomMessageRequest},
|
||||
store::{Changes, CryptoStore, CryptoStoreError, DeviceChanges},
|
||||
ReadOnlyAccount, ToDeviceRequest,
|
||||
};
|
||||
|
@ -189,6 +193,7 @@ impl Sas {
|
|||
) -> (Sas, OutgoingContent) {
|
||||
let (inner, content) = InnerSas::start_in_room(
|
||||
flow_id,
|
||||
room_id,
|
||||
account.clone(),
|
||||
other_device.clone(),
|
||||
other_identity.clone(),
|
||||
|
@ -249,10 +254,18 @@ impl Sas {
|
|||
///
|
||||
/// This does nothing if the verification was already accepted, otherwise it
|
||||
/// returns an `AcceptEventContent` that needs to be sent out.
|
||||
pub fn accept(&self) -> Option<ToDeviceRequest> {
|
||||
self.inner.lock().unwrap().accept().map(|c| {
|
||||
let content = AnyToDeviceEventContent::KeyVerificationAccept(c);
|
||||
self.content_to_request(content)
|
||||
pub fn accept(&self) -> Option<OutgoingVerificationRequest> {
|
||||
self.inner.lock().unwrap().accept().map(|c| match c {
|
||||
AcceptContent::ToDevice(c) => {
|
||||
let content = AnyToDeviceEventContent::KeyVerificationAccept(c);
|
||||
self.content_to_request(content).into()
|
||||
}
|
||||
AcceptContent::Room(room_id, content) => RoomMessageRequest {
|
||||
room_id,
|
||||
txn_id: Uuid::new_v4(),
|
||||
content: AnyMessageEventContent::KeyVerificationAccept(content),
|
||||
}
|
||||
.into(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
use std::{
|
||||
convert::TryFrom,
|
||||
matches,
|
||||
sync::{Arc, Mutex},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
@ -24,8 +25,8 @@ use matrix_sdk_common::{
|
|||
events::{
|
||||
key::verification::{
|
||||
accept::{
|
||||
AcceptMethod, AcceptToDeviceEventContent, MSasV1Content as AcceptV1Content,
|
||||
MSasV1ContentInit as AcceptV1ContentInit,
|
||||
AcceptEventContent, AcceptMethod, AcceptToDeviceEventContent,
|
||||
MSasV1Content as AcceptV1Content, MSasV1ContentInit as AcceptV1ContentInit,
|
||||
},
|
||||
cancel::{CancelCode, CancelToDeviceEventContent},
|
||||
key::KeyToDeviceEventContent,
|
||||
|
@ -39,13 +40,13 @@ use matrix_sdk_common::{
|
|||
},
|
||||
AnyMessageEventContent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent,
|
||||
},
|
||||
identifiers::{DeviceId, EventId, UserId},
|
||||
identifiers::{DeviceId, EventId, RoomId, UserId},
|
||||
uuid::Uuid,
|
||||
};
|
||||
use tracing::error;
|
||||
|
||||
use super::{
|
||||
event_enums::{OutgoingContent, StartContent},
|
||||
event_enums::{AcceptContent, OutgoingContent, StartContent},
|
||||
helpers::{
|
||||
calculate_commitment, get_decimal, get_emoji, get_mac_content, receive_mac_event, SasIds,
|
||||
},
|
||||
|
@ -74,20 +75,28 @@ const MAX_EVENT_TIMEOUT: Duration = Duration::from_secs(60);
|
|||
#[derive(Clone, Debug)]
|
||||
pub enum FlowId {
|
||||
ToDevice(String),
|
||||
InRoom(EventId),
|
||||
InRoom(RoomId, EventId),
|
||||
}
|
||||
|
||||
impl FlowId {
|
||||
pub fn room_id(&self) -> Option<&RoomId> {
|
||||
if let FlowId::InRoom(r, _) = &self {
|
||||
Some(r)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
match self {
|
||||
FlowId::InRoom(r) => r.to_string(),
|
||||
FlowId::InRoom(_, r) => r.to_string(),
|
||||
FlowId::ToDevice(t) => t.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
FlowId::InRoom(r) => r.as_str(),
|
||||
FlowId::InRoom(_, r) => r.as_str(),
|
||||
FlowId::ToDevice(t) => t.as_str(),
|
||||
}
|
||||
}
|
||||
|
@ -340,12 +349,13 @@ impl SasState<Created> {
|
|||
///
|
||||
/// * `other_identity` - The identity of the other user if one exists.
|
||||
pub fn new_in_room(
|
||||
room_id: RoomId,
|
||||
event_id: EventId,
|
||||
account: ReadOnlyAccount,
|
||||
other_device: ReadOnlyDevice,
|
||||
other_identity: Option<UserIdentities>,
|
||||
) -> SasState<Created> {
|
||||
let flow_id = FlowId::InRoom(event_id);
|
||||
let flow_id = FlowId::InRoom(room_id, event_id);
|
||||
Self::new_helper(flow_id, account, other_device, other_identity)
|
||||
}
|
||||
|
||||
|
@ -380,7 +390,7 @@ impl SasState<Created> {
|
|||
|
||||
pub fn as_start_content(&self) -> StartContent {
|
||||
match self.verification_flow_id.as_ref() {
|
||||
FlowId::ToDevice(s) => StartContent::ToDevice(StartToDeviceEventContent {
|
||||
FlowId::ToDevice(_) => StartContent::ToDevice(StartToDeviceEventContent {
|
||||
transaction_id: self.verification_flow_id.to_string(),
|
||||
from_device: self.device_id().into(),
|
||||
method: StartMethod::MSasV1(
|
||||
|
@ -388,16 +398,19 @@ impl SasState<Created> {
|
|||
.expect("Invalid initial protocol definitions."),
|
||||
),
|
||||
}),
|
||||
FlowId::InRoom(e) => StartContent::Room(StartEventContent {
|
||||
from_device: self.device_id().into(),
|
||||
method: StartMethod::MSasV1(
|
||||
MSasV1Content::new(self.state.protocol_definitions.clone())
|
||||
.expect("Invalid initial protocol definitions."),
|
||||
),
|
||||
relation: Relation {
|
||||
event_id: e.clone(),
|
||||
FlowId::InRoom(r, e) => StartContent::Room(
|
||||
r.clone(),
|
||||
StartEventContent {
|
||||
from_device: self.device_id().into(),
|
||||
method: StartMethod::MSasV1(
|
||||
MSasV1Content::new(self.state.protocol_definitions.clone())
|
||||
.expect("Invalid initial protocol definitions."),
|
||||
),
|
||||
relation: Relation {
|
||||
event_id: e.clone(),
|
||||
},
|
||||
},
|
||||
}),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -558,25 +571,40 @@ impl SasState<Started> {
|
|||
/// This should be sent out automatically if the SAS verification flow has
|
||||
/// been started because of a
|
||||
/// m.key.verification.request -> m.key.verification.ready flow.
|
||||
pub fn as_content(&self) -> AcceptToDeviceEventContent {
|
||||
pub fn as_content(&self) -> AcceptContent {
|
||||
let accepted_protocols = AcceptedProtocols::default();
|
||||
|
||||
AcceptToDeviceEventContent {
|
||||
transaction_id: self.verification_flow_id.to_string(),
|
||||
method: AcceptMethod::MSasV1(
|
||||
AcceptV1ContentInit {
|
||||
commitment: self.state.commitment.clone(),
|
||||
hash: accepted_protocols.hash,
|
||||
key_agreement_protocol: accepted_protocols.key_agreement_protocol,
|
||||
message_authentication_code: accepted_protocols.message_auth_code,
|
||||
short_authentication_string: self
|
||||
.state
|
||||
.protocol_definitions
|
||||
.short_authentication_string
|
||||
.clone(),
|
||||
}
|
||||
let method = AcceptMethod::MSasV1(
|
||||
AcceptV1ContentInit {
|
||||
commitment: self.state.commitment.clone(),
|
||||
hash: accepted_protocols.hash,
|
||||
key_agreement_protocol: accepted_protocols.key_agreement_protocol,
|
||||
message_authentication_code: accepted_protocols.message_auth_code,
|
||||
short_authentication_string: self
|
||||
.state
|
||||
.protocol_definitions
|
||||
.short_authentication_string
|
||||
.clone(),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
|
||||
match self.verification_flow_id.as_ref() {
|
||||
FlowId::ToDevice(_) => AcceptToDeviceEventContent {
|
||||
transaction_id: self.verification_flow_id.to_string(),
|
||||
method,
|
||||
}
|
||||
.into(),
|
||||
FlowId::InRoom(r, e) => (
|
||||
r.clone(),
|
||||
AcceptEventContent {
|
||||
method,
|
||||
relation: Relation {
|
||||
event_id: e.clone(),
|
||||
},
|
||||
},
|
||||
)
|
||||
.into(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -676,7 +704,7 @@ impl SasState<Accepted> {
|
|||
transaction_id: s.to_string(),
|
||||
key: self.inner.lock().unwrap().public_key(),
|
||||
},
|
||||
FlowId::InRoom(r) => {
|
||||
FlowId::InRoom(_, r) => {
|
||||
todo!("In-room verifications aren't implemented")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue