diff --git a/matrix_sdk/examples/emoji_verification.rs b/matrix_sdk/examples/emoji_verification.rs index 04f1375c..62ffb9a3 100644 --- a/matrix_sdk/examples/emoji_verification.rs +++ b/matrix_sdk/examples/emoji_verification.rs @@ -135,19 +135,42 @@ async fn login( if !initial.load(Ordering::SeqCst) { for (_room_id, room_info) in response.rooms.join { for event in room_info.timeline.events { - if let Ok(AnySyncRoomEvent::Message(AnySyncMessageEvent::RoomMessage(m))) = - event.deserialize() - { - if let MessageEventContent::VerificationRequest(_) = &m.content { - let request = client - .get_verification_request(&m.event_id) - .await - .expect("Request object wasn't created"); + if let AnySyncRoomEvent::Message(event) = event.deserialize().unwrap() { + match event { + AnySyncMessageEvent::RoomMessage(m) => { + if let MessageEventContent::VerificationRequest(_) = &m.content + { + let request = client + .get_verification_request(&m.event_id) + .await + .expect("Request object wasn't created"); - request - .accept() - .await - .expect("Can't accept verification request"); + request + .accept() + .await + .expect("Can't accept verification request"); + } + } + AnySyncMessageEvent::KeyVerificationKey(e) => { + let sas = client + .get_verification(&e.content.relation.event_id.as_str()) + .await + .expect("Sas object wasn't created"); + + tokio::spawn(wait_for_confirmation((*client).clone(), sas)); + } + AnySyncMessageEvent::KeyVerificationMac(e) => { + let sas = client + .get_verification(&e.content.relation.event_id.as_str()) + .await + .expect("Sas object wasn't created"); + + if sas.is_done() { + print_result(&sas); + print_devices(&e.sender, &client).await; + } + } + _ => (), } } } diff --git a/matrix_sdk/src/client.rs b/matrix_sdk/src/client.rs index d3c94028..114275d9 100644 --- a/matrix_sdk/src/client.rs +++ b/matrix_sdk/src/client.rs @@ -1160,7 +1160,7 @@ impl Client { Ok(()) } - async fn room_send_helper( + pub(crate) async fn room_send_helper( &self, request: &RoomMessageRequest, ) -> Result { diff --git a/matrix_sdk/src/sas.rs b/matrix_sdk/src/sas.rs index 16da6156..ccbc4224 100644 --- a/matrix_sdk/src/sas.rs +++ b/matrix_sdk/src/sas.rs @@ -39,10 +39,18 @@ impl Sas { /// Confirm that the short auth strings match on both sides. pub async fn confirm(&self) -> Result<()> { - let (to_device, signature) = self.inner.confirm().await?; + let (request, signature) = self.inner.confirm().await?; - if let Some(request) = to_device { - self.client.send_to_device(&request).await?; + match request { + Some(OutgoingVerificationRequest::InRoom(r)) => { + self.client.room_send_helper(&r).await?; + } + + Some(OutgoingVerificationRequest::ToDevice(r)) => { + self.client.send_to_device(&r).await?; + } + + None => (), } if let Some(s) = signature { @@ -55,7 +63,14 @@ impl Sas { /// Cancel the interactive verification flow. pub async fn cancel(&self) -> Result<()> { if let Some(request) = self.inner.cancel() { - self.client.send_to_device(&request).await?; + match request { + OutgoingVerificationRequest::ToDevice(r) => { + self.client.send_to_device(&r).await?; + } + OutgoingVerificationRequest::InRoom(r) => { + self.client.room_send_helper(&r).await?; + } + } } Ok(()) diff --git a/matrix_sdk_crypto/src/requests.rs b/matrix_sdk_crypto/src/requests.rs index 97cd4e89..a14b46bb 100644 --- a/matrix_sdk_crypto/src/requests.rs +++ b/matrix_sdk_crypto/src/requests.rs @@ -166,6 +166,24 @@ impl From for OutgoingRequests { } } +impl From for OutgoingRequest { + fn from(r: OutgoingVerificationRequest) -> Self { + Self { + request_id: r.request_id(), + request: Arc::new(r.into()), + } + } +} + +impl From for OutgoingRequest { + fn from(r: SignatureUploadRequest) -> Self { + Self { + request_id: Uuid::new_v4(), + request: Arc::new(r.into()), + } + } +} + /// Enum over all the incoming responses we need to receive. #[derive(Debug)] pub enum IncomingResponse<'a> { diff --git a/matrix_sdk_crypto/src/verification/machine.rs b/matrix_sdk_crypto/src/verification/machine.rs index b2bace8b..fc168782 100644 --- a/matrix_sdk_crypto/src/verification/machine.rs +++ b/matrix_sdk_crypto/src/verification/machine.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::sync::Arc; +use std::{convert::TryFrom, sync::Arc}; use dashmap::DashMap; @@ -20,7 +20,7 @@ use tracing::{info, trace, warn}; use matrix_sdk_common::{ events::{ - room::message::MessageEventContent, AnySyncMessageEvent, AnySyncRoomEvent, + room::message::MessageEventContent, AnyMessageEvent, AnySyncMessageEvent, AnySyncRoomEvent, AnyToDeviceEvent, AnyToDeviceEventContent, }, identifiers::{DeviceId, EventId, RoomId, UserId}, @@ -112,8 +112,19 @@ impl VerificationMachine { } pub fn get_sas(&self, transaction_id: &str) -> Option { - #[allow(clippy::map_clone)] - self.verifications.get(transaction_id).map(|s| s.clone()) + let sas = if let Ok(e) = EventId::try_from(transaction_id) { + #[allow(clippy::map_clone)] + self.room_verifications.get(&e).map(|s| s.clone()) + } else { + None + }; + + if sas.is_some() { + sas + } else { + #[allow(clippy::map_clone)] + self.verifications.get(transaction_id).map(|s| s.clone()) + } } fn queue_up_content( @@ -155,6 +166,13 @@ impl VerificationMachine { } } + #[allow(dead_code)] + fn receive_room_event_helper(&self, sas: &Sas, event: &AnyMessageEvent) { + if let Some(c) = sas.receive_room_event(event) { + self.queue_up_content(sas.other_user_id(), sas.other_device_id(), c); + } + } + fn receive_event_helper(&self, sas: &Sas, event: &AnyToDeviceEvent) { if let Some(c) = sas.receive_event(event) { self.queue_up_content(sas.other_user_id(), sas.other_device_id(), c); @@ -188,9 +206,9 @@ impl VerificationMachine { for sas in self.verifications.iter() { if let Some(r) = sas.cancel_if_timed_out() { self.outgoing_to_device_messages.insert( - r.txn_id, + r.request_id(), OutgoingRequest { - request_id: r.txn_id, + request_id: r.request_id(), request: Arc::new(r.into()), }, ); @@ -204,6 +222,12 @@ impl VerificationMachine { event: &AnySyncRoomEvent, ) -> Result<(), CryptoStoreError> { if let AnySyncRoomEvent::Message(m) = event { + // Since this are room events we will get events that we send out on + // our own as well. + if m.sender() == self.account.user_id() { + return Ok(()); + } + match m { AnySyncMessageEvent::RoomMessage(m) => { if let MessageEventContent::VerificationRequest(r) = &m.content { @@ -245,25 +269,19 @@ impl VerificationMachine { self.store.get_user_identity(&e.sender).await?, ) { Ok(s) => { - // TODO we need to queue up the accept event - // here. info!( "Started a new SAS verification, \ automatically accepting because of in-room" ); + // TODO remove this unwrap 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()), - }, - ); + self.outgoing_room_messages + .insert(accept_request.request_id(), accept_request.into()); } Err(c) => { warn!( @@ -276,6 +294,38 @@ impl VerificationMachine { } } } + AnySyncMessageEvent::KeyVerificationKey(e) => { + if let Some(s) = self.room_verifications.get(&e.content.relation.event_id) { + self.receive_room_event_helper( + &s, + &m.clone().into_full_event(room_id.clone()), + ) + }; + } + AnySyncMessageEvent::KeyVerificationMac(e) => { + if let Some(s) = self.room_verifications.get(&e.content.relation.event_id) { + self.receive_room_event_helper( + &s, + &m.clone().into_full_event(room_id.clone()), + ); + + if s.is_done() { + match s.mark_as_done().await? { + VerificationResult::Ok => (), + VerificationResult::Cancel(r) => { + self.outgoing_to_device_messages + .insert(r.request_id(), r.into()); + } + VerificationResult::SignatureUpload(r) => { + let request: OutgoingRequest = r.into(); + + self.outgoing_to_device_messages + .insert(request.request_id, request); + } + } + } + }; + } _ => (), } } @@ -350,9 +400,9 @@ impl VerificationMachine { VerificationResult::Ok => (), VerificationResult::Cancel(r) => { self.outgoing_to_device_messages.insert( - r.txn_id, + r.request_id(), OutgoingRequest { - request_id: r.txn_id, + request_id: r.request_id(), request: Arc::new(r.into()), }, ); diff --git a/matrix_sdk_crypto/src/verification/sas/event_enums.rs b/matrix_sdk_crypto/src/verification/sas/event_enums.rs index 7d9d3f7c..35bf3034 100644 --- a/matrix_sdk_crypto/src/verification/sas/event_enums.rs +++ b/matrix_sdk_crypto/src/verification/sas/event_enums.rs @@ -14,16 +14,18 @@ #![allow(dead_code)] -use std::convert::TryInto; +use std::{collections::BTreeMap, convert::TryInto}; use matrix_sdk_common::{ events::{ key::verification::{ accept::{AcceptEventContent, AcceptToDeviceEventContent}, + cancel::{CancelEventContent, CancelToDeviceEventContent}, + key::{KeyEventContent, KeyToDeviceEventContent}, + mac::{MacEventContent, MacToDeviceEventContent}, start::{StartEventContent, StartMethod, StartToDeviceEventContent}, - KeyAgreementProtocol, }, - AnyMessageEventContent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent, + AnyMessageEventContent, AnyToDeviceEventContent, }, identifiers::RoomId, CanonicalJsonValue, @@ -95,6 +97,96 @@ impl From<(RoomId, AcceptEventContent)> for AcceptContent { } } +pub enum KeyContent { + ToDevice(KeyToDeviceEventContent), + Room(RoomId, KeyEventContent), +} + +impl KeyContent { + pub fn flow_id(&self) -> FlowId { + match self { + KeyContent::ToDevice(c) => FlowId::ToDevice(c.transaction_id.clone()), + KeyContent::Room(r, c) => FlowId::InRoom(r.clone(), c.relation.event_id.clone()), + } + } + + pub fn public_key(&self) -> &str { + match self { + KeyContent::ToDevice(c) => &c.key, + KeyContent::Room(_, c) => &c.key, + } + } +} + +impl From for KeyContent { + fn from(content: KeyToDeviceEventContent) -> Self { + KeyContent::ToDevice(content) + } +} + +impl From<(RoomId, KeyEventContent)> for KeyContent { + fn from(content: (RoomId, KeyEventContent)) -> Self { + KeyContent::Room(content.0, content.1) + } +} + +pub enum MacContent { + ToDevice(MacToDeviceEventContent), + Room(RoomId, MacEventContent), +} + +impl MacContent { + pub fn flow_id(&self) -> FlowId { + match self { + MacContent::ToDevice(c) => FlowId::ToDevice(c.transaction_id.clone()), + MacContent::Room(r, c) => FlowId::InRoom(r.clone(), c.relation.event_id.clone()), + } + } + + pub fn mac(&self) -> &BTreeMap { + match self { + MacContent::ToDevice(c) => &c.mac, + MacContent::Room(_, c) => &c.mac, + } + } + + pub fn keys(&self) -> &str { + match self { + MacContent::ToDevice(c) => &c.keys, + MacContent::Room(_, c) => &c.keys, + } + } +} + +impl From for MacContent { + fn from(content: MacToDeviceEventContent) -> Self { + MacContent::ToDevice(content) + } +} + +impl From<(RoomId, MacEventContent)> for MacContent { + fn from(content: (RoomId, MacEventContent)) -> Self { + MacContent::Room(content.0, content.1) + } +} + +pub enum CancelContent { + ToDevice(CancelToDeviceEventContent), + Room(RoomId, CancelEventContent), +} + +impl From<(RoomId, CancelEventContent)> for CancelContent { + fn from(content: (RoomId, CancelEventContent)) -> Self { + CancelContent::Room(content.0, content.1) + } +} + +impl From for CancelContent { + fn from(content: CancelToDeviceEventContent) -> Self { + CancelContent::ToDevice(content) + } +} + #[derive(Clone, Debug)] pub enum OutgoingContent { Room(RoomId, AnyMessageEventContent), @@ -110,6 +202,26 @@ impl From for OutgoingContent { } } +impl From for OutgoingContent { + fn from(content: CancelContent) -> Self { + match content { + CancelContent::Room(r, c) => { + (r, AnyMessageEventContent::KeyVerificationCancel(c)).into() + } + CancelContent::ToDevice(c) => AnyToDeviceEventContent::KeyVerificationCancel(c).into(), + } + } +} + +impl From for OutgoingContent { + fn from(content: KeyContent) -> Self { + match content { + KeyContent::Room(r, c) => (r, AnyMessageEventContent::KeyVerificationKey(c)).into(), + KeyContent::ToDevice(c) => AnyToDeviceEventContent::KeyVerificationKey(c).into(), + } + } +} + impl From for OutgoingContent { fn from(content: AnyToDeviceEventContent) -> Self { OutgoingContent::ToDevice(content) diff --git a/matrix_sdk_crypto/src/verification/sas/helpers.rs b/matrix_sdk_crypto/src/verification/sas/helpers.rs index 388fd6c2..fd6f4bca 100644 --- a/matrix_sdk_crypto/src/verification/sas/helpers.rs +++ b/matrix_sdk_crypto/src/verification/sas/helpers.rs @@ -23,7 +23,10 @@ use matrix_sdk_common::{ api::r0::to_device::DeviceIdOrAllDevices, events::{ key::verification::{ - cancel::CancelCode, mac::MacToDeviceEventContent, start::StartToDeviceEventContent, + cancel::CancelCode, + mac::{MacEventContent, MacToDeviceEventContent}, + start::StartToDeviceEventContent, + Relation, }, AnyToDeviceEventContent, EventType, ToDeviceEvent, }, @@ -38,7 +41,10 @@ use crate::{ ReadOnlyAccount, ToDeviceRequest, }; -use super::{event_enums::StartContent, sas_state::FlowId}; +use super::{ + event_enums::{MacContent, StartContent}, + sas_state::FlowId, +}; #[derive(Clone, Debug)] pub struct SasIds { @@ -186,7 +192,8 @@ pub fn receive_mac_event( sas: &OlmSas, ids: &SasIds, flow_id: &str, - event: &ToDeviceEvent, + sender: &UserId, + content: &MacContent, ) -> Result<(Vec, Vec), CancelCode> { let mut verified_devices = Vec::new(); let mut verified_identities = Vec::new(); @@ -195,25 +202,25 @@ pub fn receive_mac_event( trace!( "Received a key.verification.mac event from {} {}", - event.sender, + sender, ids.other_device.device_id() ); - let mut keys = event.content.mac.keys().cloned().collect::>(); + let mut keys = content.mac().keys().cloned().collect::>(); keys.sort(); let keys = sas .calculate_mac(&keys.join(","), &format!("{}KEY_IDS", &info)) .expect("Can't calculate SAS MAC"); - if keys != event.content.keys { + if keys != content.keys() { return Err(CancelCode::KeyMismatch); } - for (key_id, key_mac) in &event.content.mac { + for (key_id, key_mac) in content.mac() { trace!( "Checking MAC for the key id {} from {} {}", key_id, - event.sender, + sender, ids.other_device.device_id() ); let key_id: DeviceKeyId = match key_id.as_str().try_into() { @@ -227,6 +234,12 @@ pub fn receive_mac_event( .calculate_mac(key, &format!("{}{}", info, key_id)) .expect("Can't calculate SAS MAC") { + trace!( + "Successfully verified the device key {} from {}", + key_id, + sender + ); + verified_devices.push(ids.other_device.clone()); } else { return Err(CancelCode::KeyMismatch); @@ -243,7 +256,7 @@ pub fn receive_mac_event( trace!( "Successfully verified the master key {} from {}", key_id, - event.sender + sender ); verified_identities.push(identity.clone()) } else { @@ -255,7 +268,7 @@ pub fn receive_mac_event( "Key ID {} in MAC event from {} {} doesn't belong to any device \ or user identity", key_id, - event.sender, + sender, ids.other_device.device_id() ); } @@ -297,7 +310,7 @@ fn extra_mac_info_send(ids: &SasIds, flow_id: &str) -> String { /// # Panics /// /// This will panic if the public key of the other side wasn't set. -pub fn get_mac_content(sas: &OlmSas, ids: &SasIds, flow_id: &FlowId) -> MacToDeviceEventContent { +pub fn get_mac_content(sas: &OlmSas, ids: &SasIds, flow_id: &FlowId) -> MacContent { let mut mac: BTreeMap = BTreeMap::new(); let key_id = DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, ids.account.device_id()); @@ -323,8 +336,19 @@ pub fn get_mac_content(sas: &OlmSas, ids: &SasIds, flow_id: &FlowId) -> MacToDev transaction_id: s.to_string(), keys, mac, - }, - _ => todo!(), + } + .into(), + FlowId::InRoom(r, e) => ( + r.clone(), + MacEventContent { + mac, + keys, + relation: Relation { + event_id: e.clone(), + }, + }, + ) + .into(), } } diff --git a/matrix_sdk_crypto/src/verification/sas/inner_sas.rs b/matrix_sdk_crypto/src/verification/sas/inner_sas.rs index 1db06ab2..ffebb8bc 100644 --- a/matrix_sdk_crypto/src/verification/sas/inner_sas.rs +++ b/matrix_sdk_crypto/src/verification/sas/inner_sas.rs @@ -25,7 +25,8 @@ use matrix_sdk_common::{ mac::MacToDeviceEventContent, start::{StartEventContent, StartToDeviceEventContent}, }, - AnyToDeviceEvent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent, + AnyMessageEvent, AnyMessageEventContent, AnySyncMessageEvent, AnyToDeviceEvent, + AnyToDeviceEventContent, MessageEvent, ToDeviceEvent, }, identifiers::{EventId, RoomId, UserId}, }; @@ -36,7 +37,7 @@ use crate::{ }; use super::{ - event_enums::{AcceptContent, OutgoingContent}, + event_enums::{AcceptContent, CancelContent, MacContent, OutgoingContent}, sas_state::{ Accepted, Canceled, Confirmed, Created, Done, FlowId, KeyReceived, MacReceived, SasState, Started, @@ -91,7 +92,7 @@ impl InnerSas { sender: &UserId, content: impl Into, other_identity: Option, - ) -> Result { + ) -> Result { match SasState::::from_start_event( account, other_device, @@ -127,7 +128,7 @@ impl InnerSas { } } - pub fn cancel(self, code: CancelCode) -> (InnerSas, Option) { + pub fn cancel(self, code: CancelCode) -> (InnerSas, Option) { let sas = match self { InnerSas::Created(s) => s.cancel(code), InnerSas::Started(s) => s.cancel(code), @@ -142,7 +143,7 @@ impl InnerSas { (InnerSas::Canceled(sas), Some(content)) } - pub fn confirm(self) -> (InnerSas, Option) { + pub fn confirm(self) -> (InnerSas, Option) { match self { InnerSas::KeyRecieved(s) => { let sas = s.confirm(); @@ -158,6 +159,62 @@ impl InnerSas { } } + #[allow(dead_code)] + pub fn receive_room_event( + self, + event: &AnyMessageEvent, + ) -> (InnerSas, Option) { + match event { + AnyMessageEvent::KeyVerificationKey(e) => match self { + InnerSas::Accepted(s) => { + match s.into_key_received(&e.sender, (e.room_id.clone(), e.content.clone())) { + Ok(s) => (InnerSas::KeyRecieved(s), None), + Err(s) => { + let content = s.as_content(); + (InnerSas::Canceled(s), Some(content.into())) + } + } + } + InnerSas::Started(s) => { + match s.into_key_received(&e.sender, (e.room_id.clone(), e.content.clone())) { + Ok(s) => { + let content = s.as_content(); + (InnerSas::KeyRecieved(s), Some(content.into())) + } + Err(s) => { + let content = s.as_content(); + (InnerSas::Canceled(s), Some(content.into())) + } + } + } + + _ => (self, None), + }, + AnyMessageEvent::KeyVerificationMac(e) => match self { + InnerSas::KeyRecieved(s) => { + match s.into_mac_received(&e.sender, (e.room_id.clone(), e.content.clone())) { + Ok(s) => (InnerSas::MacReceived(s), None), + Err(s) => { + let content = s.as_content(); + (InnerSas::Canceled(s), Some(content.into())) + } + } + } + InnerSas::Confirmed(s) => { + match s.into_done(&e.sender, (e.room_id.clone(), e.content.clone())) { + Ok(s) => (InnerSas::Done(s), None), + Err(s) => { + let content = s.as_content(); + (InnerSas::Canceled(s), Some(content.into())) + } + } + } + _ => (self, None), + }, + _ => (self, None), + } + } + pub fn receive_event(self, event: &AnyToDeviceEvent) -> (InnerSas, Option) { match event { AnyToDeviceEvent::KeyVerificationAccept(e) => { @@ -165,14 +222,11 @@ impl InnerSas { match s.into_accepted(e) { Ok(s) => { let content = s.as_content(); - ( - InnerSas::Accepted(s), - Some(AnyToDeviceEventContent::KeyVerificationKey(content).into()), - ) + (InnerSas::Accepted(s), Some(content.into())) } Err(s) => { let content = s.as_content(); - (InnerSas::Canceled(s), Some(content)) + (InnerSas::Canceled(s), Some(content.into())) } } } else { @@ -180,41 +234,39 @@ impl InnerSas { } } AnyToDeviceEvent::KeyVerificationKey(e) => match self { - InnerSas::Accepted(s) => match s.into_key_received(e) { + InnerSas::Accepted(s) => match s.into_key_received(&e.sender, e.content.clone()) { Ok(s) => (InnerSas::KeyRecieved(s), None), Err(s) => { let content = s.as_content(); - (InnerSas::Canceled(s), Some(content)) + (InnerSas::Canceled(s), Some(content.into())) } }, - InnerSas::Started(s) => match s.into_key_received(e) { + InnerSas::Started(s) => match s.into_key_received(&e.sender, e.content.clone()) { Ok(s) => { let content = s.as_content(); - ( - InnerSas::KeyRecieved(s), - Some(AnyToDeviceEventContent::KeyVerificationKey(content).into()), - ) + (InnerSas::KeyRecieved(s), Some(content.into())) } Err(s) => { let content = s.as_content(); - (InnerSas::Canceled(s), Some(content)) + (InnerSas::Canceled(s), Some(content.into())) } }, _ => (self, None), }, AnyToDeviceEvent::KeyVerificationMac(e) => match self { - InnerSas::KeyRecieved(s) => match s.into_mac_received(e) { + InnerSas::KeyRecieved(s) => match s.into_mac_received(&e.sender, e.content.clone()) + { Ok(s) => (InnerSas::MacReceived(s), None), Err(s) => { let content = s.as_content(); - (InnerSas::Canceled(s), Some(content)) + (InnerSas::Canceled(s), Some(content.into())) } }, - InnerSas::Confirmed(s) => match s.into_done(e) { + InnerSas::Confirmed(s) => match s.into_done(&e.sender, e.content.clone()) { Ok(s) => (InnerSas::Done(s), None), Err(s) => { let content = s.as_content(); - (InnerSas::Canceled(s), Some(content)) + (InnerSas::Canceled(s), Some(content.into())) } }, _ => (self, None), diff --git a/matrix_sdk_crypto/src/verification/sas/mod.rs b/matrix_sdk_crypto/src/verification/sas/mod.rs index 0e17d5e5..8ee330d4 100644 --- a/matrix_sdk_crypto/src/verification/sas/mod.rs +++ b/matrix_sdk_crypto/src/verification/sas/mod.rs @@ -31,8 +31,8 @@ use matrix_sdk_common::{ cancel::CancelCode, start::{StartEventContent, StartToDeviceEventContent}, }, - AnyMessageEventContent, AnyToDeviceEvent, AnyToDeviceEventContent, MessageEvent, - ToDeviceEvent, + AnyMessageEvent, AnyMessageEventContent, AnySyncMessageEvent, AnyToDeviceEvent, + AnyToDeviceEventContent, MessageEvent, ToDeviceEvent, }, identifiers::{DeviceId, EventId, RoomId, UserId}, uuid::Uuid, @@ -53,13 +53,15 @@ pub use sas_state::FlowId; pub use event_enums::{OutgoingContent, StartContent}; +use self::event_enums::CancelContent; + #[derive(Debug)] /// A result of a verification flow. pub enum VerificationResult { /// The verification succeeded, nothing needs to be done. Ok, /// The verification was canceled. - Cancel(ToDeviceRequest), + Cancel(OutgoingVerificationRequest), /// The verification is done and has signatures that need to be uploaded. SignatureUpload(SignatureUploadRequest), } @@ -278,7 +280,13 @@ impl Sas { /// the server. pub async fn confirm( &self, - ) -> Result<(Option, Option), CryptoStoreError> { + ) -> Result< + ( + Option, + Option, + ), + CryptoStoreError, + > { let (content, done) = { let mut guard = self.inner.lock().unwrap(); let sas: InnerSas = (*guard).clone(); @@ -288,8 +296,17 @@ impl Sas { (content, guard.is_done()) }; - let mac_request = content - .map(|c| self.content_to_request(AnyToDeviceEventContent::KeyVerificationMac(c))); + let mac_request = content.map(|c| match c { + event_enums::MacContent::ToDevice(c) => self + .content_to_request(AnyToDeviceEventContent::KeyVerificationMac(c)) + .into(), + event_enums::MacContent::Room(r, c) => RoomMessageRequest { + room_id: r, + txn_id: Uuid::new_v4(), + content: AnyMessageEventContent::KeyVerificationMac(c), + } + .into(), + }); if done { match self.mark_as_done().await? { @@ -530,22 +547,26 @@ impl Sas { /// /// Returns None if the `Sas` object is already in a canceled state, /// otherwise it returns a request that needs to be sent out. - pub fn cancel(&self) -> Option { + pub fn cancel(&self) -> Option { let mut guard = self.inner.lock().unwrap(); let sas: InnerSas = (*guard).clone(); let (sas, content) = sas.cancel(CancelCode::User); *guard = sas; - content.map(|c| { - if let OutgoingContent::ToDevice(c) = c { - self.content_to_request(c) - } else { - todo!() + content.map(|c| match c { + CancelContent::Room(room_id, content) => RoomMessageRequest { + room_id, + txn_id: Uuid::new_v4(), + content: AnyMessageEventContent::KeyVerificationCancel(content), } + .into(), + CancelContent::ToDevice(c) => self + .content_to_request(AnyToDeviceEventContent::KeyVerificationCancel(c)) + .into(), }) } - pub(crate) fn cancel_if_timed_out(&self) -> Option { + pub(crate) fn cancel_if_timed_out(&self) -> Option { if self.is_canceled() || self.is_done() { None } else if self.timed_out() { @@ -553,12 +574,16 @@ impl Sas { let sas: InnerSas = (*guard).clone(); let (sas, content) = sas.cancel(CancelCode::Timeout); *guard = sas; - content.map(|c| { - if let OutgoingContent::ToDevice(c) = c { - self.content_to_request(c) - } else { - todo!() + content.map(|c| match c { + CancelContent::Room(room_id, content) => RoomMessageRequest { + room_id, + txn_id: Uuid::new_v4(), + content: AnyMessageEventContent::KeyVerificationCancel(content), } + .into(), + CancelContent::ToDevice(c) => self + .content_to_request(AnyToDeviceEventContent::KeyVerificationCancel(c)) + .into(), }) } else { None @@ -602,6 +627,15 @@ impl Sas { self.inner.lock().unwrap().decimals() } + pub(crate) fn receive_room_event(&self, event: &AnyMessageEvent) -> Option { + let mut guard = self.inner.lock().unwrap(); + let sas: InnerSas = (*guard).clone(); + let (sas, content) = sas.receive_room_event(event); + *guard = sas; + + content + } + pub(crate) fn receive_event(&self, event: &AnyToDeviceEvent) -> Option { let mut guard = self.inner.lock().unwrap(); let sas: InnerSas = (*guard).clone(); diff --git a/matrix_sdk_crypto/src/verification/sas/sas_state.rs b/matrix_sdk_crypto/src/verification/sas/sas_state.rs index 2ae05e32..d7533c75 100644 --- a/matrix_sdk_crypto/src/verification/sas/sas_state.rs +++ b/matrix_sdk_crypto/src/verification/sas/sas_state.rs @@ -28,8 +28,8 @@ use matrix_sdk_common::{ AcceptEventContent, AcceptMethod, AcceptToDeviceEventContent, MSasV1Content as AcceptV1Content, MSasV1ContentInit as AcceptV1ContentInit, }, - cancel::{CancelCode, CancelToDeviceEventContent}, - key::KeyToDeviceEventContent, + cancel::{CancelCode, CancelEventContent, CancelToDeviceEventContent}, + key::{KeyEventContent, KeyToDeviceEventContent}, mac::MacToDeviceEventContent, start::{ MSasV1Content, MSasV1ContentInit, StartEventContent, StartMethod, @@ -46,7 +46,9 @@ use matrix_sdk_common::{ use tracing::error; use super::{ - event_enums::{AcceptContent, OutgoingContent, StartContent}, + event_enums::{ + AcceptContent, CancelContent, KeyContent, MacContent, OutgoingContent, StartContent, + }, helpers::{ calculate_commitment, get_decimal, get_emoji, get_mac_content, receive_mac_event, SasIds, }, @@ -618,14 +620,17 @@ impl SasState { /// anymore. pub fn into_key_received( self, - event: &ToDeviceEvent, + sender: &UserId, + content: impl Into, ) -> Result, SasState> { - self.check_event(&event.sender, &event.content.transaction_id) + let content = content.into(); + + self.check_event(&sender, &content.flow_id().as_str()) .map_err(|c| self.clone().cancel(c))?; let accepted_protocols = AcceptedProtocols::default(); - let their_pubkey = event.content.key.clone(); + let their_pubkey = content.public_key().to_owned(); self.inner .lock() @@ -659,20 +664,23 @@ impl SasState { /// anymore. pub fn into_key_received( self, - event: &ToDeviceEvent, + sender: &UserId, + content: impl Into, ) -> Result, SasState> { - self.check_event(&event.sender, &event.content.transaction_id) + let content = content.into(); + + self.check_event(&sender, content.flow_id().as_str()) .map_err(|c| self.clone().cancel(c))?; let commitment = calculate_commitment( - &event.content.key, + content.public_key(), self.state.start_content.as_ref().clone(), ); if self.state.commitment != commitment { Err(self.cancel(CancelCode::InvalidMessage)) } else { - let their_pubkey = event.content.key.clone(); + let their_pubkey = content.public_key().to_owned(); self.inner .lock() @@ -698,15 +706,23 @@ impl SasState { /// Get the content for the key event. /// /// The content needs to be automatically sent to the other side. - pub fn as_content(&self) -> KeyToDeviceEventContent { + pub fn as_content(&self) -> OutgoingContent { match &*self.verification_flow_id { - FlowId::ToDevice(s) => KeyToDeviceEventContent { + FlowId::ToDevice(s) => KeyContent::ToDevice(KeyToDeviceEventContent { transaction_id: s.to_string(), key: self.inner.lock().unwrap().public_key(), - }, - FlowId::InRoom(_, r) => { - todo!("In-room verifications aren't implemented") - } + }) + .into(), + FlowId::InRoom(r, e) => KeyContent::Room( + r.clone(), + KeyEventContent { + key: self.inner.lock().unwrap().public_key(), + relation: Relation { + event_id: e.clone(), + }, + }, + ) + .into(), } } } @@ -716,13 +732,23 @@ impl SasState { /// /// The content needs to be automatically sent to the other side if and only /// if we_started is false. - pub fn as_content(&self) -> KeyToDeviceEventContent { - match self.verification_flow_id.as_ref() { - FlowId::ToDevice(s) => KeyToDeviceEventContent { + pub fn as_content(&self) -> KeyContent { + match &*self.verification_flow_id { + FlowId::ToDevice(s) => KeyContent::ToDevice(KeyToDeviceEventContent { transaction_id: s.to_string(), key: self.inner.lock().unwrap().public_key(), - }, - _ => todo!(), + }) + .into(), + FlowId::InRoom(r, e) => KeyContent::Room( + r.clone(), + KeyEventContent { + key: self.inner.lock().unwrap().public_key(), + relation: Relation { + event_id: e.clone(), + }, + }, + ) + .into(), } } @@ -763,16 +789,20 @@ impl SasState { /// the other side. pub fn into_mac_received( self, - event: &ToDeviceEvent, + sender: &UserId, + content: impl Into, ) -> Result, SasState> { - self.check_event(&event.sender, &event.content.transaction_id) + let content = content.into(); + + self.check_event(&sender, content.flow_id().as_str()) .map_err(|c| self.clone().cancel(c))?; let (devices, master_keys) = receive_mac_event( &self.inner.lock().unwrap(), &self.ids, self.verification_flow_id.as_str(), - event, + sender, + &content, ) .map_err(|c| self.clone().cancel(c))?; @@ -819,16 +849,20 @@ impl SasState { /// the other side. pub fn into_done( self, - event: &ToDeviceEvent, + sender: &UserId, + content: impl Into, ) -> Result, SasState> { - self.check_event(&event.sender, &event.content.transaction_id) + let content = content.into(); + + self.check_event(&sender, &content.flow_id().as_str()) .map_err(|c| self.clone().cancel(c))?; let (devices, master_keys) = receive_mac_event( &self.inner.lock().unwrap(), &self.ids, &self.verification_flow_id.as_str(), - event, + sender, + &content, ) .map_err(|c| self.clone().cancel(c))?; @@ -849,7 +883,7 @@ impl SasState { /// Get the content for the mac event. /// /// The content needs to be automatically sent to the other side. - pub fn as_content(&self) -> MacToDeviceEventContent { + pub fn as_content(&self) -> MacContent { get_mac_content( &self.inner.lock().unwrap(), &self.ids, @@ -911,7 +945,7 @@ impl SasState { /// /// The content needs to be automatically sent to the other side if it /// wasn't already sent. - pub fn as_content(&self) -> MacToDeviceEventContent { + pub fn as_content(&self) -> MacContent { get_mac_content( &self.inner.lock().unwrap(), &self.ids, @@ -959,17 +993,26 @@ impl Canceled { } impl SasState { - pub fn as_content(&self) -> OutgoingContent { + pub fn as_content(&self) -> CancelContent { match self.verification_flow_id.as_ref() { - FlowId::ToDevice(s) => { - AnyToDeviceEventContent::KeyVerificationCancel(CancelToDeviceEventContent { - transaction_id: self.verification_flow_id.to_string(), + FlowId::ToDevice(s) => CancelToDeviceEventContent { + transaction_id: s.clone(), + reason: self.state.reason.to_string(), + code: self.state.cancel_code.clone(), + } + .into(), + + FlowId::InRoom(r, e) => ( + r.clone(), + CancelEventContent { reason: self.state.reason.to_string(), code: self.state.cancel_code.clone(), - }) - .into() - } - _ => todo!(), + relation: Relation { + event_id: e.clone(), + }, + }, + ) + .into(), } } }