crypto: Make the cancelations output only CancelContents.

master
Damir Jelić 2020-12-17 12:15:11 +01:00
parent b6e28e2280
commit 79102b3390
10 changed files with 498 additions and 127 deletions

View File

@ -135,10 +135,11 @@ async fn login(
if !initial.load(Ordering::SeqCst) { if !initial.load(Ordering::SeqCst) {
for (_room_id, room_info) in response.rooms.join { for (_room_id, room_info) in response.rooms.join {
for event in room_info.timeline.events { for event in room_info.timeline.events {
if let Ok(AnySyncRoomEvent::Message(AnySyncMessageEvent::RoomMessage(m))) = if let AnySyncRoomEvent::Message(event) = event.deserialize().unwrap() {
event.deserialize() match event {
AnySyncMessageEvent::RoomMessage(m) => {
if let MessageEventContent::VerificationRequest(_) = &m.content
{ {
if let MessageEventContent::VerificationRequest(_) = &m.content {
let request = client let request = client
.get_verification_request(&m.event_id) .get_verification_request(&m.event_id)
.await .await
@ -150,6 +151,28 @@ async fn login(
.expect("Can't accept verification request"); .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;
}
}
_ => (),
}
}
} }
} }
} }

View File

@ -1160,7 +1160,7 @@ impl Client {
Ok(()) Ok(())
} }
async fn room_send_helper( pub(crate) async fn room_send_helper(
&self, &self,
request: &RoomMessageRequest, request: &RoomMessageRequest,
) -> Result<send_message_event::Response> { ) -> Result<send_message_event::Response> {

View File

@ -39,10 +39,18 @@ impl Sas {
/// Confirm that the short auth strings match on both sides. /// Confirm that the short auth strings match on both sides.
pub async fn confirm(&self) -> Result<()> { 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 { match request {
self.client.send_to_device(&request).await?; 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 { if let Some(s) = signature {
@ -55,7 +63,14 @@ impl Sas {
/// Cancel the interactive verification flow. /// Cancel the interactive verification flow.
pub async fn cancel(&self) -> Result<()> { pub async fn cancel(&self) -> Result<()> {
if let Some(request) = self.inner.cancel() { 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(()) Ok(())

View File

@ -166,6 +166,24 @@ impl From<SignatureUploadRequest> for OutgoingRequests {
} }
} }
impl From<OutgoingVerificationRequest> for OutgoingRequest {
fn from(r: OutgoingVerificationRequest) -> Self {
Self {
request_id: r.request_id(),
request: Arc::new(r.into()),
}
}
}
impl From<SignatureUploadRequest> 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. /// Enum over all the incoming responses we need to receive.
#[derive(Debug)] #[derive(Debug)]
pub enum IncomingResponse<'a> { pub enum IncomingResponse<'a> {

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std::sync::Arc; use std::{convert::TryFrom, sync::Arc};
use dashmap::DashMap; use dashmap::DashMap;
@ -20,7 +20,7 @@ use tracing::{info, trace, warn};
use matrix_sdk_common::{ use matrix_sdk_common::{
events::{ events::{
room::message::MessageEventContent, AnySyncMessageEvent, AnySyncRoomEvent, room::message::MessageEventContent, AnyMessageEvent, AnySyncMessageEvent, AnySyncRoomEvent,
AnyToDeviceEvent, AnyToDeviceEventContent, AnyToDeviceEvent, AnyToDeviceEventContent,
}, },
identifiers::{DeviceId, EventId, RoomId, UserId}, identifiers::{DeviceId, EventId, RoomId, UserId},
@ -112,9 +112,20 @@ impl VerificationMachine {
} }
pub fn get_sas(&self, transaction_id: &str) -> Option<Sas> { pub fn get_sas(&self, transaction_id: &str) -> Option<Sas> {
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)] #[allow(clippy::map_clone)]
self.verifications.get(transaction_id).map(|s| s.clone()) self.verifications.get(transaction_id).map(|s| s.clone())
} }
}
fn queue_up_content( fn queue_up_content(
&self, &self,
@ -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) { fn receive_event_helper(&self, sas: &Sas, event: &AnyToDeviceEvent) {
if let Some(c) = sas.receive_event(event) { if let Some(c) = sas.receive_event(event) {
self.queue_up_content(sas.other_user_id(), sas.other_device_id(), c); 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() { for sas in self.verifications.iter() {
if let Some(r) = sas.cancel_if_timed_out() { if let Some(r) = sas.cancel_if_timed_out() {
self.outgoing_to_device_messages.insert( self.outgoing_to_device_messages.insert(
r.txn_id, r.request_id(),
OutgoingRequest { OutgoingRequest {
request_id: r.txn_id, request_id: r.request_id(),
request: Arc::new(r.into()), request: Arc::new(r.into()),
}, },
); );
@ -204,6 +222,12 @@ impl VerificationMachine {
event: &AnySyncRoomEvent, event: &AnySyncRoomEvent,
) -> Result<(), CryptoStoreError> { ) -> Result<(), CryptoStoreError> {
if let AnySyncRoomEvent::Message(m) = event { 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 { match m {
AnySyncMessageEvent::RoomMessage(m) => { AnySyncMessageEvent::RoomMessage(m) => {
if let MessageEventContent::VerificationRequest(r) = &m.content { if let MessageEventContent::VerificationRequest(r) = &m.content {
@ -245,25 +269,19 @@ impl VerificationMachine {
self.store.get_user_identity(&e.sender).await?, self.store.get_user_identity(&e.sender).await?,
) { ) {
Ok(s) => { Ok(s) => {
// TODO we need to queue up the accept event
// here.
info!( info!(
"Started a new SAS verification, \ "Started a new SAS verification, \
automatically accepting because of in-room" automatically accepting because of in-room"
); );
// TODO remove this unwrap
let accept_request = s.accept().unwrap(); let accept_request = s.accept().unwrap();
self.room_verifications self.room_verifications
.insert(e.content.relation.event_id.clone(), s); .insert(e.content.relation.event_id.clone(), s);
self.outgoing_room_messages.insert( self.outgoing_room_messages
accept_request.request_id(), .insert(accept_request.request_id(), accept_request.into());
OutgoingRequest {
request_id: accept_request.request_id(),
request: Arc::new(accept_request.into()),
},
);
} }
Err(c) => { Err(c) => {
warn!( 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::Ok => (),
VerificationResult::Cancel(r) => { VerificationResult::Cancel(r) => {
self.outgoing_to_device_messages.insert( self.outgoing_to_device_messages.insert(
r.txn_id, r.request_id(),
OutgoingRequest { OutgoingRequest {
request_id: r.txn_id, request_id: r.request_id(),
request: Arc::new(r.into()), request: Arc::new(r.into()),
}, },
); );

View File

@ -14,16 +14,18 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::convert::TryInto; use std::{collections::BTreeMap, convert::TryInto};
use matrix_sdk_common::{ use matrix_sdk_common::{
events::{ events::{
key::verification::{ key::verification::{
accept::{AcceptEventContent, AcceptToDeviceEventContent}, accept::{AcceptEventContent, AcceptToDeviceEventContent},
cancel::{CancelEventContent, CancelToDeviceEventContent},
key::{KeyEventContent, KeyToDeviceEventContent},
mac::{MacEventContent, MacToDeviceEventContent},
start::{StartEventContent, StartMethod, StartToDeviceEventContent}, start::{StartEventContent, StartMethod, StartToDeviceEventContent},
KeyAgreementProtocol,
}, },
AnyMessageEventContent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent, AnyMessageEventContent, AnyToDeviceEventContent,
}, },
identifiers::RoomId, identifiers::RoomId,
CanonicalJsonValue, 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<KeyToDeviceEventContent> 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<String, String> {
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<MacToDeviceEventContent> 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<CancelToDeviceEventContent> for CancelContent {
fn from(content: CancelToDeviceEventContent) -> Self {
CancelContent::ToDevice(content)
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum OutgoingContent { pub enum OutgoingContent {
Room(RoomId, AnyMessageEventContent), Room(RoomId, AnyMessageEventContent),
@ -110,6 +202,26 @@ impl From<StartContent> for OutgoingContent {
} }
} }
impl From<CancelContent> 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<KeyContent> 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<AnyToDeviceEventContent> for OutgoingContent { impl From<AnyToDeviceEventContent> for OutgoingContent {
fn from(content: AnyToDeviceEventContent) -> Self { fn from(content: AnyToDeviceEventContent) -> Self {
OutgoingContent::ToDevice(content) OutgoingContent::ToDevice(content)

View File

@ -23,7 +23,10 @@ use matrix_sdk_common::{
api::r0::to_device::DeviceIdOrAllDevices, api::r0::to_device::DeviceIdOrAllDevices,
events::{ events::{
key::verification::{ key::verification::{
cancel::CancelCode, mac::MacToDeviceEventContent, start::StartToDeviceEventContent, cancel::CancelCode,
mac::{MacEventContent, MacToDeviceEventContent},
start::StartToDeviceEventContent,
Relation,
}, },
AnyToDeviceEventContent, EventType, ToDeviceEvent, AnyToDeviceEventContent, EventType, ToDeviceEvent,
}, },
@ -38,7 +41,10 @@ use crate::{
ReadOnlyAccount, ToDeviceRequest, ReadOnlyAccount, ToDeviceRequest,
}; };
use super::{event_enums::StartContent, sas_state::FlowId}; use super::{
event_enums::{MacContent, StartContent},
sas_state::FlowId,
};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SasIds { pub struct SasIds {
@ -186,7 +192,8 @@ pub fn receive_mac_event(
sas: &OlmSas, sas: &OlmSas,
ids: &SasIds, ids: &SasIds,
flow_id: &str, flow_id: &str,
event: &ToDeviceEvent<MacToDeviceEventContent>, sender: &UserId,
content: &MacContent,
) -> Result<(Vec<ReadOnlyDevice>, Vec<UserIdentities>), CancelCode> { ) -> Result<(Vec<ReadOnlyDevice>, Vec<UserIdentities>), CancelCode> {
let mut verified_devices = Vec::new(); let mut verified_devices = Vec::new();
let mut verified_identities = Vec::new(); let mut verified_identities = Vec::new();
@ -195,25 +202,25 @@ pub fn receive_mac_event(
trace!( trace!(
"Received a key.verification.mac event from {} {}", "Received a key.verification.mac event from {} {}",
event.sender, sender,
ids.other_device.device_id() ids.other_device.device_id()
); );
let mut keys = event.content.mac.keys().cloned().collect::<Vec<String>>(); let mut keys = content.mac().keys().cloned().collect::<Vec<String>>();
keys.sort(); keys.sort();
let keys = sas let keys = sas
.calculate_mac(&keys.join(","), &format!("{}KEY_IDS", &info)) .calculate_mac(&keys.join(","), &format!("{}KEY_IDS", &info))
.expect("Can't calculate SAS MAC"); .expect("Can't calculate SAS MAC");
if keys != event.content.keys { if keys != content.keys() {
return Err(CancelCode::KeyMismatch); return Err(CancelCode::KeyMismatch);
} }
for (key_id, key_mac) in &event.content.mac { for (key_id, key_mac) in content.mac() {
trace!( trace!(
"Checking MAC for the key id {} from {} {}", "Checking MAC for the key id {} from {} {}",
key_id, key_id,
event.sender, sender,
ids.other_device.device_id() ids.other_device.device_id()
); );
let key_id: DeviceKeyId = match key_id.as_str().try_into() { 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)) .calculate_mac(key, &format!("{}{}", info, key_id))
.expect("Can't calculate SAS MAC") .expect("Can't calculate SAS MAC")
{ {
trace!(
"Successfully verified the device key {} from {}",
key_id,
sender
);
verified_devices.push(ids.other_device.clone()); verified_devices.push(ids.other_device.clone());
} else { } else {
return Err(CancelCode::KeyMismatch); return Err(CancelCode::KeyMismatch);
@ -243,7 +256,7 @@ pub fn receive_mac_event(
trace!( trace!(
"Successfully verified the master key {} from {}", "Successfully verified the master key {} from {}",
key_id, key_id,
event.sender sender
); );
verified_identities.push(identity.clone()) verified_identities.push(identity.clone())
} else { } else {
@ -255,7 +268,7 @@ pub fn receive_mac_event(
"Key ID {} in MAC event from {} {} doesn't belong to any device \ "Key ID {} in MAC event from {} {} doesn't belong to any device \
or user identity", or user identity",
key_id, key_id,
event.sender, sender,
ids.other_device.device_id() ids.other_device.device_id()
); );
} }
@ -297,7 +310,7 @@ fn extra_mac_info_send(ids: &SasIds, flow_id: &str) -> String {
/// # Panics /// # Panics
/// ///
/// This will panic if the public key of the other side wasn't set. /// 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<String, String> = BTreeMap::new(); let mut mac: BTreeMap<String, String> = BTreeMap::new();
let key_id = DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, ids.account.device_id()); 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(), transaction_id: s.to_string(),
keys, keys,
mac, mac,
}
.into(),
FlowId::InRoom(r, e) => (
r.clone(),
MacEventContent {
mac,
keys,
relation: Relation {
event_id: e.clone(),
}, },
_ => todo!(), },
)
.into(),
} }
} }

View File

@ -25,7 +25,8 @@ use matrix_sdk_common::{
mac::MacToDeviceEventContent, mac::MacToDeviceEventContent,
start::{StartEventContent, StartToDeviceEventContent}, start::{StartEventContent, StartToDeviceEventContent},
}, },
AnyToDeviceEvent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent, AnyMessageEvent, AnyMessageEventContent, AnySyncMessageEvent, AnyToDeviceEvent,
AnyToDeviceEventContent, MessageEvent, ToDeviceEvent,
}, },
identifiers::{EventId, RoomId, UserId}, identifiers::{EventId, RoomId, UserId},
}; };
@ -36,7 +37,7 @@ use crate::{
}; };
use super::{ use super::{
event_enums::{AcceptContent, OutgoingContent}, event_enums::{AcceptContent, CancelContent, MacContent, OutgoingContent},
sas_state::{ sas_state::{
Accepted, Canceled, Confirmed, Created, Done, FlowId, KeyReceived, MacReceived, SasState, Accepted, Canceled, Confirmed, Created, Done, FlowId, KeyReceived, MacReceived, SasState,
Started, Started,
@ -91,7 +92,7 @@ impl InnerSas {
sender: &UserId, sender: &UserId,
content: impl Into<StartContent>, content: impl Into<StartContent>,
other_identity: Option<UserIdentities>, other_identity: Option<UserIdentities>,
) -> Result<InnerSas, OutgoingContent> { ) -> Result<InnerSas, CancelContent> {
match SasState::<Started>::from_start_event( match SasState::<Started>::from_start_event(
account, account,
other_device, other_device,
@ -127,7 +128,7 @@ impl InnerSas {
} }
} }
pub fn cancel(self, code: CancelCode) -> (InnerSas, Option<OutgoingContent>) { pub fn cancel(self, code: CancelCode) -> (InnerSas, Option<CancelContent>) {
let sas = match self { let sas = match self {
InnerSas::Created(s) => s.cancel(code), InnerSas::Created(s) => s.cancel(code),
InnerSas::Started(s) => s.cancel(code), InnerSas::Started(s) => s.cancel(code),
@ -142,7 +143,7 @@ impl InnerSas {
(InnerSas::Canceled(sas), Some(content)) (InnerSas::Canceled(sas), Some(content))
} }
pub fn confirm(self) -> (InnerSas, Option<MacToDeviceEventContent>) { pub fn confirm(self) -> (InnerSas, Option<MacContent>) {
match self { match self {
InnerSas::KeyRecieved(s) => { InnerSas::KeyRecieved(s) => {
let sas = s.confirm(); let sas = s.confirm();
@ -158,6 +159,62 @@ impl InnerSas {
} }
} }
#[allow(dead_code)]
pub fn receive_room_event(
self,
event: &AnyMessageEvent,
) -> (InnerSas, Option<OutgoingContent>) {
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<OutgoingContent>) { pub fn receive_event(self, event: &AnyToDeviceEvent) -> (InnerSas, Option<OutgoingContent>) {
match event { match event {
AnyToDeviceEvent::KeyVerificationAccept(e) => { AnyToDeviceEvent::KeyVerificationAccept(e) => {
@ -165,14 +222,11 @@ impl InnerSas {
match s.into_accepted(e) { match s.into_accepted(e) {
Ok(s) => { Ok(s) => {
let content = s.as_content(); let content = s.as_content();
( (InnerSas::Accepted(s), Some(content.into()))
InnerSas::Accepted(s),
Some(AnyToDeviceEventContent::KeyVerificationKey(content).into()),
)
} }
Err(s) => { Err(s) => {
let content = s.as_content(); let content = s.as_content();
(InnerSas::Canceled(s), Some(content)) (InnerSas::Canceled(s), Some(content.into()))
} }
} }
} else { } else {
@ -180,41 +234,39 @@ impl InnerSas {
} }
} }
AnyToDeviceEvent::KeyVerificationKey(e) => match self { 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), Ok(s) => (InnerSas::KeyRecieved(s), None),
Err(s) => { Err(s) => {
let content = s.as_content(); 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) => { Ok(s) => {
let content = s.as_content(); let content = s.as_content();
( (InnerSas::KeyRecieved(s), Some(content.into()))
InnerSas::KeyRecieved(s),
Some(AnyToDeviceEventContent::KeyVerificationKey(content).into()),
)
} }
Err(s) => { Err(s) => {
let content = s.as_content(); let content = s.as_content();
(InnerSas::Canceled(s), Some(content)) (InnerSas::Canceled(s), Some(content.into()))
} }
}, },
_ => (self, None), _ => (self, None),
}, },
AnyToDeviceEvent::KeyVerificationMac(e) => match self { 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), Ok(s) => (InnerSas::MacReceived(s), None),
Err(s) => { Err(s) => {
let content = s.as_content(); 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), Ok(s) => (InnerSas::Done(s), None),
Err(s) => { Err(s) => {
let content = s.as_content(); let content = s.as_content();
(InnerSas::Canceled(s), Some(content)) (InnerSas::Canceled(s), Some(content.into()))
} }
}, },
_ => (self, None), _ => (self, None),

View File

@ -31,8 +31,8 @@ use matrix_sdk_common::{
cancel::CancelCode, cancel::CancelCode,
start::{StartEventContent, StartToDeviceEventContent}, start::{StartEventContent, StartToDeviceEventContent},
}, },
AnyMessageEventContent, AnyToDeviceEvent, AnyToDeviceEventContent, MessageEvent, AnyMessageEvent, AnyMessageEventContent, AnySyncMessageEvent, AnyToDeviceEvent,
ToDeviceEvent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent,
}, },
identifiers::{DeviceId, EventId, RoomId, UserId}, identifiers::{DeviceId, EventId, RoomId, UserId},
uuid::Uuid, uuid::Uuid,
@ -53,13 +53,15 @@ pub use sas_state::FlowId;
pub use event_enums::{OutgoingContent, StartContent}; pub use event_enums::{OutgoingContent, StartContent};
use self::event_enums::CancelContent;
#[derive(Debug)] #[derive(Debug)]
/// A result of a verification flow. /// A result of a verification flow.
pub enum VerificationResult { pub enum VerificationResult {
/// The verification succeeded, nothing needs to be done. /// The verification succeeded, nothing needs to be done.
Ok, Ok,
/// The verification was canceled. /// The verification was canceled.
Cancel(ToDeviceRequest), Cancel(OutgoingVerificationRequest),
/// The verification is done and has signatures that need to be uploaded. /// The verification is done and has signatures that need to be uploaded.
SignatureUpload(SignatureUploadRequest), SignatureUpload(SignatureUploadRequest),
} }
@ -278,7 +280,13 @@ impl Sas {
/// the server. /// the server.
pub async fn confirm( pub async fn confirm(
&self, &self,
) -> Result<(Option<ToDeviceRequest>, Option<SignatureUploadRequest>), CryptoStoreError> { ) -> Result<
(
Option<OutgoingVerificationRequest>,
Option<SignatureUploadRequest>,
),
CryptoStoreError,
> {
let (content, done) = { let (content, done) = {
let mut guard = self.inner.lock().unwrap(); let mut guard = self.inner.lock().unwrap();
let sas: InnerSas = (*guard).clone(); let sas: InnerSas = (*guard).clone();
@ -288,8 +296,17 @@ impl Sas {
(content, guard.is_done()) (content, guard.is_done())
}; };
let mac_request = content let mac_request = content.map(|c| match c {
.map(|c| self.content_to_request(AnyToDeviceEventContent::KeyVerificationMac(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 { if done {
match self.mark_as_done().await? { match self.mark_as_done().await? {
@ -530,22 +547,26 @@ impl Sas {
/// ///
/// Returns None if the `Sas` object is already in a canceled state, /// Returns None if the `Sas` object is already in a canceled state,
/// otherwise it returns a request that needs to be sent out. /// otherwise it returns a request that needs to be sent out.
pub fn cancel(&self) -> Option<ToDeviceRequest> { pub fn cancel(&self) -> Option<OutgoingVerificationRequest> {
let mut guard = self.inner.lock().unwrap(); let mut guard = self.inner.lock().unwrap();
let sas: InnerSas = (*guard).clone(); let sas: InnerSas = (*guard).clone();
let (sas, content) = sas.cancel(CancelCode::User); let (sas, content) = sas.cancel(CancelCode::User);
*guard = sas; *guard = sas;
content.map(|c| { content.map(|c| match c {
if let OutgoingContent::ToDevice(c) = c { CancelContent::Room(room_id, content) => RoomMessageRequest {
self.content_to_request(c) room_id,
} else { txn_id: Uuid::new_v4(),
todo!() 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<ToDeviceRequest> { pub(crate) fn cancel_if_timed_out(&self) -> Option<OutgoingVerificationRequest> {
if self.is_canceled() || self.is_done() { if self.is_canceled() || self.is_done() {
None None
} else if self.timed_out() { } else if self.timed_out() {
@ -553,12 +574,16 @@ impl Sas {
let sas: InnerSas = (*guard).clone(); let sas: InnerSas = (*guard).clone();
let (sas, content) = sas.cancel(CancelCode::Timeout); let (sas, content) = sas.cancel(CancelCode::Timeout);
*guard = sas; *guard = sas;
content.map(|c| { content.map(|c| match c {
if let OutgoingContent::ToDevice(c) = c { CancelContent::Room(room_id, content) => RoomMessageRequest {
self.content_to_request(c) room_id,
} else { txn_id: Uuid::new_v4(),
todo!() content: AnyMessageEventContent::KeyVerificationCancel(content),
} }
.into(),
CancelContent::ToDevice(c) => self
.content_to_request(AnyToDeviceEventContent::KeyVerificationCancel(c))
.into(),
}) })
} else { } else {
None None
@ -602,6 +627,15 @@ impl Sas {
self.inner.lock().unwrap().decimals() self.inner.lock().unwrap().decimals()
} }
pub(crate) fn receive_room_event(&self, event: &AnyMessageEvent) -> Option<OutgoingContent> {
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<OutgoingContent> { pub(crate) fn receive_event(&self, event: &AnyToDeviceEvent) -> Option<OutgoingContent> {
let mut guard = self.inner.lock().unwrap(); let mut guard = self.inner.lock().unwrap();
let sas: InnerSas = (*guard).clone(); let sas: InnerSas = (*guard).clone();

View File

@ -28,8 +28,8 @@ use matrix_sdk_common::{
AcceptEventContent, AcceptMethod, AcceptToDeviceEventContent, AcceptEventContent, AcceptMethod, AcceptToDeviceEventContent,
MSasV1Content as AcceptV1Content, MSasV1ContentInit as AcceptV1ContentInit, MSasV1Content as AcceptV1Content, MSasV1ContentInit as AcceptV1ContentInit,
}, },
cancel::{CancelCode, CancelToDeviceEventContent}, cancel::{CancelCode, CancelEventContent, CancelToDeviceEventContent},
key::KeyToDeviceEventContent, key::{KeyEventContent, KeyToDeviceEventContent},
mac::MacToDeviceEventContent, mac::MacToDeviceEventContent,
start::{ start::{
MSasV1Content, MSasV1ContentInit, StartEventContent, StartMethod, MSasV1Content, MSasV1ContentInit, StartEventContent, StartMethod,
@ -46,7 +46,9 @@ use matrix_sdk_common::{
use tracing::error; use tracing::error;
use super::{ use super::{
event_enums::{AcceptContent, OutgoingContent, StartContent}, event_enums::{
AcceptContent, CancelContent, KeyContent, MacContent, OutgoingContent, StartContent,
},
helpers::{ helpers::{
calculate_commitment, get_decimal, get_emoji, get_mac_content, receive_mac_event, SasIds, calculate_commitment, get_decimal, get_emoji, get_mac_content, receive_mac_event, SasIds,
}, },
@ -618,14 +620,17 @@ impl SasState<Started> {
/// anymore. /// anymore.
pub fn into_key_received( pub fn into_key_received(
self, self,
event: &ToDeviceEvent<KeyToDeviceEventContent>, sender: &UserId,
content: impl Into<KeyContent>,
) -> Result<SasState<KeyReceived>, SasState<Canceled>> { ) -> Result<SasState<KeyReceived>, SasState<Canceled>> {
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))?; .map_err(|c| self.clone().cancel(c))?;
let accepted_protocols = AcceptedProtocols::default(); let accepted_protocols = AcceptedProtocols::default();
let their_pubkey = event.content.key.clone(); let their_pubkey = content.public_key().to_owned();
self.inner self.inner
.lock() .lock()
@ -659,20 +664,23 @@ impl SasState<Accepted> {
/// anymore. /// anymore.
pub fn into_key_received( pub fn into_key_received(
self, self,
event: &ToDeviceEvent<KeyToDeviceEventContent>, sender: &UserId,
content: impl Into<KeyContent>,
) -> Result<SasState<KeyReceived>, SasState<Canceled>> { ) -> Result<SasState<KeyReceived>, SasState<Canceled>> {
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))?; .map_err(|c| self.clone().cancel(c))?;
let commitment = calculate_commitment( let commitment = calculate_commitment(
&event.content.key, content.public_key(),
self.state.start_content.as_ref().clone(), self.state.start_content.as_ref().clone(),
); );
if self.state.commitment != commitment { if self.state.commitment != commitment {
Err(self.cancel(CancelCode::InvalidMessage)) Err(self.cancel(CancelCode::InvalidMessage))
} else { } else {
let their_pubkey = event.content.key.clone(); let their_pubkey = content.public_key().to_owned();
self.inner self.inner
.lock() .lock()
@ -698,15 +706,23 @@ impl SasState<Accepted> {
/// Get the content for the key event. /// Get the content for the key event.
/// ///
/// The content needs to be automatically sent to the other side. /// 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 { match &*self.verification_flow_id {
FlowId::ToDevice(s) => KeyToDeviceEventContent { FlowId::ToDevice(s) => KeyContent::ToDevice(KeyToDeviceEventContent {
transaction_id: s.to_string(), transaction_id: s.to_string(),
key: self.inner.lock().unwrap().public_key(), key: self.inner.lock().unwrap().public_key(),
})
.into(),
FlowId::InRoom(r, e) => KeyContent::Room(
r.clone(),
KeyEventContent {
key: self.inner.lock().unwrap().public_key(),
relation: Relation {
event_id: e.clone(),
}, },
FlowId::InRoom(_, r) => { },
todo!("In-room verifications aren't implemented") )
} .into(),
} }
} }
} }
@ -716,13 +732,23 @@ impl SasState<KeyReceived> {
/// ///
/// The content needs to be automatically sent to the other side if and only /// The content needs to be automatically sent to the other side if and only
/// if we_started is false. /// if we_started is false.
pub fn as_content(&self) -> KeyToDeviceEventContent { pub fn as_content(&self) -> KeyContent {
match self.verification_flow_id.as_ref() { match &*self.verification_flow_id {
FlowId::ToDevice(s) => KeyToDeviceEventContent { FlowId::ToDevice(s) => KeyContent::ToDevice(KeyToDeviceEventContent {
transaction_id: s.to_string(), transaction_id: s.to_string(),
key: self.inner.lock().unwrap().public_key(), key: self.inner.lock().unwrap().public_key(),
})
.into(),
FlowId::InRoom(r, e) => KeyContent::Room(
r.clone(),
KeyEventContent {
key: self.inner.lock().unwrap().public_key(),
relation: Relation {
event_id: e.clone(),
}, },
_ => todo!(), },
)
.into(),
} }
} }
@ -763,16 +789,20 @@ impl SasState<KeyReceived> {
/// the other side. /// the other side.
pub fn into_mac_received( pub fn into_mac_received(
self, self,
event: &ToDeviceEvent<MacToDeviceEventContent>, sender: &UserId,
content: impl Into<MacContent>,
) -> Result<SasState<MacReceived>, SasState<Canceled>> { ) -> Result<SasState<MacReceived>, SasState<Canceled>> {
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))?; .map_err(|c| self.clone().cancel(c))?;
let (devices, master_keys) = receive_mac_event( let (devices, master_keys) = receive_mac_event(
&self.inner.lock().unwrap(), &self.inner.lock().unwrap(),
&self.ids, &self.ids,
self.verification_flow_id.as_str(), self.verification_flow_id.as_str(),
event, sender,
&content,
) )
.map_err(|c| self.clone().cancel(c))?; .map_err(|c| self.clone().cancel(c))?;
@ -819,16 +849,20 @@ impl SasState<Confirmed> {
/// the other side. /// the other side.
pub fn into_done( pub fn into_done(
self, self,
event: &ToDeviceEvent<MacToDeviceEventContent>, sender: &UserId,
content: impl Into<MacContent>,
) -> Result<SasState<Done>, SasState<Canceled>> { ) -> Result<SasState<Done>, SasState<Canceled>> {
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))?; .map_err(|c| self.clone().cancel(c))?;
let (devices, master_keys) = receive_mac_event( let (devices, master_keys) = receive_mac_event(
&self.inner.lock().unwrap(), &self.inner.lock().unwrap(),
&self.ids, &self.ids,
&self.verification_flow_id.as_str(), &self.verification_flow_id.as_str(),
event, sender,
&content,
) )
.map_err(|c| self.clone().cancel(c))?; .map_err(|c| self.clone().cancel(c))?;
@ -849,7 +883,7 @@ impl SasState<Confirmed> {
/// Get the content for the mac event. /// Get the content for the mac event.
/// ///
/// The content needs to be automatically sent to the other side. /// 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( get_mac_content(
&self.inner.lock().unwrap(), &self.inner.lock().unwrap(),
&self.ids, &self.ids,
@ -911,7 +945,7 @@ impl SasState<Done> {
/// ///
/// The content needs to be automatically sent to the other side if it /// The content needs to be automatically sent to the other side if it
/// wasn't already sent. /// wasn't already sent.
pub fn as_content(&self) -> MacToDeviceEventContent { pub fn as_content(&self) -> MacContent {
get_mac_content( get_mac_content(
&self.inner.lock().unwrap(), &self.inner.lock().unwrap(),
&self.ids, &self.ids,
@ -959,17 +993,26 @@ impl Canceled {
} }
impl SasState<Canceled> { impl SasState<Canceled> {
pub fn as_content(&self) -> OutgoingContent { pub fn as_content(&self) -> CancelContent {
match self.verification_flow_id.as_ref() { match self.verification_flow_id.as_ref() {
FlowId::ToDevice(s) => { FlowId::ToDevice(s) => CancelToDeviceEventContent {
AnyToDeviceEventContent::KeyVerificationCancel(CancelToDeviceEventContent { transaction_id: s.clone(),
transaction_id: self.verification_flow_id.to_string(),
reason: self.state.reason.to_string(), reason: self.state.reason.to_string(),
code: self.state.cancel_code.clone(), code: self.state.cancel_code.clone(),
})
.into()
} }
_ => todo!(), .into(),
FlowId::InRoom(r, e) => (
r.clone(),
CancelEventContent {
reason: self.state.reason.to_string(),
code: self.state.cancel_code.clone(),
relation: Relation {
event_id: e.clone(),
},
},
)
.into(),
} }
} }
} }