diff --git a/matrix_sdk_crypto/src/verification/sas/inner_sas.rs b/matrix_sdk_crypto/src/verification/sas/inner_sas.rs new file mode 100644 index 00000000..6a566990 --- /dev/null +++ b/matrix_sdk_crypto/src/verification/sas/inner_sas.rs @@ -0,0 +1,267 @@ +// Copyright 2020 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[cfg(test)] +use std::time::Instant; + +use std::sync::Arc; + +use matrix_sdk_common::events::{ + key::verification::{ + accept::AcceptToDeviceEventContent, cancel::CancelCode, mac::MacToDeviceEventContent, + start::StartToDeviceEventContent, + }, + AnyToDeviceEvent, AnyToDeviceEventContent, ToDeviceEvent, +}; + +use crate::{ + identities::{ReadOnlyDevice, UserIdentities}, + ReadOnlyAccount, +}; + +use super::sas_state::{ + Accepted, Canceled, Confirmed, Created, Done, KeyReceived, MacReceived, SasState, Started, +}; + +#[derive(Clone, Debug)] +pub enum InnerSas { + Created(SasState), + Started(SasState), + Accepted(SasState), + KeyRecieved(SasState), + Confirmed(SasState), + MacReceived(SasState), + Done(SasState), + Canceled(SasState), +} + +impl InnerSas { + pub fn start( + account: ReadOnlyAccount, + other_device: ReadOnlyDevice, + other_identity: Option, + ) -> (InnerSas, StartToDeviceEventContent) { + let sas = SasState::::new(account, other_device, other_identity); + let content = sas.as_content(); + (InnerSas::Created(sas), content) + } + + pub fn from_start_event( + account: ReadOnlyAccount, + other_device: ReadOnlyDevice, + event: &ToDeviceEvent, + other_identity: Option, + ) -> Result { + match SasState::::from_start_event(account, other_device, event, other_identity) { + Ok(s) => Ok(InnerSas::Started(s)), + Err(s) => Err(s.as_content()), + } + } + + pub fn accept(&self) -> Option { + if let InnerSas::Started(s) = self { + Some(s.as_content()) + } else { + None + } + } + + #[cfg(test)] + #[allow(dead_code)] + pub fn set_creation_time(&mut self, time: Instant) { + match self { + InnerSas::Created(s) => s.set_creation_time(time), + InnerSas::Started(s) => s.set_creation_time(time), + InnerSas::Canceled(s) => s.set_creation_time(time), + InnerSas::Accepted(s) => s.set_creation_time(time), + InnerSas::KeyRecieved(s) => s.set_creation_time(time), + InnerSas::Confirmed(s) => s.set_creation_time(time), + InnerSas::MacReceived(s) => s.set_creation_time(time), + InnerSas::Done(s) => s.set_creation_time(time), + } + } + + pub fn cancel(self, code: CancelCode) -> (InnerSas, Option) { + let sas = match self { + InnerSas::Created(s) => s.cancel(code), + InnerSas::Started(s) => s.cancel(code), + InnerSas::Accepted(s) => s.cancel(code), + InnerSas::KeyRecieved(s) => s.cancel(code), + InnerSas::MacReceived(s) => s.cancel(code), + _ => return (self, None), + }; + + let content = sas.as_content(); + + (InnerSas::Canceled(sas), Some(content)) + } + + pub fn confirm(self) -> (InnerSas, Option) { + match self { + InnerSas::KeyRecieved(s) => { + let sas = s.confirm(); + let content = sas.as_content(); + (InnerSas::Confirmed(sas), Some(content)) + } + InnerSas::MacReceived(s) => { + let sas = s.confirm(); + let content = sas.as_content(); + (InnerSas::Done(sas), Some(content)) + } + _ => (self, None), + } + } + + pub fn receive_event( + self, + event: &AnyToDeviceEvent, + ) -> (InnerSas, Option) { + match event { + AnyToDeviceEvent::KeyVerificationAccept(e) => { + if let InnerSas::Created(s) = self { + match s.into_accepted(e) { + Ok(s) => { + let content = s.as_content(); + ( + InnerSas::Accepted(s), + Some(AnyToDeviceEventContent::KeyVerificationKey(content)), + ) + } + Err(s) => { + let content = s.as_content(); + (InnerSas::Canceled(s), Some(content)) + } + } + } else { + (self, None) + } + } + AnyToDeviceEvent::KeyVerificationKey(e) => match self { + InnerSas::Accepted(s) => match s.into_key_received(e) { + Ok(s) => (InnerSas::KeyRecieved(s), None), + Err(s) => { + let content = s.as_content(); + (InnerSas::Canceled(s), Some(content)) + } + }, + InnerSas::Started(s) => match s.into_key_received(e) { + Ok(s) => { + let content = s.as_content(); + ( + InnerSas::KeyRecieved(s), + Some(AnyToDeviceEventContent::KeyVerificationKey(content)), + ) + } + Err(s) => { + let content = s.as_content(); + (InnerSas::Canceled(s), Some(content)) + } + }, + _ => (self, None), + }, + AnyToDeviceEvent::KeyVerificationMac(e) => match self { + InnerSas::KeyRecieved(s) => match s.into_mac_received(e) { + Ok(s) => (InnerSas::MacReceived(s), None), + Err(s) => { + let content = s.as_content(); + (InnerSas::Canceled(s), Some(content)) + } + }, + InnerSas::Confirmed(s) => match s.into_done(e) { + Ok(s) => (InnerSas::Done(s), None), + Err(s) => { + let content = s.as_content(); + (InnerSas::Canceled(s), Some(content)) + } + }, + _ => (self, None), + }, + _ => (self, None), + } + } + + pub fn can_be_presented(&self) -> bool { + match self { + InnerSas::KeyRecieved(_) => true, + InnerSas::MacReceived(_) => true, + _ => false, + } + } + + pub fn is_done(&self) -> bool { + matches!(self, InnerSas::Done(_)) + } + + pub fn is_canceled(&self) -> bool { + matches!(self, InnerSas::Canceled(_)) + } + + pub fn timed_out(&self) -> bool { + match self { + InnerSas::Created(s) => s.timed_out(), + InnerSas::Started(s) => s.timed_out(), + InnerSas::Canceled(s) => s.timed_out(), + InnerSas::Accepted(s) => s.timed_out(), + InnerSas::KeyRecieved(s) => s.timed_out(), + InnerSas::Confirmed(s) => s.timed_out(), + InnerSas::MacReceived(s) => s.timed_out(), + InnerSas::Done(s) => s.timed_out(), + } + } + + pub fn verification_flow_id(&self) -> Arc { + match self { + InnerSas::Created(s) => s.verification_flow_id.clone(), + InnerSas::Started(s) => s.verification_flow_id.clone(), + InnerSas::Canceled(s) => s.verification_flow_id.clone(), + InnerSas::Accepted(s) => s.verification_flow_id.clone(), + InnerSas::KeyRecieved(s) => s.verification_flow_id.clone(), + InnerSas::Confirmed(s) => s.verification_flow_id.clone(), + InnerSas::MacReceived(s) => s.verification_flow_id.clone(), + InnerSas::Done(s) => s.verification_flow_id.clone(), + } + } + + pub fn emoji(&self) -> Option> { + match self { + InnerSas::KeyRecieved(s) => Some(s.get_emoji()), + InnerSas::MacReceived(s) => Some(s.get_emoji()), + _ => None, + } + } + + pub fn decimals(&self) -> Option<(u16, u16, u16)> { + match self { + InnerSas::KeyRecieved(s) => Some(s.get_decimal()), + InnerSas::MacReceived(s) => Some(s.get_decimal()), + _ => None, + } + } + + pub fn verified_devices(&self) -> Option> { + if let InnerSas::Done(s) = self { + Some(s.verified_devices()) + } else { + None + } + } + + pub fn verified_identities(&self) -> Option> { + if let InnerSas::Done(s) = self { + Some(s.verified_identities()) + } else { + None + } + } +} diff --git a/matrix_sdk_crypto/src/verification/sas/mod.rs b/matrix_sdk_crypto/src/verification/sas/mod.rs index 6ee7f2bb..025f0fa7 100644 --- a/matrix_sdk_crypto/src/verification/sas/mod.rs +++ b/matrix_sdk_crypto/src/verification/sas/mod.rs @@ -13,6 +13,7 @@ // limitations under the License. mod helpers; +mod inner_sas; mod sas_state; #[cfg(test)] @@ -25,8 +26,8 @@ use matrix_sdk_common::{ api::r0::keys::upload_signatures::Request as SignatureUploadRequest, events::{ key::verification::{ - accept::AcceptToDeviceEventContent, cancel::CancelCode, mac::MacToDeviceEventContent, - start::StartToDeviceEventContent, + cancel::CancelCode, + start::{StartEventContent, StartToDeviceEventContent}, }, AnyToDeviceEvent, AnyToDeviceEventContent, ToDeviceEvent, }, @@ -42,9 +43,7 @@ use crate::{ }; pub use helpers::content_to_request; -use sas_state::{ - Accepted, Canceled, Confirmed, Created, Done, KeyReceived, MacReceived, SasState, Started, -}; +use inner_sas::InnerSas; #[derive(Debug)] /// A result of a verification flow. @@ -537,238 +536,6 @@ impl Sas { } } -#[derive(Clone, Debug)] -enum InnerSas { - Created(SasState), - Started(SasState), - Accepted(SasState), - KeyRecieved(SasState), - Confirmed(SasState), - MacReceived(SasState), - Done(SasState), - Canceled(SasState), -} - -impl InnerSas { - fn start( - account: ReadOnlyAccount, - other_device: ReadOnlyDevice, - other_identity: Option, - ) -> (InnerSas, StartToDeviceEventContent) { - let sas = SasState::::new(account, other_device, other_identity); - let content = sas.as_content(); - (InnerSas::Created(sas), content) - } - - fn from_start_event( - account: ReadOnlyAccount, - other_device: ReadOnlyDevice, - event: &ToDeviceEvent, - other_identity: Option, - ) -> Result { - match SasState::::from_start_event(account, other_device, event, other_identity) { - Ok(s) => Ok(InnerSas::Started(s)), - Err(s) => Err(s.as_content()), - } - } - - fn accept(&self) -> Option { - if let InnerSas::Started(s) = self { - Some(s.as_content()) - } else { - None - } - } - - #[cfg(test)] - #[allow(dead_code)] - fn set_creation_time(&mut self, time: Instant) { - match self { - InnerSas::Created(s) => s.set_creation_time(time), - InnerSas::Started(s) => s.set_creation_time(time), - InnerSas::Canceled(s) => s.set_creation_time(time), - InnerSas::Accepted(s) => s.set_creation_time(time), - InnerSas::KeyRecieved(s) => s.set_creation_time(time), - InnerSas::Confirmed(s) => s.set_creation_time(time), - InnerSas::MacReceived(s) => s.set_creation_time(time), - InnerSas::Done(s) => s.set_creation_time(time), - } - } - - fn cancel(self, code: CancelCode) -> (InnerSas, Option) { - let sas = match self { - InnerSas::Created(s) => s.cancel(code), - InnerSas::Started(s) => s.cancel(code), - InnerSas::Accepted(s) => s.cancel(code), - InnerSas::KeyRecieved(s) => s.cancel(code), - InnerSas::MacReceived(s) => s.cancel(code), - _ => return (self, None), - }; - - let content = sas.as_content(); - - (InnerSas::Canceled(sas), Some(content)) - } - - fn confirm(self) -> (InnerSas, Option) { - match self { - InnerSas::KeyRecieved(s) => { - let sas = s.confirm(); - let content = sas.as_content(); - (InnerSas::Confirmed(sas), Some(content)) - } - InnerSas::MacReceived(s) => { - let sas = s.confirm(); - let content = sas.as_content(); - (InnerSas::Done(sas), Some(content)) - } - _ => (self, None), - } - } - - fn receive_event( - self, - event: &AnyToDeviceEvent, - ) -> (InnerSas, Option) { - match event { - AnyToDeviceEvent::KeyVerificationAccept(e) => { - if let InnerSas::Created(s) = self { - match s.into_accepted(e) { - Ok(s) => { - let content = s.as_content(); - ( - InnerSas::Accepted(s), - Some(AnyToDeviceEventContent::KeyVerificationKey(content)), - ) - } - Err(s) => { - let content = s.as_content(); - (InnerSas::Canceled(s), Some(content)) - } - } - } else { - (self, None) - } - } - AnyToDeviceEvent::KeyVerificationKey(e) => match self { - InnerSas::Accepted(s) => match s.into_key_received(e) { - Ok(s) => (InnerSas::KeyRecieved(s), None), - Err(s) => { - let content = s.as_content(); - (InnerSas::Canceled(s), Some(content)) - } - }, - InnerSas::Started(s) => match s.into_key_received(e) { - Ok(s) => { - let content = s.as_content(); - ( - InnerSas::KeyRecieved(s), - Some(AnyToDeviceEventContent::KeyVerificationKey(content)), - ) - } - Err(s) => { - let content = s.as_content(); - (InnerSas::Canceled(s), Some(content)) - } - }, - _ => (self, None), - }, - AnyToDeviceEvent::KeyVerificationMac(e) => match self { - InnerSas::KeyRecieved(s) => match s.into_mac_received(e) { - Ok(s) => (InnerSas::MacReceived(s), None), - Err(s) => { - let content = s.as_content(); - (InnerSas::Canceled(s), Some(content)) - } - }, - InnerSas::Confirmed(s) => match s.into_done(e) { - Ok(s) => (InnerSas::Done(s), None), - Err(s) => { - let content = s.as_content(); - (InnerSas::Canceled(s), Some(content)) - } - }, - _ => (self, None), - }, - _ => (self, None), - } - } - - fn can_be_presented(&self) -> bool { - match self { - InnerSas::KeyRecieved(_) => true, - InnerSas::MacReceived(_) => true, - _ => false, - } - } - - fn is_done(&self) -> bool { - matches!(self, InnerSas::Done(_)) - } - - fn is_canceled(&self) -> bool { - matches!(self, InnerSas::Canceled(_)) - } - - fn timed_out(&self) -> bool { - match self { - InnerSas::Created(s) => s.timed_out(), - InnerSas::Started(s) => s.timed_out(), - InnerSas::Canceled(s) => s.timed_out(), - InnerSas::Accepted(s) => s.timed_out(), - InnerSas::KeyRecieved(s) => s.timed_out(), - InnerSas::Confirmed(s) => s.timed_out(), - InnerSas::MacReceived(s) => s.timed_out(), - InnerSas::Done(s) => s.timed_out(), - } - } - - fn verification_flow_id(&self) -> Arc { - match self { - InnerSas::Created(s) => s.verification_flow_id.clone(), - InnerSas::Started(s) => s.verification_flow_id.clone(), - InnerSas::Canceled(s) => s.verification_flow_id.clone(), - InnerSas::Accepted(s) => s.verification_flow_id.clone(), - InnerSas::KeyRecieved(s) => s.verification_flow_id.clone(), - InnerSas::Confirmed(s) => s.verification_flow_id.clone(), - InnerSas::MacReceived(s) => s.verification_flow_id.clone(), - InnerSas::Done(s) => s.verification_flow_id.clone(), - } - } - - fn emoji(&self) -> Option> { - match self { - InnerSas::KeyRecieved(s) => Some(s.get_emoji()), - InnerSas::MacReceived(s) => Some(s.get_emoji()), - _ => None, - } - } - - fn decimals(&self) -> Option<(u16, u16, u16)> { - match self { - InnerSas::KeyRecieved(s) => Some(s.get_decimal()), - InnerSas::MacReceived(s) => Some(s.get_decimal()), - _ => None, - } - } - - fn verified_devices(&self) -> Option> { - if let InnerSas::Done(s) = self { - Some(s.verified_devices()) - } else { - None - } - } - - fn verified_identities(&self) -> Option> { - if let InnerSas::Done(s) = self { - Some(s.verified_identities()) - } else { - None - } - } -} - #[cfg(test)] mod test { use std::{convert::TryFrom, sync::Arc}; @@ -785,7 +552,10 @@ mod test { ReadOnlyAccount, ReadOnlyDevice, }; - use super::{Accepted, Created, Sas, SasState, Started}; + use super::{ + sas_state::{Accepted, Created, SasState, Started}, + Sas, + }; fn alice_id() -> UserId { UserId::try_from("@alice:example.org").unwrap()