crypto: Make the cancelations output only CancelContents.

This commit is contained in:
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,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;
}
}
_ => (),
}
}
}

View file

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

View file

@ -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(())

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.
#[derive(Debug)]
pub enum IncomingResponse<'a> {

View file

@ -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<Sas> {
#[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()),
},
);

View file

@ -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<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)]
pub enum OutgoingContent {
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 {
fn from(content: AnyToDeviceEventContent) -> Self {
OutgoingContent::ToDevice(content)

View file

@ -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<MacToDeviceEventContent>,
sender: &UserId,
content: &MacContent,
) -> Result<(Vec<ReadOnlyDevice>, Vec<UserIdentities>), 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::<Vec<String>>();
let mut keys = content.mac().keys().cloned().collect::<Vec<String>>();
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<String, String> = 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(),
}
}

View file

@ -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<StartContent>,
other_identity: Option<UserIdentities>,
) -> Result<InnerSas, OutgoingContent> {
) -> Result<InnerSas, CancelContent> {
match SasState::<Started>::from_start_event(
account,
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 {
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<MacToDeviceEventContent>) {
pub fn confirm(self) -> (InnerSas, Option<MacContent>) {
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<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>) {
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),

View file

@ -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<ToDeviceRequest>, Option<SignatureUploadRequest>), CryptoStoreError> {
) -> Result<
(
Option<OutgoingVerificationRequest>,
Option<SignatureUploadRequest>,
),
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<ToDeviceRequest> {
pub fn cancel(&self) -> Option<OutgoingVerificationRequest> {
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<ToDeviceRequest> {
pub(crate) fn cancel_if_timed_out(&self) -> Option<OutgoingVerificationRequest> {
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<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> {
let mut guard = self.inner.lock().unwrap();
let sas: InnerSas = (*guard).clone();

View file

@ -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<Started> {
/// anymore.
pub fn into_key_received(
self,
event: &ToDeviceEvent<KeyToDeviceEventContent>,
sender: &UserId,
content: impl Into<KeyContent>,
) -> 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))?;
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<Accepted> {
/// anymore.
pub fn into_key_received(
self,
event: &ToDeviceEvent<KeyToDeviceEventContent>,
sender: &UserId,
content: impl Into<KeyContent>,
) -> 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))?;
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<Accepted> {
/// 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<KeyReceived> {
///
/// 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<KeyReceived> {
/// the other side.
pub fn into_mac_received(
self,
event: &ToDeviceEvent<MacToDeviceEventContent>,
sender: &UserId,
content: impl Into<MacContent>,
) -> 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))?;
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<Confirmed> {
/// the other side.
pub fn into_done(
self,
event: &ToDeviceEvent<MacToDeviceEventContent>,
sender: &UserId,
content: impl Into<MacContent>,
) -> 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))?;
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<Confirmed> {
/// 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<Done> {
///
/// 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<Canceled> {
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(),
}
}
}