crypto: Add enums so we can handle in-room and to-device verifications the same
parent
b52f3fb11f
commit
1e48b15040
|
@ -32,7 +32,7 @@ use matrix_sdk_common::{
|
||||||
events::{
|
events::{
|
||||||
room::encrypted::{EncryptedEventContent, EncryptedEventScheme},
|
room::encrypted::{EncryptedEventContent, EncryptedEventScheme},
|
||||||
room_key::RoomKeyToDeviceEventContent,
|
room_key::RoomKeyToDeviceEventContent,
|
||||||
AnyMessageEventContent, AnyToDeviceEvent, SyncMessageEvent, ToDeviceEvent,
|
AnyMessageEventContent, AnyRoomEvent, AnyToDeviceEvent, SyncMessageEvent, ToDeviceEvent,
|
||||||
},
|
},
|
||||||
identifiers::{
|
identifiers::{
|
||||||
DeviceId, DeviceIdBox, DeviceKeyAlgorithm, EventEncryptionAlgorithm, RoomId, UserId,
|
DeviceId, DeviceIdBox, DeviceKeyAlgorithm, EventEncryptionAlgorithm, RoomId, UserId,
|
||||||
|
@ -703,7 +703,7 @@ impl OlmMachine {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_verification_event(&self, event: &AnyToDeviceEvent) {
|
async fn handle_verification_event(&self, event: &AnyToDeviceEvent) {
|
||||||
if let Err(e) = self.verification_machine.receive_event(&event).await {
|
if let Err(e) = self.verification_machine.receive_any_event(event).await {
|
||||||
error!("Error handling a verification event: {:?}", e);
|
error!("Error handling a verification event: {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -986,7 +986,11 @@ impl OlmMachine {
|
||||||
trace!("Successfully decrypted a Megolm event {:?}", decrypted_event);
|
trace!("Successfully decrypted a Megolm event {:?}", decrypted_event);
|
||||||
|
|
||||||
if let Ok(e) = decrypted_event.deserialize() {
|
if let Ok(e) = decrypted_event.deserialize() {
|
||||||
self.verification_machine.receive_room_event(room_id, &e).await?;
|
let event = e.into_full_event(room_id.to_owned());
|
||||||
|
|
||||||
|
if let AnyRoomEvent::Message(e) = event {
|
||||||
|
self.verification_machine.receive_any_event(&e).await?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let encryption_info =
|
let encryption_info =
|
||||||
|
|
|
@ -0,0 +1,711 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
collections::BTreeMap,
|
||||||
|
convert::{TryFrom, TryInto},
|
||||||
|
};
|
||||||
|
|
||||||
|
use matrix_sdk_common::{
|
||||||
|
events::{
|
||||||
|
key::verification::{
|
||||||
|
accept::{AcceptEventContent, AcceptMethod, AcceptToDeviceEventContent},
|
||||||
|
cancel::{CancelCode, CancelEventContent, CancelToDeviceEventContent},
|
||||||
|
done::{DoneEventContent, DoneToDeviceEventContent},
|
||||||
|
key::{KeyEventContent, KeyToDeviceEventContent},
|
||||||
|
mac::{MacEventContent, MacToDeviceEventContent},
|
||||||
|
ready::{ReadyEventContent, ReadyToDeviceEventContent},
|
||||||
|
request::RequestToDeviceEventContent,
|
||||||
|
start::{StartEventContent, StartMethod, StartToDeviceEventContent},
|
||||||
|
VerificationMethod,
|
||||||
|
},
|
||||||
|
room::message::{KeyVerificationRequestEventContent, MessageType},
|
||||||
|
AnyMessageEvent, AnyMessageEventContent, AnyToDeviceEvent, AnyToDeviceEventContent,
|
||||||
|
},
|
||||||
|
identifiers::{DeviceId, RoomId, UserId},
|
||||||
|
CanonicalJsonValue,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{sas::OutgoingContent, FlowId};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum AnyEvent<'a> {
|
||||||
|
Room(&'a AnyMessageEvent),
|
||||||
|
ToDevice(&'a AnyToDeviceEvent),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnyEvent<'_> {
|
||||||
|
pub fn sender(&self) -> &UserId {
|
||||||
|
match self {
|
||||||
|
Self::Room(e) => &e.sender(),
|
||||||
|
Self::ToDevice(e) => &e.sender(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verification_content(&self) -> Option<AnyVerificationContent> {
|
||||||
|
match self {
|
||||||
|
AnyEvent::Room(e) => match e {
|
||||||
|
AnyMessageEvent::CallAnswer(_)
|
||||||
|
| AnyMessageEvent::CallInvite(_)
|
||||||
|
| AnyMessageEvent::CallHangup(_)
|
||||||
|
| AnyMessageEvent::CallCandidates(_)
|
||||||
|
| AnyMessageEvent::Reaction(_)
|
||||||
|
| AnyMessageEvent::RoomEncrypted(_)
|
||||||
|
| AnyMessageEvent::RoomMessageFeedback(_)
|
||||||
|
| AnyMessageEvent::RoomRedaction(_)
|
||||||
|
| AnyMessageEvent::Sticker(_)
|
||||||
|
| AnyMessageEvent::Custom(_) => None,
|
||||||
|
AnyMessageEvent::RoomMessage(m) => {
|
||||||
|
if let MessageType::VerificationRequest(v) = &m.content.msgtype {
|
||||||
|
Some(RequestContent::from(v).into())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AnyMessageEvent::KeyVerificationReady(e) => {
|
||||||
|
Some(ReadyContent::from(&e.content).into())
|
||||||
|
}
|
||||||
|
AnyMessageEvent::KeyVerificationStart(e) => {
|
||||||
|
Some(StartContent::from(&e.content).into())
|
||||||
|
}
|
||||||
|
AnyMessageEvent::KeyVerificationCancel(e) => {
|
||||||
|
Some(CancelContent::from(&e.content).into())
|
||||||
|
}
|
||||||
|
AnyMessageEvent::KeyVerificationAccept(e) => {
|
||||||
|
Some(AcceptContent::from(&e.content).into())
|
||||||
|
}
|
||||||
|
AnyMessageEvent::KeyVerificationKey(e) => Some(KeyContent::from(&e.content).into()),
|
||||||
|
AnyMessageEvent::KeyVerificationMac(e) => Some(MacContent::from(&e.content).into()),
|
||||||
|
AnyMessageEvent::KeyVerificationDone(e) => {
|
||||||
|
Some(DoneContent::from(&e.content).into())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
AnyEvent::ToDevice(e) => match e {
|
||||||
|
AnyToDeviceEvent::Dummy(_)
|
||||||
|
| AnyToDeviceEvent::RoomKey(_)
|
||||||
|
| AnyToDeviceEvent::RoomKeyRequest(_)
|
||||||
|
| AnyToDeviceEvent::ForwardedRoomKey(_)
|
||||||
|
| AnyToDeviceEvent::RoomEncrypted(_)
|
||||||
|
| AnyToDeviceEvent::Custom(_) => None,
|
||||||
|
AnyToDeviceEvent::KeyVerificationRequest(e) => {
|
||||||
|
Some(RequestContent::from(&e.content).into())
|
||||||
|
}
|
||||||
|
AnyToDeviceEvent::KeyVerificationReady(e) => {
|
||||||
|
Some(ReadyContent::from(&e.content).into())
|
||||||
|
}
|
||||||
|
AnyToDeviceEvent::KeyVerificationStart(e) => {
|
||||||
|
Some(StartContent::from(&e.content).into())
|
||||||
|
}
|
||||||
|
AnyToDeviceEvent::KeyVerificationCancel(e) => {
|
||||||
|
Some(CancelContent::from(&e.content).into())
|
||||||
|
}
|
||||||
|
AnyToDeviceEvent::KeyVerificationAccept(e) => {
|
||||||
|
Some(AcceptContent::from(&e.content).into())
|
||||||
|
}
|
||||||
|
AnyToDeviceEvent::KeyVerificationKey(e) => {
|
||||||
|
Some(KeyContent::from(&e.content).into())
|
||||||
|
}
|
||||||
|
AnyToDeviceEvent::KeyVerificationMac(e) => {
|
||||||
|
Some(MacContent::from(&e.content).into())
|
||||||
|
}
|
||||||
|
AnyToDeviceEvent::KeyVerificationDone(e) => {
|
||||||
|
Some(DoneContent::from(&e.content).into())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a AnyMessageEvent> for AnyEvent<'a> {
|
||||||
|
fn from(e: &'a AnyMessageEvent) -> Self {
|
||||||
|
Self::Room(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a AnyToDeviceEvent> for AnyEvent<'a> {
|
||||||
|
fn from(e: &'a AnyToDeviceEvent) -> Self {
|
||||||
|
Self::ToDevice(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&AnyEvent<'_>> for FlowId {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: &AnyEvent<'_>) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
AnyEvent::Room(e) => FlowId::try_from(*e),
|
||||||
|
AnyEvent::ToDevice(e) => FlowId::try_from(*e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&AnyMessageEvent> for FlowId {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: &AnyMessageEvent) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
AnyMessageEvent::CallAnswer(_)
|
||||||
|
| AnyMessageEvent::CallInvite(_)
|
||||||
|
| AnyMessageEvent::CallHangup(_)
|
||||||
|
| AnyMessageEvent::CallCandidates(_)
|
||||||
|
| AnyMessageEvent::Reaction(_)
|
||||||
|
| AnyMessageEvent::RoomEncrypted(_)
|
||||||
|
| AnyMessageEvent::RoomMessageFeedback(_)
|
||||||
|
| AnyMessageEvent::RoomRedaction(_)
|
||||||
|
| AnyMessageEvent::Sticker(_)
|
||||||
|
| AnyMessageEvent::Custom(_) => Err(()),
|
||||||
|
AnyMessageEvent::KeyVerificationReady(e) => {
|
||||||
|
Ok(FlowId::from((&e.room_id, &e.content.relation.event_id)))
|
||||||
|
}
|
||||||
|
AnyMessageEvent::RoomMessage(e) => Ok(FlowId::from((&e.room_id, &e.event_id))),
|
||||||
|
AnyMessageEvent::KeyVerificationStart(e) => {
|
||||||
|
Ok(FlowId::from((&e.room_id, &e.content.relation.event_id)))
|
||||||
|
}
|
||||||
|
AnyMessageEvent::KeyVerificationCancel(e) => {
|
||||||
|
Ok(FlowId::from((&e.room_id, &e.content.relation.event_id)))
|
||||||
|
}
|
||||||
|
AnyMessageEvent::KeyVerificationAccept(e) => {
|
||||||
|
Ok(FlowId::from((&e.room_id, &e.content.relation.event_id)))
|
||||||
|
}
|
||||||
|
AnyMessageEvent::KeyVerificationKey(e) => {
|
||||||
|
Ok(FlowId::from((&e.room_id, &e.content.relation.event_id)))
|
||||||
|
}
|
||||||
|
AnyMessageEvent::KeyVerificationMac(e) => {
|
||||||
|
Ok(FlowId::from((&e.room_id, &e.content.relation.event_id)))
|
||||||
|
}
|
||||||
|
AnyMessageEvent::KeyVerificationDone(e) => {
|
||||||
|
Ok(FlowId::from((&e.room_id, &e.content.relation.event_id)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&AnyToDeviceEvent> for FlowId {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: &AnyToDeviceEvent) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
AnyToDeviceEvent::Dummy(_)
|
||||||
|
| AnyToDeviceEvent::RoomKey(_)
|
||||||
|
| AnyToDeviceEvent::RoomKeyRequest(_)
|
||||||
|
| AnyToDeviceEvent::ForwardedRoomKey(_)
|
||||||
|
| AnyToDeviceEvent::RoomEncrypted(_)
|
||||||
|
| AnyToDeviceEvent::Custom(_) => Err(()),
|
||||||
|
AnyToDeviceEvent::KeyVerificationRequest(e) => {
|
||||||
|
Ok(FlowId::from(e.content.transaction_id.to_owned()))
|
||||||
|
}
|
||||||
|
AnyToDeviceEvent::KeyVerificationReady(e) => {
|
||||||
|
Ok(FlowId::from(e.content.transaction_id.to_owned()))
|
||||||
|
}
|
||||||
|
AnyToDeviceEvent::KeyVerificationStart(e) => {
|
||||||
|
Ok(FlowId::from(e.content.transaction_id.to_owned()))
|
||||||
|
}
|
||||||
|
AnyToDeviceEvent::KeyVerificationCancel(e) => {
|
||||||
|
Ok(FlowId::from(e.content.transaction_id.to_owned()))
|
||||||
|
}
|
||||||
|
AnyToDeviceEvent::KeyVerificationAccept(e) => {
|
||||||
|
Ok(FlowId::from(e.content.transaction_id.to_owned()))
|
||||||
|
}
|
||||||
|
AnyToDeviceEvent::KeyVerificationKey(e) => {
|
||||||
|
Ok(FlowId::from(e.content.transaction_id.to_owned()))
|
||||||
|
}
|
||||||
|
AnyToDeviceEvent::KeyVerificationMac(e) => {
|
||||||
|
Ok(FlowId::from(e.content.transaction_id.to_owned()))
|
||||||
|
}
|
||||||
|
AnyToDeviceEvent::KeyVerificationDone(e) => {
|
||||||
|
Ok(FlowId::from(e.content.transaction_id.to_owned()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum AnyVerificationContent<'a> {
|
||||||
|
Request(RequestContent<'a>),
|
||||||
|
Ready(ReadyContent<'a>),
|
||||||
|
Cancel(CancelContent<'a>),
|
||||||
|
Start(StartContent<'a>),
|
||||||
|
Done(DoneContent<'a>),
|
||||||
|
Accept(AcceptContent<'a>),
|
||||||
|
Key(KeyContent<'a>),
|
||||||
|
Mac(MacContent<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<ReadyContent<'a>> for AnyVerificationContent<'a> {
|
||||||
|
fn from(c: ReadyContent<'a>) -> Self {
|
||||||
|
Self::Ready(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<RequestContent<'a>> for AnyVerificationContent<'a> {
|
||||||
|
fn from(c: RequestContent<'a>) -> Self {
|
||||||
|
Self::Request(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<StartContent<'a>> for AnyVerificationContent<'a> {
|
||||||
|
fn from(c: StartContent<'a>) -> Self {
|
||||||
|
Self::Start(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<DoneContent<'a>> for AnyVerificationContent<'a> {
|
||||||
|
fn from(c: DoneContent<'a>) -> Self {
|
||||||
|
Self::Done(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<CancelContent<'a>> for AnyVerificationContent<'a> {
|
||||||
|
fn from(c: CancelContent<'a>) -> Self {
|
||||||
|
Self::Cancel(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<AcceptContent<'a>> for AnyVerificationContent<'a> {
|
||||||
|
fn from(c: AcceptContent<'a>) -> Self {
|
||||||
|
Self::Accept(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<KeyContent<'a>> for AnyVerificationContent<'a> {
|
||||||
|
fn from(c: KeyContent<'a>) -> Self {
|
||||||
|
Self::Key(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<MacContent<'a>> for AnyVerificationContent<'a> {
|
||||||
|
fn from(c: MacContent<'a>) -> Self {
|
||||||
|
Self::Mac(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum RequestContent<'a> {
|
||||||
|
ToDevice(&'a RequestToDeviceEventContent),
|
||||||
|
Room(&'a KeyVerificationRequestEventContent),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RequestContent<'_> {
|
||||||
|
pub fn from_device(&self) -> &DeviceId {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(t) => &t.from_device,
|
||||||
|
Self::Room(r) => &r.from_device,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn methods(&self) -> &[VerificationMethod] {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(t) => &t.methods,
|
||||||
|
Self::Room(r) => &r.methods,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a KeyVerificationRequestEventContent> for RequestContent<'a> {
|
||||||
|
fn from(c: &'a KeyVerificationRequestEventContent) -> Self {
|
||||||
|
Self::Room(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a RequestToDeviceEventContent> for RequestContent<'a> {
|
||||||
|
fn from(c: &'a RequestToDeviceEventContent) -> Self {
|
||||||
|
Self::ToDevice(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ReadyContent<'a> {
|
||||||
|
ToDevice(&'a ReadyToDeviceEventContent),
|
||||||
|
Room(&'a ReadyEventContent),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReadyContent<'_> {
|
||||||
|
pub fn from_device(&self) -> &DeviceId {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(t) => &t.from_device,
|
||||||
|
Self::Room(r) => &r.from_device,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn methods(&self) -> &[VerificationMethod] {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(t) => &t.methods,
|
||||||
|
Self::Room(r) => &r.methods,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a ReadyEventContent> for ReadyContent<'a> {
|
||||||
|
fn from(c: &'a ReadyEventContent) -> Self {
|
||||||
|
Self::Room(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a ReadyToDeviceEventContent> for ReadyContent<'a> {
|
||||||
|
fn from(c: &'a ReadyToDeviceEventContent) -> Self {
|
||||||
|
Self::ToDevice(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! try_from_outgoing_content {
|
||||||
|
($type: ident, $enum_variant: ident) => {
|
||||||
|
impl<'a> TryFrom<&'a OutgoingContent> for $type<'a> {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: &'a OutgoingContent) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
OutgoingContent::Room(_, c) => {
|
||||||
|
if let AnyMessageEventContent::$enum_variant(c) = c {
|
||||||
|
Ok(Self::Room(c))
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutgoingContent::ToDevice(c) => {
|
||||||
|
if let AnyToDeviceEventContent::$enum_variant(c) = c {
|
||||||
|
Ok(Self::ToDevice(c))
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try_from_outgoing_content!(ReadyContent, KeyVerificationReady);
|
||||||
|
try_from_outgoing_content!(StartContent, KeyVerificationStart);
|
||||||
|
try_from_outgoing_content!(AcceptContent, KeyVerificationAccept);
|
||||||
|
try_from_outgoing_content!(KeyContent, KeyVerificationKey);
|
||||||
|
try_from_outgoing_content!(MacContent, KeyVerificationMac);
|
||||||
|
try_from_outgoing_content!(CancelContent, KeyVerificationCancel);
|
||||||
|
try_from_outgoing_content!(DoneContent, KeyVerificationDone);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum StartContent<'a> {
|
||||||
|
ToDevice(&'a StartToDeviceEventContent),
|
||||||
|
Room(&'a StartEventContent),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> StartContent<'a> {
|
||||||
|
pub fn from_device(&self) -> &DeviceId {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(c) => &c.from_device,
|
||||||
|
Self::Room(c) => &c.from_device,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flow_id(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(c) => &c.transaction_id,
|
||||||
|
Self::Room(c) => &c.relation.event_id.as_str(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn method(&self) -> &StartMethod {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(c) => &c.method,
|
||||||
|
Self::Room(c) => &c.method,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn canonical_json(&self) -> CanonicalJsonValue {
|
||||||
|
let content = match self {
|
||||||
|
Self::ToDevice(c) => serde_json::to_value(c),
|
||||||
|
Self::Room(c) => serde_json::to_value(c),
|
||||||
|
};
|
||||||
|
|
||||||
|
content.expect("Can't serialize content").try_into().expect("Can't canonicalize content")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a StartEventContent> for StartContent<'a> {
|
||||||
|
fn from(c: &'a StartEventContent) -> Self {
|
||||||
|
Self::Room(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a StartToDeviceEventContent> for StartContent<'a> {
|
||||||
|
fn from(c: &'a StartToDeviceEventContent) -> Self {
|
||||||
|
Self::ToDevice(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a OwnedStartContent> for StartContent<'a> {
|
||||||
|
fn from(c: &'a OwnedStartContent) -> Self {
|
||||||
|
match c {
|
||||||
|
OwnedStartContent::ToDevice(c) => Self::ToDevice(c),
|
||||||
|
OwnedStartContent::Room(_, c) => Self::Room(c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum DoneContent<'a> {
|
||||||
|
ToDevice(&'a DoneToDeviceEventContent),
|
||||||
|
Room(&'a DoneEventContent),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a DoneEventContent> for DoneContent<'a> {
|
||||||
|
fn from(c: &'a DoneEventContent) -> Self {
|
||||||
|
Self::Room(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a DoneToDeviceEventContent> for DoneContent<'a> {
|
||||||
|
fn from(c: &'a DoneToDeviceEventContent) -> Self {
|
||||||
|
Self::ToDevice(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DoneContent<'a> {
|
||||||
|
pub fn flow_id(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(c) => &c.transaction_id,
|
||||||
|
Self::Room(c) => &c.relation.event_id.as_str(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum AcceptContent<'a> {
|
||||||
|
ToDevice(&'a AcceptToDeviceEventContent),
|
||||||
|
Room(&'a AcceptEventContent),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AcceptContent<'_> {
|
||||||
|
pub fn flow_id(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(c) => &c.transaction_id,
|
||||||
|
Self::Room(c) => c.relation.event_id.as_str(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn method(&self) -> &AcceptMethod {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(c) => &c.method,
|
||||||
|
Self::Room(c) => &c.method,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a AcceptToDeviceEventContent> for AcceptContent<'a> {
|
||||||
|
fn from(content: &'a AcceptToDeviceEventContent) -> Self {
|
||||||
|
Self::ToDevice(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a AcceptEventContent> for AcceptContent<'a> {
|
||||||
|
fn from(content: &'a AcceptEventContent) -> Self {
|
||||||
|
Self::Room(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a OwnedAcceptContent> for AcceptContent<'a> {
|
||||||
|
fn from(content: &'a OwnedAcceptContent) -> Self {
|
||||||
|
match content {
|
||||||
|
OwnedAcceptContent::ToDevice(c) => Self::ToDevice(c),
|
||||||
|
OwnedAcceptContent::Room(_, c) => Self::Room(c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum KeyContent<'a> {
|
||||||
|
ToDevice(&'a KeyToDeviceEventContent),
|
||||||
|
Room(&'a KeyEventContent),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyContent<'_> {
|
||||||
|
pub fn flow_id(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(c) => &c.transaction_id,
|
||||||
|
Self::Room(c) => c.relation.event_id.as_str(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn public_key(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(c) => &c.key,
|
||||||
|
Self::Room(c) => &c.key,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a KeyToDeviceEventContent> for KeyContent<'a> {
|
||||||
|
fn from(content: &'a KeyToDeviceEventContent) -> Self {
|
||||||
|
Self::ToDevice(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a KeyEventContent> for KeyContent<'a> {
|
||||||
|
fn from(content: &'a KeyEventContent) -> Self {
|
||||||
|
Self::Room(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum MacContent<'a> {
|
||||||
|
ToDevice(&'a MacToDeviceEventContent),
|
||||||
|
Room(&'a MacEventContent),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MacContent<'_> {
|
||||||
|
pub fn flow_id(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(c) => &c.transaction_id,
|
||||||
|
Self::Room(c) => c.relation.event_id.as_str(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mac(&self) -> &BTreeMap<String, String> {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(c) => &c.mac,
|
||||||
|
Self::Room(c) => &c.mac,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keys(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(c) => &c.keys,
|
||||||
|
Self::Room(c) => &c.keys,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a MacToDeviceEventContent> for MacContent<'a> {
|
||||||
|
fn from(content: &'a MacToDeviceEventContent) -> Self {
|
||||||
|
Self::ToDevice(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a MacEventContent> for MacContent<'a> {
|
||||||
|
fn from(content: &'a MacEventContent) -> Self {
|
||||||
|
Self::Room(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum CancelContent<'a> {
|
||||||
|
ToDevice(&'a CancelToDeviceEventContent),
|
||||||
|
Room(&'a CancelEventContent),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CancelContent<'_> {
|
||||||
|
pub fn cancel_code(&self) -> &CancelCode {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(c) => &c.code,
|
||||||
|
Self::Room(c) => &c.code,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a CancelEventContent> for CancelContent<'a> {
|
||||||
|
fn from(content: &'a CancelEventContent) -> Self {
|
||||||
|
Self::Room(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a CancelToDeviceEventContent> for CancelContent<'a> {
|
||||||
|
fn from(content: &'a CancelToDeviceEventContent) -> Self {
|
||||||
|
Self::ToDevice(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum OwnedStartContent {
|
||||||
|
ToDevice(StartToDeviceEventContent),
|
||||||
|
Room(RoomId, StartEventContent),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OwnedStartContent {
|
||||||
|
pub fn method(&self) -> &StartMethod {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(c) => &c.method,
|
||||||
|
Self::Room(_, c) => &c.method,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn method_mut(&mut self) -> &mut StartMethod {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(c) => &mut c.method,
|
||||||
|
Self::Room(_, c) => &mut c.method,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_start_content(&self) -> StartContent<'_> {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(c) => StartContent::ToDevice(c),
|
||||||
|
Self::Room(_, c) => StartContent::Room(c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flow_id(&self) -> FlowId {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(c) => FlowId::ToDevice(c.transaction_id.clone()),
|
||||||
|
Self::Room(r, c) => FlowId::InRoom(r.clone(), c.relation.event_id.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn canonical_json(self) -> CanonicalJsonValue {
|
||||||
|
let content = match self {
|
||||||
|
Self::ToDevice(c) => serde_json::to_value(c),
|
||||||
|
Self::Room(_, c) => serde_json::to_value(c),
|
||||||
|
};
|
||||||
|
|
||||||
|
content.expect("Can't serialize content").try_into().expect("Can't canonicalize content")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(RoomId, StartEventContent)> for OwnedStartContent {
|
||||||
|
fn from(tuple: (RoomId, StartEventContent)) -> Self {
|
||||||
|
Self::Room(tuple.0, tuple.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<StartToDeviceEventContent> for OwnedStartContent {
|
||||||
|
fn from(content: StartToDeviceEventContent) -> Self {
|
||||||
|
Self::ToDevice(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum OwnedAcceptContent {
|
||||||
|
ToDevice(AcceptToDeviceEventContent),
|
||||||
|
Room(RoomId, AcceptEventContent),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<AcceptToDeviceEventContent> for OwnedAcceptContent {
|
||||||
|
fn from(content: AcceptToDeviceEventContent) -> Self {
|
||||||
|
Self::ToDevice(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(RoomId, AcceptEventContent)> for OwnedAcceptContent {
|
||||||
|
fn from(content: (RoomId, AcceptEventContent)) -> Self {
|
||||||
|
Self::Room(content.0, content.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OwnedAcceptContent {
|
||||||
|
pub fn method_mut(&mut self) -> &mut AcceptMethod {
|
||||||
|
match self {
|
||||||
|
Self::ToDevice(c) => &mut c.method,
|
||||||
|
Self::Room(_, c) => &mut c.method,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,20 +16,17 @@ use std::{convert::TryFrom, sync::Arc};
|
||||||
|
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
events::{
|
identifiers::{DeviceId, EventId, UserId},
|
||||||
room::message::MessageType, AnyMessageEvent, AnySyncMessageEvent, AnySyncRoomEvent,
|
|
||||||
AnyToDeviceEvent,
|
|
||||||
},
|
|
||||||
identifiers::{DeviceId, EventId, RoomId, UserId},
|
|
||||||
locks::Mutex,
|
locks::Mutex,
|
||||||
uuid::Uuid,
|
uuid::Uuid,
|
||||||
};
|
};
|
||||||
use tracing::{info, trace, warn};
|
use tracing::info;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
event_enums::{AnyEvent, AnyVerificationContent},
|
||||||
requests::VerificationRequest,
|
requests::VerificationRequest,
|
||||||
sas::{content_to_request, OutgoingContent, Sas},
|
sas::{content_to_request, OutgoingContent, Sas},
|
||||||
VerificationResult,
|
FlowId, VerificationResult,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
olm::PrivateCrossSigningIdentity,
|
olm::PrivateCrossSigningIdentity,
|
||||||
|
@ -59,10 +56,6 @@ impl VerificationCache {
|
||||||
self.room_sas_verifications.is_empty() && self.sas_verification.is_empty()
|
self.room_sas_verifications.is_empty() && self.sas_verification.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_room_sas(&self, event_id: &EventId) -> Option<Sas> {
|
|
||||||
self.room_sas_verifications.get(event_id).map(|s| s.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_sas(&self, sas: Sas) {
|
pub fn insert_sas(&self, sas: Sas) {
|
||||||
match sas.flow_id() {
|
match sas.flow_id() {
|
||||||
super::FlowId::ToDevice(t) => self.sas_verification.insert(t.to_owned(), sas),
|
super::FlowId::ToDevice(t) => self.sas_verification.insert(t.to_owned(), sas),
|
||||||
|
@ -194,7 +187,7 @@ impl VerificationMachine {
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
let request = match content.into() {
|
let request = match content {
|
||||||
OutgoingContent::Room(r, c) => {
|
OutgoingContent::Room(r, c) => {
|
||||||
RoomMessageRequest { room_id: r, txn_id: Uuid::new_v4(), content: c }.into()
|
RoomMessageRequest { room_id: r, txn_id: Uuid::new_v4(), content: c }.into()
|
||||||
}
|
}
|
||||||
|
@ -230,18 +223,6 @@ impl VerificationMachine {
|
||||||
self.verifications.queue_up_content(recipient, recipient_device, content)
|
self.verifications.queue_up_content(recipient, recipient_device, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mark_request_as_sent(&self, uuid: &Uuid) {
|
pub fn mark_request_as_sent(&self, uuid: &Uuid) {
|
||||||
self.verifications.mark_request_as_sent(uuid);
|
self.verifications.mark_request_as_sent(uuid);
|
||||||
}
|
}
|
||||||
|
@ -256,220 +237,155 @@ impl VerificationMachine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn receive_room_event(
|
async fn mark_sas_as_done(
|
||||||
&self,
|
&self,
|
||||||
room_id: &RoomId,
|
sas: Sas,
|
||||||
event: &AnySyncRoomEvent,
|
out_content: Option<OutgoingContent>,
|
||||||
) -> Result<(), CryptoStoreError> {
|
) -> Result<(), CryptoStoreError> {
|
||||||
if let AnySyncRoomEvent::Message(m) = event {
|
match sas.mark_as_done().await? {
|
||||||
// Since these are room events we will get events that we send out on
|
VerificationResult::Ok => {
|
||||||
// our own as well.
|
if let Some(c) = out_content {
|
||||||
if m.sender() == self.account.user_id() {
|
self.queue_up_content(sas.other_user_id(), sas.other_device_id(), c);
|
||||||
if let AnySyncMessageEvent::KeyVerificationReady(_e) = m {
|
|
||||||
// TODO if there is a verification request, go into passive
|
|
||||||
// mode since another device is handling this request.
|
|
||||||
}
|
}
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
|
VerificationResult::Cancel(c) => {
|
||||||
match m {
|
if let Some(r) = sas.cancel_with_code(c) {
|
||||||
AnySyncMessageEvent::RoomMessage(m) => {
|
self.verifications.add_request(r.into());
|
||||||
if let MessageType::VerificationRequest(r) = &m.content.msgtype {
|
|
||||||
if self.account.user_id() == &r.to {
|
|
||||||
info!(
|
|
||||||
"Received a new verification request from {} {}",
|
|
||||||
m.sender, r.from_device
|
|
||||||
);
|
|
||||||
|
|
||||||
let request = VerificationRequest::from_room_request(
|
|
||||||
self.verifications.clone(),
|
|
||||||
self.account.clone(),
|
|
||||||
self.private_identity.lock().await.clone(),
|
|
||||||
self.store.clone(),
|
|
||||||
&m.sender,
|
|
||||||
&m.event_id,
|
|
||||||
room_id,
|
|
||||||
r,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.requests.insert(request.flow_id().as_str().to_owned(), request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AnySyncMessageEvent::KeyVerificationReady(e) => {
|
|
||||||
if let Some(request) = self.requests.get(e.content.relation.event_id.as_str()) {
|
|
||||||
if &e.sender == request.other_user() {
|
|
||||||
// TODO remove this unwrap.
|
|
||||||
request.receive_ready(&e.sender, &e.content).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AnySyncMessageEvent::KeyVerificationStart(e) => {
|
|
||||||
if let Some(request) = self.requests.get(e.content.relation.event_id.as_str()) {
|
|
||||||
request.receive_start(&e.sender, &e.content).await?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AnySyncMessageEvent::KeyVerificationKey(e) => {
|
|
||||||
if let Some(s) = self.verifications.get_room_sas(&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.verifications.get_room_sas(&e.content.relation.event_id) {
|
|
||||||
self.receive_room_event_helper(
|
|
||||||
&s,
|
|
||||||
&m.clone().into_full_event(room_id.clone()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
VerificationResult::SignatureUpload(r) => {
|
||||||
|
self.verifications.add_request(r.into());
|
||||||
|
|
||||||
AnySyncMessageEvent::KeyVerificationDone(e) => {
|
if let Some(c) = out_content {
|
||||||
if let Some(s) = self.verifications.get_room_sas(&e.content.relation.event_id) {
|
self.queue_up_content(sas.other_user_id(), sas.other_device_id(), c);
|
||||||
let content =
|
|
||||||
s.receive_room_event(&m.clone().into_full_event(room_id.clone()));
|
|
||||||
|
|
||||||
if s.is_done() {
|
|
||||||
match s.mark_as_done().await? {
|
|
||||||
VerificationResult::Ok => {
|
|
||||||
if let Some(c) = content {
|
|
||||||
self.queue_up_content(
|
|
||||||
s.other_user_id(),
|
|
||||||
s.other_device_id(),
|
|
||||||
c,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
VerificationResult::Cancel(c) => {
|
|
||||||
if let Some(r) = s.cancel_with_code(c) {
|
|
||||||
self.verifications.add_request(r.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
VerificationResult::SignatureUpload(r) => {
|
|
||||||
self.verifications.add_request(r.into());
|
|
||||||
|
|
||||||
if let Some(c) = content {
|
|
||||||
self.queue_up_content(
|
|
||||||
s.other_user_id(),
|
|
||||||
s.other_device_id(),
|
|
||||||
c,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn receive_event(&self, event: &AnyToDeviceEvent) -> Result<(), CryptoStoreError> {
|
pub async fn receive_any_event(
|
||||||
trace!("Received a key verification event {:?}", event);
|
&self,
|
||||||
|
event: impl Into<AnyEvent<'_>>,
|
||||||
|
) -> Result<(), CryptoStoreError> {
|
||||||
|
let event = event.into();
|
||||||
|
|
||||||
match event {
|
let flow_id = if let Ok(flow_id) = FlowId::try_from(&event) {
|
||||||
AnyToDeviceEvent::KeyVerificationRequest(e) => {
|
flow_id
|
||||||
let request = VerificationRequest::from_request(
|
} else {
|
||||||
self.verifications.clone(),
|
// This isn't a verification event, return early.
|
||||||
self.account.clone(),
|
return Ok(());
|
||||||
self.private_identity.lock().await.clone(),
|
};
|
||||||
self.store.clone(),
|
|
||||||
&e.sender,
|
|
||||||
&e.content,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.requests.insert(request.flow_id().as_str().to_string(), request);
|
if let Some(content) = event.verification_content() {
|
||||||
}
|
match &content {
|
||||||
AnyToDeviceEvent::KeyVerificationReady(e) => {
|
AnyVerificationContent::Request(r) => {
|
||||||
if let Some(request) = self.requests.get(&e.content.transaction_id) {
|
info!(
|
||||||
if &e.sender == request.other_user() {
|
sender = event.sender().as_str(),
|
||||||
// TODO remove this unwrap.
|
from_device = r.from_device().as_str(),
|
||||||
request.receive_ready(&e.sender, &e.content).unwrap();
|
"Received a new verification request",
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AnyToDeviceEvent::KeyVerificationStart(e) => {
|
|
||||||
trace!(
|
|
||||||
"Received a m.key.verification start event from {} {}",
|
|
||||||
e.sender,
|
|
||||||
e.content.from_device
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(verification) = self.get_request(&e.content.transaction_id) {
|
|
||||||
verification.receive_start(&e.sender, &e.content).await?;
|
|
||||||
} else if let Some(d) =
|
|
||||||
self.store.get_device(&e.sender, &e.content.from_device).await?
|
|
||||||
{
|
|
||||||
// TODO remove this soon, this has been deprecated by
|
|
||||||
// MSC3122 https://github.com/matrix-org/matrix-doc/pull/3122
|
|
||||||
let private_identity = self.private_identity.lock().await.clone();
|
|
||||||
match Sas::from_start_event(
|
|
||||||
e.content.clone(),
|
|
||||||
self.store.clone(),
|
|
||||||
self.account.clone(),
|
|
||||||
private_identity,
|
|
||||||
d,
|
|
||||||
self.store.get_user_identity(&e.sender).await?,
|
|
||||||
) {
|
|
||||||
Ok(s) => {
|
|
||||||
self.verifications
|
|
||||||
.sas_verification
|
|
||||||
.insert(e.content.transaction_id.clone(), s);
|
|
||||||
}
|
|
||||||
Err(c) => {
|
|
||||||
warn!(
|
|
||||||
"Can't start key verification with {} {}, canceling: {:?}",
|
|
||||||
e.sender, e.content.from_device, c
|
|
||||||
);
|
|
||||||
self.queue_up_content(&e.sender, &e.content.from_device, c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
warn!(
|
|
||||||
"Received a key verification start event from an unknown device {} {}",
|
|
||||||
e.sender, e.content.from_device
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
AnyToDeviceEvent::KeyVerificationCancel(e) => {
|
|
||||||
self.verifications.sas_verification.remove(&e.content.transaction_id);
|
|
||||||
}
|
|
||||||
AnyToDeviceEvent::KeyVerificationAccept(e) => {
|
|
||||||
if let Some(s) = self.get_sas(&e.content.transaction_id) {
|
|
||||||
self.receive_event_helper(&s, event)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
AnyToDeviceEvent::KeyVerificationKey(e) => {
|
|
||||||
if let Some(s) = self.get_sas(&e.content.transaction_id) {
|
|
||||||
self.receive_event_helper(&s, event)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
AnyToDeviceEvent::KeyVerificationMac(e) => {
|
|
||||||
if let Some(s) = self.get_sas(&e.content.transaction_id) {
|
|
||||||
self.receive_event_helper(&s, event);
|
|
||||||
|
|
||||||
if s.is_done() {
|
let request = VerificationRequest::from_request(
|
||||||
match s.mark_as_done().await? {
|
self.verifications.clone(),
|
||||||
VerificationResult::Ok => (),
|
self.account.clone(),
|
||||||
VerificationResult::Cancel(c) => {
|
self.private_identity.lock().await.clone(),
|
||||||
if let Some(r) = s.cancel_with_code(c) {
|
self.store.clone(),
|
||||||
self.verifications.add_request(r.into());
|
event.sender(),
|
||||||
|
flow_id,
|
||||||
|
r,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.requests.insert(request.flow_id().as_str().to_owned(), request);
|
||||||
|
}
|
||||||
|
AnyVerificationContent::Cancel(_) => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
AnyVerificationContent::Ready(c) => {
|
||||||
|
if let Some(request) = self.requests.get(flow_id.as_str()) {
|
||||||
|
if request.flow_id() == &flow_id {
|
||||||
|
// TODO remove this unwrap.
|
||||||
|
request.receive_ready(event.sender(), c).unwrap();
|
||||||
|
} else {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AnyVerificationContent::Start(c) => {
|
||||||
|
if let Some(request) = self.requests.get(flow_id.as_str()) {
|
||||||
|
request.receive_start(event.sender(), &c).await?
|
||||||
|
} else if let FlowId::ToDevice(_) = flow_id {
|
||||||
|
// TODO remove this soon, this has been deprecated by
|
||||||
|
// MSC3122 https://github.com/matrix-org/matrix-doc/pull/3122
|
||||||
|
if let Some(device) =
|
||||||
|
self.store.get_device(event.sender(), c.from_device()).await?
|
||||||
|
{
|
||||||
|
let private_identity = self.private_identity.lock().await.clone();
|
||||||
|
let identity = self.store.get_user_identity(event.sender()).await?;
|
||||||
|
|
||||||
|
match Sas::from_start_event(
|
||||||
|
flow_id,
|
||||||
|
c,
|
||||||
|
self.store.clone(),
|
||||||
|
self.account.clone(),
|
||||||
|
private_identity,
|
||||||
|
device,
|
||||||
|
identity,
|
||||||
|
false,
|
||||||
|
) {
|
||||||
|
Ok(sas) => {
|
||||||
|
self.verifications.insert_sas(sas);
|
||||||
}
|
}
|
||||||
}
|
Err(cancellation) => self.queue_up_content(
|
||||||
VerificationResult::SignatureUpload(r) => {
|
event.sender(),
|
||||||
self.verifications.add_request(r.into());
|
c.from_device(),
|
||||||
|
cancellation,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
AnyVerificationContent::Accept(_) | AnyVerificationContent::Key(_) => {
|
||||||
|
if let Some(sas) = self.verifications.get_sas(flow_id.as_str()) {
|
||||||
|
if sas.flow_id() == &flow_id {
|
||||||
|
if let Some(content) = sas.receive_any_event(event.sender(), &content) {
|
||||||
|
self.queue_up_content(
|
||||||
|
sas.other_user_id(),
|
||||||
|
sas.other_device_id(),
|
||||||
|
content,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AnyVerificationContent::Mac(_) => {
|
||||||
|
if let Some(s) = self.verifications.get_sas(flow_id.as_str()) {
|
||||||
|
if s.flow_id() == &flow_id {
|
||||||
|
let content = s.receive_any_event(event.sender(), &content);
|
||||||
|
|
||||||
|
if s.is_done() {
|
||||||
|
self.mark_sas_as_done(s, content).await?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AnyVerificationContent::Done(_) => {
|
||||||
|
if let Some(s) = self.verifications.get_sas(flow_id.as_str()) {
|
||||||
|
let content = s.receive_any_event(event.sender(), &content);
|
||||||
|
|
||||||
|
if s.is_done() {
|
||||||
|
self.mark_sas_as_done(s, content).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -491,9 +407,12 @@ mod test {
|
||||||
use super::{Sas, VerificationMachine};
|
use super::{Sas, VerificationMachine};
|
||||||
use crate::{
|
use crate::{
|
||||||
olm::PrivateCrossSigningIdentity,
|
olm::PrivateCrossSigningIdentity,
|
||||||
requests::OutgoingRequests,
|
|
||||||
store::{CryptoStore, MemoryStore},
|
store::{CryptoStore, MemoryStore},
|
||||||
verification::test::{get_content_from_request, wrap_any_to_device_content},
|
verification::{
|
||||||
|
event_enums::{AcceptContent, KeyContent, MacContent},
|
||||||
|
sas::OutgoingContent,
|
||||||
|
test::wrap_any_to_device_content,
|
||||||
|
},
|
||||||
ReadOnlyAccount, ReadOnlyDevice,
|
ReadOnlyAccount, ReadOnlyDevice,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -538,7 +457,7 @@ mod test {
|
||||||
);
|
);
|
||||||
|
|
||||||
machine
|
machine
|
||||||
.receive_event(&wrap_any_to_device_content(bob_sas.user_id(), start_content.into()))
|
.receive_any_event(&wrap_any_to_device_content(bob_sas.user_id(), start_content.into()))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -559,53 +478,41 @@ mod test {
|
||||||
|
|
||||||
let alice = alice_machine.get_sas(bob.flow_id().as_str()).unwrap();
|
let alice = alice_machine.get_sas(bob.flow_id().as_str()).unwrap();
|
||||||
|
|
||||||
let event = alice
|
let request = alice.accept().unwrap();
|
||||||
.accept()
|
|
||||||
.map(|c| wrap_any_to_device_content(alice.user_id(), get_content_from_request(&c)))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let event = bob
|
let content = OutgoingContent::try_from(request).unwrap();
|
||||||
.receive_event(&event)
|
let content = AcceptContent::try_from(&content).unwrap().into();
|
||||||
.map(|c| wrap_any_to_device_content(bob.user_id(), c))
|
|
||||||
.unwrap();
|
let content = bob.receive_any_event(alice.user_id(), &content).unwrap();
|
||||||
|
|
||||||
|
let event = wrap_any_to_device_content(bob.user_id(), content);
|
||||||
|
|
||||||
assert!(alice_machine.verifications.outgoing_requests.is_empty());
|
assert!(alice_machine.verifications.outgoing_requests.is_empty());
|
||||||
alice_machine.receive_event(&event).await.unwrap();
|
alice_machine.receive_any_event(&event).await.unwrap();
|
||||||
assert!(!alice_machine.verifications.outgoing_requests.is_empty());
|
assert!(!alice_machine.verifications.outgoing_requests.is_empty());
|
||||||
|
|
||||||
let request = alice_machine.verifications.outgoing_requests.iter().next().unwrap();
|
let request = alice_machine.verifications.outgoing_requests.iter().next().unwrap().clone();
|
||||||
|
|
||||||
let txn_id = *request.request_id();
|
let txn_id = *request.request_id();
|
||||||
|
let content = OutgoingContent::try_from(request).unwrap();
|
||||||
|
let content = KeyContent::try_from(&content).unwrap().into();
|
||||||
|
|
||||||
let r = if let OutgoingRequests::ToDeviceRequest(r) = request.request() {
|
|
||||||
r.clone()
|
|
||||||
} else {
|
|
||||||
panic!("Invalid request type");
|
|
||||||
};
|
|
||||||
|
|
||||||
let event =
|
|
||||||
wrap_any_to_device_content(alice.user_id(), get_content_from_request(&r.into()));
|
|
||||||
drop(request);
|
|
||||||
alice_machine.mark_request_as_sent(&txn_id);
|
alice_machine.mark_request_as_sent(&txn_id);
|
||||||
|
|
||||||
assert!(bob.receive_event(&event).is_none());
|
assert!(bob.receive_any_event(alice.user_id(), &content).is_none());
|
||||||
|
|
||||||
assert!(alice.emoji().is_some());
|
assert!(alice.emoji().is_some());
|
||||||
assert!(bob.emoji().is_some());
|
assert!(bob.emoji().is_some());
|
||||||
|
|
||||||
assert_eq!(alice.emoji(), bob.emoji());
|
assert_eq!(alice.emoji(), bob.emoji());
|
||||||
|
|
||||||
let event = wrap_any_to_device_content(
|
let request = alice.confirm().await.unwrap().0.unwrap();
|
||||||
alice.user_id(),
|
let content = OutgoingContent::try_from(request).unwrap();
|
||||||
get_content_from_request(&alice.confirm().await.unwrap().0.unwrap()),
|
let content = MacContent::try_from(&content).unwrap().into();
|
||||||
);
|
bob.receive_any_event(alice.user_id(), &content);
|
||||||
bob.receive_event(&event);
|
|
||||||
|
|
||||||
let event = wrap_any_to_device_content(
|
let request = bob.confirm().await.unwrap().0.unwrap();
|
||||||
bob.user_id(),
|
let content = OutgoingContent::try_from(request).unwrap();
|
||||||
get_content_from_request(&bob.confirm().await.unwrap().0.unwrap()),
|
let content = MacContent::try_from(&content).unwrap().into();
|
||||||
);
|
alice.receive_any_event(bob.user_id(), &content);
|
||||||
alice.receive_event(&event);
|
|
||||||
|
|
||||||
assert!(alice.is_done());
|
assert!(alice.is_done());
|
||||||
assert!(bob.is_done());
|
assert!(bob.is_done());
|
||||||
|
|
|
@ -12,26 +12,30 @@
|
||||||
// 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.
|
||||||
|
|
||||||
|
mod event_enums;
|
||||||
mod machine;
|
mod machine;
|
||||||
mod requests;
|
mod requests;
|
||||||
mod sas;
|
mod sas;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub use machine::{VerificationCache, VerificationMachine};
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
api::r0::keys::upload_signatures::Request as SignatureUploadRequest,
|
api::r0::keys::upload_signatures::Request as SignatureUploadRequest,
|
||||||
events::key::verification::{
|
events::{
|
||||||
cancel::{CancelCode, CancelEventContent, CancelToDeviceEventContent},
|
key::verification::{
|
||||||
Relation,
|
cancel::{CancelCode, CancelEventContent, CancelToDeviceEventContent},
|
||||||
|
Relation,
|
||||||
|
},
|
||||||
|
AnyMessageEventContent, AnyToDeviceEventContent,
|
||||||
},
|
},
|
||||||
identifiers::{DeviceId, EventId, RoomId, UserId},
|
identifiers::{DeviceId, EventId, RoomId, UserId},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use machine::{VerificationCache, VerificationMachine};
|
|
||||||
pub use requests::VerificationRequest;
|
pub use requests::VerificationRequest;
|
||||||
pub use sas::{AcceptSettings, Sas};
|
pub use sas::{AcceptSettings, Sas};
|
||||||
use tracing::{error, info, trace, warn};
|
use tracing::{error, info, trace, warn};
|
||||||
|
|
||||||
|
use self::sas::OutgoingContent;
|
||||||
use crate::{
|
use crate::{
|
||||||
error::SignatureError,
|
error::SignatureError,
|
||||||
olm::PrivateCrossSigningIdentity,
|
olm::PrivateCrossSigningIdentity,
|
||||||
|
@ -39,8 +43,6 @@ use crate::{
|
||||||
CryptoStoreError, LocalTrust, ReadOnlyDevice, UserIdentities,
|
CryptoStoreError, LocalTrust, ReadOnlyDevice, UserIdentities,
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::sas::CancelContent;
|
|
||||||
|
|
||||||
/// The verification state indicating that the verification finished
|
/// The verification state indicating that the verification finished
|
||||||
/// successfully.
|
/// successfully.
|
||||||
///
|
///
|
||||||
|
@ -82,22 +84,24 @@ impl Cancelled {
|
||||||
Self { cancel_code: code, reason }
|
Self { cancel_code: code, reason }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_content(&self, flow_id: &FlowId) -> CancelContent {
|
pub fn as_content(&self, flow_id: &FlowId) -> OutgoingContent {
|
||||||
match flow_id {
|
match flow_id {
|
||||||
FlowId::ToDevice(s) => CancelToDeviceEventContent::new(
|
FlowId::ToDevice(s) => {
|
||||||
s.clone(),
|
AnyToDeviceEventContent::KeyVerificationCancel(CancelToDeviceEventContent::new(
|
||||||
self.reason.to_string(),
|
s.clone(),
|
||||||
self.cancel_code.clone(),
|
self.reason.to_string(),
|
||||||
)
|
self.cancel_code.clone(),
|
||||||
.into(),
|
))
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
FlowId::InRoom(r, e) => (
|
FlowId::InRoom(r, e) => (
|
||||||
r.clone(),
|
r.clone(),
|
||||||
CancelEventContent::new(
|
AnyMessageEventContent::KeyVerificationCancel(CancelEventContent::new(
|
||||||
self.reason.to_string(),
|
self.reason.to_string(),
|
||||||
self.cancel_code.clone(),
|
self.cancel_code.clone(),
|
||||||
Relation::new(e.clone()),
|
Relation::new(e.clone()),
|
||||||
),
|
)),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
}
|
}
|
||||||
|
@ -139,6 +143,12 @@ impl From<(RoomId, EventId)> for FlowId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<(&RoomId, &EventId)> for FlowId {
|
||||||
|
fn from(ids: (&RoomId, &EventId)) -> Self {
|
||||||
|
FlowId::InRoom(ids.0.to_owned(), ids.1.to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A result of a verification flow.
|
/// A result of a verification flow.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum VerificationResult {
|
pub enum VerificationResult {
|
||||||
|
@ -158,7 +168,6 @@ pub struct IdentitiesBeingVerified {
|
||||||
identity_being_verified: Option<UserIdentities>,
|
identity_being_verified: Option<UserIdentities>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
impl IdentitiesBeingVerified {
|
impl IdentitiesBeingVerified {
|
||||||
fn user_id(&self) -> &UserId {
|
fn user_id(&self) -> &UserId {
|
||||||
self.private_identity.user_id()
|
self.private_identity.user_id()
|
||||||
|
@ -298,7 +307,10 @@ impl IdentitiesBeingVerified {
|
||||||
.map_or(false, |i| i.master_key() == identity.master_key())
|
.map_or(false, |i| i.master_key() == identity.master_key())
|
||||||
{
|
{
|
||||||
if verified_identities.map_or(false, |i| i.contains(&identity)) {
|
if verified_identities.map_or(false, |i| i.contains(&identity)) {
|
||||||
trace!("Marking user identity of {} as verified.", identity.user_id(),);
|
trace!(
|
||||||
|
user_id = self.other_user_id().as_str(),
|
||||||
|
"Marking the user identity of as verified."
|
||||||
|
);
|
||||||
|
|
||||||
if let UserIdentities::Own(i) = &identity {
|
if let UserIdentities::Own(i) = &identity {
|
||||||
i.mark_as_verified();
|
i.mark_as_verified();
|
||||||
|
@ -307,28 +319,28 @@ impl IdentitiesBeingVerified {
|
||||||
Ok(Some(identity))
|
Ok(Some(identity))
|
||||||
} else {
|
} else {
|
||||||
info!(
|
info!(
|
||||||
|
user_id = self.other_user_id().as_str(),
|
||||||
"The interactive verification process didn't verify \
|
"The interactive verification process didn't verify \
|
||||||
the user identity of {} {:?}",
|
the user identity of the user that participated in \
|
||||||
identity.user_id(),
|
the interactive verification",
|
||||||
verified_identities,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
warn!(
|
warn!(
|
||||||
"The master keys of {} have changed while an interactive \
|
user_id = self.other_user_id().as_str(),
|
||||||
|
"The master keys of the user have changed while an interactive \
|
||||||
verification was going on, not marking the identity as verified.",
|
verification was going on, not marking the identity as verified.",
|
||||||
identity.user_id(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
info!(
|
info!(
|
||||||
"The identity for {} was deleted while an interactive \
|
user_id = self.other_user_id().as_str(),
|
||||||
|
"The identity of the user was deleted while an interactive \
|
||||||
verification was going on.",
|
verification was going on.",
|
||||||
self.other_user_id(),
|
|
||||||
);
|
);
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,19 +14,15 @@
|
||||||
|
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::{
|
use std::sync::{Arc, Mutex};
|
||||||
convert::TryFrom,
|
|
||||||
sync::{Arc, Mutex},
|
|
||||||
};
|
|
||||||
|
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
api::r0::to_device::DeviceIdOrAllDevices,
|
api::r0::to_device::DeviceIdOrAllDevices,
|
||||||
events::{
|
events::{
|
||||||
key::verification::{
|
key::verification::{
|
||||||
done::{DoneEventContent, DoneToDeviceEventContent},
|
|
||||||
ready::{ReadyEventContent, ReadyToDeviceEventContent},
|
ready::{ReadyEventContent, ReadyToDeviceEventContent},
|
||||||
request::RequestToDeviceEventContent,
|
request::RequestToDeviceEventContent,
|
||||||
start::{StartEventContent, StartMethod, StartToDeviceEventContent},
|
start::StartMethod,
|
||||||
Relation, VerificationMethod,
|
Relation, VerificationMethod,
|
||||||
},
|
},
|
||||||
room::message::KeyVerificationRequestEventContent,
|
room::message::KeyVerificationRequestEventContent,
|
||||||
|
@ -36,10 +32,11 @@ use matrix_sdk_common::{
|
||||||
uuid::Uuid,
|
uuid::Uuid,
|
||||||
MilliSecondsSinceUnixEpoch,
|
MilliSecondsSinceUnixEpoch,
|
||||||
};
|
};
|
||||||
use tracing::{info, trace, warn};
|
use tracing::{info, warn};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
sas::{content_to_request, OutgoingContent, StartContent as OwnedStartContent},
|
event_enums::{ReadyContent, RequestContent, StartContent},
|
||||||
|
sas::{content_to_request, OutgoingContent},
|
||||||
FlowId, VerificationCache,
|
FlowId, VerificationCache,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -51,184 +48,6 @@ use crate::{
|
||||||
|
|
||||||
const SUPPORTED_METHODS: &[VerificationMethod] = &[VerificationMethod::MSasV1];
|
const SUPPORTED_METHODS: &[VerificationMethod] = &[VerificationMethod::MSasV1];
|
||||||
|
|
||||||
pub enum RequestContent<'a> {
|
|
||||||
ToDevice(&'a RequestToDeviceEventContent),
|
|
||||||
Room(&'a KeyVerificationRequestEventContent),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RequestContent<'_> {
|
|
||||||
fn from_device(&self) -> &DeviceId {
|
|
||||||
match self {
|
|
||||||
RequestContent::ToDevice(t) => &t.from_device,
|
|
||||||
RequestContent::Room(r) => &r.from_device,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn methods(&self) -> &[VerificationMethod] {
|
|
||||||
match self {
|
|
||||||
RequestContent::ToDevice(t) => &t.methods,
|
|
||||||
RequestContent::Room(r) => &r.methods,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a KeyVerificationRequestEventContent> for RequestContent<'a> {
|
|
||||||
fn from(c: &'a KeyVerificationRequestEventContent) -> Self {
|
|
||||||
Self::Room(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a RequestToDeviceEventContent> for RequestContent<'a> {
|
|
||||||
fn from(c: &'a RequestToDeviceEventContent) -> Self {
|
|
||||||
Self::ToDevice(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ReadyContent<'a> {
|
|
||||||
ToDevice(&'a ReadyToDeviceEventContent),
|
|
||||||
Room(&'a ReadyEventContent),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ReadyContent<'_> {
|
|
||||||
fn from_device(&self) -> &DeviceId {
|
|
||||||
match self {
|
|
||||||
ReadyContent::ToDevice(t) => &t.from_device,
|
|
||||||
ReadyContent::Room(r) => &r.from_device,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn methods(&self) -> &[VerificationMethod] {
|
|
||||||
match self {
|
|
||||||
ReadyContent::ToDevice(t) => &t.methods,
|
|
||||||
ReadyContent::Room(r) => &r.methods,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a ReadyEventContent> for ReadyContent<'a> {
|
|
||||||
fn from(c: &'a ReadyEventContent) -> Self {
|
|
||||||
Self::Room(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a ReadyToDeviceEventContent> for ReadyContent<'a> {
|
|
||||||
fn from(c: &'a ReadyToDeviceEventContent) -> Self {
|
|
||||||
Self::ToDevice(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TryFrom<&'a OutgoingContent> for ReadyContent<'a> {
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn try_from(value: &'a OutgoingContent) -> Result<Self, Self::Error> {
|
|
||||||
match value {
|
|
||||||
OutgoingContent::Room(_, c) => {
|
|
||||||
if let AnyMessageEventContent::KeyVerificationReady(c) = c {
|
|
||||||
Ok(ReadyContent::Room(c))
|
|
||||||
} else {
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OutgoingContent::ToDevice(c) => {
|
|
||||||
if let AnyToDeviceEventContent::KeyVerificationReady(c) = c {
|
|
||||||
Ok(ReadyContent::ToDevice(c))
|
|
||||||
} else {
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum StartContent<'a> {
|
|
||||||
ToDevice(&'a StartToDeviceEventContent),
|
|
||||||
Room(&'a StartEventContent),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> StartContent<'a> {
|
|
||||||
pub fn from_device(&self) -> &DeviceId {
|
|
||||||
match self {
|
|
||||||
StartContent::ToDevice(c) => &c.from_device,
|
|
||||||
StartContent::Room(c) => &c.from_device,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn flow_id(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
StartContent::ToDevice(c) => &c.transaction_id,
|
|
||||||
StartContent::Room(c) => &c.relation.event_id.as_str(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn method(&self) -> &StartMethod {
|
|
||||||
match self {
|
|
||||||
StartContent::ToDevice(c) => &c.method,
|
|
||||||
StartContent::Room(c) => &c.method,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a StartEventContent> for StartContent<'a> {
|
|
||||||
fn from(c: &'a StartEventContent) -> Self {
|
|
||||||
Self::Room(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a StartToDeviceEventContent> for StartContent<'a> {
|
|
||||||
fn from(c: &'a StartToDeviceEventContent) -> Self {
|
|
||||||
Self::ToDevice(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TryFrom<&'a OutgoingContent> for StartContent<'a> {
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn try_from(value: &'a OutgoingContent) -> Result<Self, Self::Error> {
|
|
||||||
match value {
|
|
||||||
OutgoingContent::Room(_, c) => {
|
|
||||||
if let AnyMessageEventContent::KeyVerificationStart(c) = c {
|
|
||||||
Ok(StartContent::Room(c))
|
|
||||||
} else {
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OutgoingContent::ToDevice(c) => {
|
|
||||||
if let AnyToDeviceEventContent::KeyVerificationStart(c) = c {
|
|
||||||
Ok(StartContent::ToDevice(c))
|
|
||||||
} else {
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum DoneContent<'a> {
|
|
||||||
ToDevice(&'a DoneToDeviceEventContent),
|
|
||||||
Room(&'a DoneEventContent),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a DoneEventContent> for DoneContent<'a> {
|
|
||||||
fn from(c: &'a DoneEventContent) -> Self {
|
|
||||||
Self::Room(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a DoneToDeviceEventContent> for DoneContent<'a> {
|
|
||||||
fn from(c: &'a DoneToDeviceEventContent) -> Self {
|
|
||||||
Self::ToDevice(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> DoneContent<'a> {
|
|
||||||
pub fn flow_id(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Self::ToDevice(c) => &c.transaction_id,
|
|
||||||
Self::Room(c) => &c.relation.event_id.as_str(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
/// TODO
|
/// TODO
|
||||||
pub struct VerificationRequest {
|
pub struct VerificationRequest {
|
||||||
|
@ -311,56 +130,14 @@ impl VerificationRequest {
|
||||||
&self.flow_id
|
&self.flow_id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_room_request(
|
|
||||||
cache: VerificationCache,
|
|
||||||
account: ReadOnlyAccount,
|
|
||||||
private_cross_signing_identity: PrivateCrossSigningIdentity,
|
|
||||||
store: Arc<Box<dyn CryptoStore>>,
|
|
||||||
sender: &UserId,
|
|
||||||
event_id: &EventId,
|
|
||||||
room_id: &RoomId,
|
|
||||||
content: &KeyVerificationRequestEventContent,
|
|
||||||
) -> Self {
|
|
||||||
let flow_id = FlowId::from((room_id.to_owned(), event_id.to_owned()));
|
|
||||||
Self::from_helper(
|
|
||||||
cache,
|
|
||||||
account,
|
|
||||||
private_cross_signing_identity,
|
|
||||||
store,
|
|
||||||
sender,
|
|
||||||
flow_id,
|
|
||||||
content.into(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn from_request(
|
pub(crate) fn from_request(
|
||||||
cache: VerificationCache,
|
|
||||||
account: ReadOnlyAccount,
|
|
||||||
private_cross_signing_identity: PrivateCrossSigningIdentity,
|
|
||||||
store: Arc<Box<dyn CryptoStore>>,
|
|
||||||
sender: &UserId,
|
|
||||||
content: &RequestToDeviceEventContent,
|
|
||||||
) -> Self {
|
|
||||||
let flow_id = FlowId::from(content.transaction_id.to_owned());
|
|
||||||
Self::from_helper(
|
|
||||||
cache,
|
|
||||||
account,
|
|
||||||
private_cross_signing_identity,
|
|
||||||
store,
|
|
||||||
sender,
|
|
||||||
flow_id,
|
|
||||||
content.into(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_helper(
|
|
||||||
cache: VerificationCache,
|
cache: VerificationCache,
|
||||||
account: ReadOnlyAccount,
|
account: ReadOnlyAccount,
|
||||||
private_cross_signing_identity: PrivateCrossSigningIdentity,
|
private_cross_signing_identity: PrivateCrossSigningIdentity,
|
||||||
store: Arc<Box<dyn CryptoStore>>,
|
store: Arc<Box<dyn CryptoStore>>,
|
||||||
sender: &UserId,
|
sender: &UserId,
|
||||||
flow_id: FlowId,
|
flow_id: FlowId,
|
||||||
content: RequestContent,
|
content: &RequestContent,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
verification_cache: cache.clone(),
|
verification_cache: cache.clone(),
|
||||||
|
@ -394,13 +171,8 @@ impl VerificationRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::unnecessary_wraps)]
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
pub(crate) fn receive_ready<'a>(
|
pub(crate) fn receive_ready(&self, sender: &UserId, content: &ReadyContent) -> Result<(), ()> {
|
||||||
&self,
|
|
||||||
sender: &UserId,
|
|
||||||
content: impl Into<ReadyContent<'a>>,
|
|
||||||
) -> Result<(), ()> {
|
|
||||||
let mut inner = self.inner.lock().unwrap();
|
let mut inner = self.inner.lock().unwrap();
|
||||||
let content = content.into();
|
|
||||||
|
|
||||||
if let InnerRequest::Created(s) = &*inner {
|
if let InnerRequest::Created(s) = &*inner {
|
||||||
*inner = InnerRequest::Ready(s.clone().into_ready(sender, content));
|
*inner = InnerRequest::Ready(s.clone().into_ready(sender, content));
|
||||||
|
@ -409,13 +181,11 @@ impl VerificationRequest {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn receive_start<'a>(
|
pub(crate) async fn receive_start(
|
||||||
&self,
|
&self,
|
||||||
sender: &UserId,
|
sender: &UserId,
|
||||||
content: impl Into<StartContent<'a>>,
|
content: &StartContent<'_>,
|
||||||
) -> Result<(), CryptoStoreError> {
|
) -> Result<(), CryptoStoreError> {
|
||||||
let content = content.into();
|
|
||||||
|
|
||||||
let inner = self.inner.lock().unwrap().clone();
|
let inner = self.inner.lock().unwrap().clone();
|
||||||
|
|
||||||
if let InnerRequest::Ready(s) = inner {
|
if let InnerRequest::Ready(s) = inner {
|
||||||
|
@ -502,9 +272,9 @@ impl InnerRequest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_started_sas<'a>(
|
fn to_started_sas(
|
||||||
&self,
|
&self,
|
||||||
content: impl Into<StartContent<'a>>,
|
content: &StartContent,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
) -> Result<Option<Sas>, OutgoingContent> {
|
) -> Result<Option<Sas>, OutgoingContent> {
|
||||||
|
@ -551,7 +321,7 @@ impl RequestState<Created> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_ready(self, _sender: &UserId, content: ReadyContent) -> RequestState<Ready> {
|
fn into_ready(self, _sender: &UserId, content: &ReadyContent) -> RequestState<Ready> {
|
||||||
// TODO check the flow id, and that the methods match what we suggested.
|
// TODO check the flow id, and that the methods match what we suggested.
|
||||||
RequestState {
|
RequestState {
|
||||||
account: self.account,
|
account: self.account,
|
||||||
|
@ -600,7 +370,7 @@ impl RequestState<Requested> {
|
||||||
store: Arc<Box<dyn CryptoStore>>,
|
store: Arc<Box<dyn CryptoStore>>,
|
||||||
sender: &UserId,
|
sender: &UserId,
|
||||||
flow_id: &FlowId,
|
flow_id: &FlowId,
|
||||||
content: RequestContent,
|
content: &RequestContent,
|
||||||
) -> RequestState<Requested> {
|
) -> RequestState<Requested> {
|
||||||
// TODO only create this if we suport the methods
|
// TODO only create this if we suport the methods
|
||||||
RequestState {
|
RequestState {
|
||||||
|
@ -673,39 +443,27 @@ struct Ready {
|
||||||
impl RequestState<Ready> {
|
impl RequestState<Ready> {
|
||||||
fn to_started_sas<'a>(
|
fn to_started_sas<'a>(
|
||||||
&self,
|
&self,
|
||||||
content: impl Into<StartContent<'a>>,
|
content: &StartContent<'a>,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
) -> Result<Sas, OutgoingContent> {
|
) -> Result<Sas, OutgoingContent> {
|
||||||
let content: OwnedStartContent = match content.into() {
|
|
||||||
StartContent::Room(c) => {
|
|
||||||
if let FlowId::InRoom(r, _) = &*self.flow_id {
|
|
||||||
(r.to_owned(), c.to_owned()).into()
|
|
||||||
} else {
|
|
||||||
// TODO cancel here
|
|
||||||
panic!("Missmatch between content and flow id");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StartContent::ToDevice(c) => c.clone().into(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Sas::from_start_event(
|
Sas::from_start_event(
|
||||||
|
(&*self.flow_id).to_owned(),
|
||||||
content,
|
content,
|
||||||
self.store.clone(),
|
self.store.clone(),
|
||||||
self.account.clone(),
|
self.account.clone(),
|
||||||
self.private_cross_signing_identity.clone(),
|
self.private_cross_signing_identity.clone(),
|
||||||
other_device,
|
other_device,
|
||||||
other_identity,
|
other_identity,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn receive_start<'a>(
|
async fn receive_start(
|
||||||
&self,
|
&self,
|
||||||
sender: &UserId,
|
sender: &UserId,
|
||||||
content: impl Into<StartContent<'a>>,
|
content: &StartContent<'_>,
|
||||||
) -> Result<(), CryptoStoreError> {
|
) -> Result<(), CryptoStoreError> {
|
||||||
let content = content.into();
|
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
sender = sender.as_str(),
|
sender = sender.as_str(),
|
||||||
device = content.from_device().as_str(),
|
device = content.from_device().as_str(),
|
||||||
|
@ -747,7 +505,7 @@ impl RequestState<Ready> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
m => {
|
m => {
|
||||||
warn!(method =? m, "Received a key verificaton start event with an unknown method")
|
warn!(method =? m, "Received a key verificaton start event with an unsupported method")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -772,7 +530,7 @@ impl RequestState<Ready> {
|
||||||
other_identity,
|
other_identity,
|
||||||
Some(t),
|
Some(t),
|
||||||
);
|
);
|
||||||
(sas, content.into())
|
(sas, content)
|
||||||
}
|
}
|
||||||
FlowId::InRoom(r, e) => {
|
FlowId::InRoom(r, e) => {
|
||||||
let (sas, content) = Sas::start_in_room(
|
let (sas, content) = Sas::start_in_room(
|
||||||
|
@ -784,7 +542,7 @@ impl RequestState<Ready> {
|
||||||
store,
|
store,
|
||||||
other_identity,
|
other_identity,
|
||||||
);
|
);
|
||||||
(sas, content.into())
|
(sas, content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -807,11 +565,15 @@ mod test {
|
||||||
use matrix_sdk_common::identifiers::{event_id, room_id, DeviceIdBox, UserId};
|
use matrix_sdk_common::identifiers::{event_id, room_id, DeviceIdBox, UserId};
|
||||||
use matrix_sdk_test::async_test;
|
use matrix_sdk_test::async_test;
|
||||||
|
|
||||||
use super::{StartContent, VerificationRequest};
|
use super::VerificationRequest;
|
||||||
use crate::{
|
use crate::{
|
||||||
olm::{PrivateCrossSigningIdentity, ReadOnlyAccount},
|
olm::{PrivateCrossSigningIdentity, ReadOnlyAccount},
|
||||||
store::{Changes, CryptoStore, MemoryStore},
|
store::{Changes, CryptoStore, MemoryStore},
|
||||||
verification::{requests::ReadyContent, sas::OutgoingContent, VerificationCache},
|
verification::{
|
||||||
|
event_enums::{ReadyContent, StartContent},
|
||||||
|
sas::OutgoingContent,
|
||||||
|
FlowId, VerificationCache,
|
||||||
|
},
|
||||||
ReadOnlyDevice,
|
ReadOnlyDevice,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -856,21 +618,22 @@ mod test {
|
||||||
&alice_id(),
|
&alice_id(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let alice_request = VerificationRequest::from_room_request(
|
let flow_id = FlowId::from((room_id, event_id));
|
||||||
|
|
||||||
|
let alice_request = VerificationRequest::from_request(
|
||||||
VerificationCache::new(),
|
VerificationCache::new(),
|
||||||
alice,
|
alice,
|
||||||
alice_identity,
|
alice_identity,
|
||||||
alice_store.into(),
|
alice_store.into(),
|
||||||
&bob_id(),
|
&bob_id(),
|
||||||
&event_id,
|
flow_id,
|
||||||
&room_id,
|
&(&content).into(),
|
||||||
&content,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let content: OutgoingContent = alice_request.accept().unwrap().into();
|
let content: OutgoingContent = alice_request.accept().unwrap().into();
|
||||||
let content = ReadyContent::try_from(&content).unwrap();
|
let content = ReadyContent::try_from(&content).unwrap();
|
||||||
|
|
||||||
bob_request.receive_ready(&alice_id(), content).unwrap();
|
bob_request.receive_ready(&alice_id(), &content).unwrap();
|
||||||
|
|
||||||
assert!(bob_request.is_ready());
|
assert!(bob_request.is_ready());
|
||||||
assert!(alice_request.is_ready());
|
assert!(alice_request.is_ready());
|
||||||
|
@ -908,21 +671,22 @@ mod test {
|
||||||
&alice_id(),
|
&alice_id(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let alice_request = VerificationRequest::from_room_request(
|
let flow_id = FlowId::from((room_id, event_id));
|
||||||
|
|
||||||
|
let alice_request = VerificationRequest::from_request(
|
||||||
VerificationCache::new(),
|
VerificationCache::new(),
|
||||||
alice,
|
alice,
|
||||||
alice_identity,
|
alice_identity,
|
||||||
alice_store.into(),
|
alice_store.into(),
|
||||||
&bob_id(),
|
&bob_id(),
|
||||||
&event_id,
|
flow_id,
|
||||||
&room_id,
|
&(&content).into(),
|
||||||
&content,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let content: OutgoingContent = alice_request.accept().unwrap().into();
|
let content: OutgoingContent = alice_request.accept().unwrap().into();
|
||||||
let content = ReadyContent::try_from(&content).unwrap();
|
let content = ReadyContent::try_from(&content).unwrap();
|
||||||
|
|
||||||
bob_request.receive_ready(&alice_id(), content).unwrap();
|
bob_request.receive_ready(&alice_id(), &content).unwrap();
|
||||||
|
|
||||||
assert!(bob_request.is_ready());
|
assert!(bob_request.is_ready());
|
||||||
assert!(alice_request.is_ready());
|
assert!(alice_request.is_ready());
|
||||||
|
@ -931,7 +695,7 @@ mod test {
|
||||||
|
|
||||||
let content = StartContent::try_from(&start_content).unwrap();
|
let content = StartContent::try_from(&start_content).unwrap();
|
||||||
let flow_id = content.flow_id().to_owned();
|
let flow_id = content.flow_id().to_owned();
|
||||||
alice_request.receive_start(bob_device.user_id(), content).await.unwrap();
|
alice_request.receive_start(bob_device.user_id(), &content).await.unwrap();
|
||||||
let alice_sas = alice_request.verification_cache.get_sas(&flow_id).unwrap();
|
let alice_sas = alice_request.verification_cache.get_sas(&flow_id).unwrap();
|
||||||
|
|
||||||
assert!(!bob_sas.is_cancelled());
|
assert!(!bob_sas.is_cancelled());
|
||||||
|
|
|
@ -12,254 +12,26 @@
|
||||||
// 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::{collections::BTreeMap, convert::TryInto};
|
|
||||||
|
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
events::{
|
events::{AnyMessageEventContent, AnyToDeviceEventContent},
|
||||||
key::verification::{
|
|
||||||
accept::{AcceptEventContent, AcceptMethod, AcceptToDeviceEventContent},
|
|
||||||
cancel::{CancelEventContent, CancelToDeviceEventContent},
|
|
||||||
done::DoneEventContent,
|
|
||||||
key::{KeyEventContent, KeyToDeviceEventContent},
|
|
||||||
mac::{MacEventContent, MacToDeviceEventContent},
|
|
||||||
start::{StartEventContent, StartMethod, StartToDeviceEventContent},
|
|
||||||
},
|
|
||||||
AnyMessageEventContent, AnyToDeviceEventContent,
|
|
||||||
},
|
|
||||||
identifiers::RoomId,
|
identifiers::RoomId,
|
||||||
CanonicalJsonValue,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::FlowId;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum StartContent {
|
|
||||||
ToDevice(StartToDeviceEventContent),
|
|
||||||
Room(RoomId, StartEventContent),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StartContent {
|
|
||||||
pub fn method(&self) -> &StartMethod {
|
|
||||||
match self {
|
|
||||||
StartContent::ToDevice(c) => &c.method,
|
|
||||||
StartContent::Room(_, c) => &c.method,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn flow_id(&self) -> FlowId {
|
|
||||||
match self {
|
|
||||||
StartContent::ToDevice(c) => FlowId::ToDevice(c.transaction_id.clone()),
|
|
||||||
StartContent::Room(r, c) => FlowId::InRoom(r.clone(), c.relation.event_id.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn canonical_json(self) -> CanonicalJsonValue {
|
|
||||||
let content = match self {
|
|
||||||
StartContent::ToDevice(c) => serde_json::to_value(c),
|
|
||||||
StartContent::Room(_, c) => serde_json::to_value(c),
|
|
||||||
};
|
|
||||||
|
|
||||||
content.expect("Can't serialize content").try_into().expect("Can't canonicalize content")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(RoomId, StartEventContent)> for StartContent {
|
|
||||||
fn from(tuple: (RoomId, StartEventContent)) -> Self {
|
|
||||||
StartContent::Room(tuple.0, tuple.1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<StartToDeviceEventContent> for StartContent {
|
|
||||||
fn from(content: StartToDeviceEventContent) -> Self {
|
|
||||||
StartContent::ToDevice(content)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum AcceptContent {
|
|
||||||
ToDevice(AcceptToDeviceEventContent),
|
|
||||||
Room(RoomId, AcceptEventContent),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AcceptContent {
|
|
||||||
pub fn flow_id(&self) -> FlowId {
|
|
||||||
match self {
|
|
||||||
AcceptContent::ToDevice(c) => FlowId::ToDevice(c.transaction_id.clone()),
|
|
||||||
AcceptContent::Room(r, c) => FlowId::InRoom(r.clone(), c.relation.event_id.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn method(&self) -> &AcceptMethod {
|
|
||||||
match self {
|
|
||||||
AcceptContent::ToDevice(c) => &c.method,
|
|
||||||
AcceptContent::Room(_, c) => &c.method,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<AcceptToDeviceEventContent> for AcceptContent {
|
|
||||||
fn from(content: AcceptToDeviceEventContent) -> Self {
|
|
||||||
AcceptContent::ToDevice(content)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(RoomId, AcceptEventContent)> for AcceptContent {
|
|
||||||
fn from(content: (RoomId, AcceptEventContent)) -> Self {
|
|
||||||
AcceptContent::Room(content.0, content.1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
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 DoneContent {
|
|
||||||
Room(RoomId, DoneEventContent),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DoneContent {
|
|
||||||
pub fn flow_id(&self) -> FlowId {
|
|
||||||
match self {
|
|
||||||
DoneContent::Room(r, c) => FlowId::InRoom(r.clone(), c.relation.event_id.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(RoomId, DoneEventContent)> for DoneContent {
|
|
||||||
fn from(content: (RoomId, DoneEventContent)) -> Self {
|
|
||||||
DoneContent::Room(content.0, content.1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum OutgoingContent {
|
pub enum OutgoingContent {
|
||||||
Room(RoomId, AnyMessageEventContent),
|
Room(RoomId, AnyMessageEventContent),
|
||||||
ToDevice(AnyToDeviceEventContent),
|
ToDevice(AnyToDeviceEventContent),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<StartContent> for OutgoingContent {
|
impl From<OwnedStartContent> for OutgoingContent {
|
||||||
fn from(content: StartContent) -> Self {
|
fn from(content: OwnedStartContent) -> Self {
|
||||||
match content {
|
match content {
|
||||||
StartContent::Room(r, c) => (r, AnyMessageEventContent::KeyVerificationStart(c)).into(),
|
OwnedStartContent::Room(r, c) => {
|
||||||
StartContent::ToDevice(c) => AnyToDeviceEventContent::KeyVerificationStart(c).into(),
|
(r, AnyMessageEventContent::KeyVerificationStart(c)).into()
|
||||||
}
|
}
|
||||||
}
|
OwnedStartContent::ToDevice(c) => {
|
||||||
}
|
AnyToDeviceEventContent::KeyVerificationStart(c).into()
|
||||||
|
|
||||||
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<DoneContent> for OutgoingContent {
|
|
||||||
fn from(content: DoneContent) -> Self {
|
|
||||||
match content {
|
|
||||||
DoneContent::Room(r, c) => (r, AnyMessageEventContent::KeyVerificationDone(c)).into(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -277,62 +49,98 @@ impl From<(RoomId, AnyMessageEventContent)> for OutgoingContent {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use crate::OutgoingVerificationRequest;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
|
use crate::verification::event_enums::OwnedStartContent;
|
||||||
|
#[cfg(test)]
|
||||||
|
use crate::{OutgoingRequest, OutgoingVerificationRequest, RoomMessageRequest, ToDeviceRequest};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
impl From<OutgoingVerificationRequest> for OutgoingContent {
|
impl From<OutgoingVerificationRequest> for OutgoingContent {
|
||||||
fn from(request: OutgoingVerificationRequest) -> Self {
|
fn from(request: OutgoingVerificationRequest) -> Self {
|
||||||
use matrix_sdk_common::events::EventType;
|
|
||||||
use serde_json::Value;
|
|
||||||
|
|
||||||
match request {
|
match request {
|
||||||
OutgoingVerificationRequest::ToDevice(r) => {
|
OutgoingVerificationRequest::ToDevice(r) => Self::try_from(r).unwrap(),
|
||||||
let json: Value = serde_json::from_str(
|
OutgoingVerificationRequest::InRoom(r) => Self::from(r),
|
||||||
r.messages.values().next().unwrap().values().next().unwrap().get(),
|
}
|
||||||
)
|
}
|
||||||
.unwrap();
|
}
|
||||||
|
|
||||||
match r.event_type {
|
#[cfg(test)]
|
||||||
EventType::KeyVerificationRequest => {
|
impl From<RoomMessageRequest> for OutgoingContent {
|
||||||
AnyToDeviceEventContent::KeyVerificationRequest(
|
fn from(value: RoomMessageRequest) -> Self {
|
||||||
serde_json::from_value(json).unwrap(),
|
(value.room_id, value.content).into()
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
EventType::KeyVerificationReady => {
|
|
||||||
AnyToDeviceEventContent::KeyVerificationReady(
|
#[cfg(test)]
|
||||||
serde_json::from_value(json).unwrap(),
|
impl TryFrom<ToDeviceRequest> for OutgoingContent {
|
||||||
)
|
type Error = ();
|
||||||
}
|
|
||||||
EventType::KeyVerificationDone => AnyToDeviceEventContent::KeyVerificationDone(
|
fn try_from(value: ToDeviceRequest) -> Result<Self, Self::Error> {
|
||||||
serde_json::from_value(json).unwrap(),
|
use matrix_sdk_common::events::EventType;
|
||||||
),
|
use serde_json::Value;
|
||||||
EventType::KeyVerificationStart => {
|
|
||||||
AnyToDeviceEventContent::KeyVerificationStart(
|
let json: Value = serde_json::from_str(
|
||||||
serde_json::from_value(json).unwrap(),
|
value
|
||||||
)
|
.messages
|
||||||
}
|
.values()
|
||||||
EventType::KeyVerificationKey => AnyToDeviceEventContent::KeyVerificationKey(
|
.next()
|
||||||
serde_json::from_value(json).unwrap(),
|
.and_then(|m| m.values().next().map(|j| j.get()))
|
||||||
),
|
.ok_or(())?,
|
||||||
EventType::KeyVerificationAccept => {
|
)
|
||||||
AnyToDeviceEventContent::KeyVerificationAccept(
|
.map_err(|_| ())?;
|
||||||
serde_json::from_value(json).unwrap(),
|
|
||||||
)
|
match value.event_type {
|
||||||
}
|
EventType::KeyVerificationRequest => {
|
||||||
EventType::KeyVerificationMac => AnyToDeviceEventContent::KeyVerificationMac(
|
Ok(AnyToDeviceEventContent::KeyVerificationRequest(
|
||||||
serde_json::from_value(json).unwrap(),
|
serde_json::from_value(json).map_err(|_| ())?,
|
||||||
),
|
)
|
||||||
EventType::KeyVerificationCancel => {
|
.into())
|
||||||
AnyToDeviceEventContent::KeyVerificationCancel(
|
}
|
||||||
serde_json::from_value(json).unwrap(),
|
EventType::KeyVerificationReady => Ok(AnyToDeviceEventContent::KeyVerificationReady(
|
||||||
)
|
serde_json::from_value(json).map_err(|_| ())?,
|
||||||
}
|
)
|
||||||
_ => unreachable!(),
|
.into()),
|
||||||
}
|
EventType::KeyVerificationDone => Ok(AnyToDeviceEventContent::KeyVerificationDone(
|
||||||
.into()
|
serde_json::from_value(json).map_err(|_| ())?,
|
||||||
}
|
)
|
||||||
|
.into()),
|
||||||
OutgoingVerificationRequest::InRoom(r) => (r.room_id, r.content).into(),
|
EventType::KeyVerificationStart => Ok(AnyToDeviceEventContent::KeyVerificationStart(
|
||||||
|
serde_json::from_value(json).map_err(|_| ())?,
|
||||||
|
)
|
||||||
|
.into()),
|
||||||
|
EventType::KeyVerificationKey => Ok(AnyToDeviceEventContent::KeyVerificationKey(
|
||||||
|
serde_json::from_value(json).map_err(|_| ())?,
|
||||||
|
)
|
||||||
|
.into()),
|
||||||
|
EventType::KeyVerificationAccept => Ok(AnyToDeviceEventContent::KeyVerificationAccept(
|
||||||
|
serde_json::from_value(json).map_err(|_| ())?,
|
||||||
|
)
|
||||||
|
.into()),
|
||||||
|
EventType::KeyVerificationMac => Ok(AnyToDeviceEventContent::KeyVerificationMac(
|
||||||
|
serde_json::from_value(json).map_err(|_| ())?,
|
||||||
|
)
|
||||||
|
.into()),
|
||||||
|
EventType::KeyVerificationCancel => Ok(AnyToDeviceEventContent::KeyVerificationCancel(
|
||||||
|
serde_json::from_value(json).map_err(|_| ())?,
|
||||||
|
)
|
||||||
|
.into()),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl TryFrom<OutgoingRequest> for OutgoingContent {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: OutgoingRequest) -> Result<Self, ()> {
|
||||||
|
match value.request() {
|
||||||
|
crate::OutgoingRequests::KeysUpload(_) => Err(()),
|
||||||
|
crate::OutgoingRequests::KeysQuery(_) => Err(()),
|
||||||
|
crate::OutgoingRequests::ToDeviceRequest(r) => Self::try_from(r.clone()),
|
||||||
|
crate::OutgoingRequests::SignatureUpload(_) => Err(()),
|
||||||
|
crate::OutgoingRequests::RoomMessage(r) => Ok(Self::from(r.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ use matrix_sdk_common::{
|
||||||
mac::{MacEventContent, MacToDeviceEventContent},
|
mac::{MacEventContent, MacToDeviceEventContent},
|
||||||
Relation,
|
Relation,
|
||||||
},
|
},
|
||||||
AnyToDeviceEventContent, EventType,
|
AnyMessageEventContent, AnyToDeviceEventContent, EventType,
|
||||||
},
|
},
|
||||||
identifiers::{DeviceKeyAlgorithm, DeviceKeyId, UserId},
|
identifiers::{DeviceKeyAlgorithm, DeviceKeyId, UserId},
|
||||||
uuid::Uuid,
|
uuid::Uuid,
|
||||||
|
@ -31,13 +31,11 @@ use olm_rs::sas::OlmSas;
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
use tracing::{trace, warn};
|
use tracing::{trace, warn};
|
||||||
|
|
||||||
use super::{
|
use super::{FlowId, OutgoingContent};
|
||||||
event_enums::{MacContent, StartContent},
|
|
||||||
FlowId,
|
|
||||||
};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
identities::{ReadOnlyDevice, UserIdentities},
|
identities::{ReadOnlyDevice, UserIdentities},
|
||||||
utilities::encode,
|
utilities::encode,
|
||||||
|
verification::event_enums::{MacContent, StartContent},
|
||||||
ReadOnlyAccount, ToDeviceRequest,
|
ReadOnlyAccount, ToDeviceRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -58,8 +56,8 @@ pub struct SasIds {
|
||||||
///
|
///
|
||||||
/// * `content` - The `m.key.verification.start` event content that started the
|
/// * `content` - The `m.key.verification.start` event content that started the
|
||||||
/// interactive verification process.
|
/// interactive verification process.
|
||||||
pub fn calculate_commitment(public_key: &str, content: impl Into<StartContent>) -> String {
|
pub fn calculate_commitment(public_key: &str, content: &StartContent) -> String {
|
||||||
let content = content.into().canonical_json();
|
let content = content.canonical_json();
|
||||||
let content_string = content.to_string();
|
let content_string = content.to_string();
|
||||||
|
|
||||||
encode(Sha256::new().chain(&public_key).chain(&content_string).finalize())
|
encode(Sha256::new().chain(&public_key).chain(&content_string).finalize())
|
||||||
|
@ -199,7 +197,7 @@ pub fn receive_mac_event(
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut keys = content.mac().keys().map(|k| k.as_str()).collect::<Vec<_>>();
|
let mut keys = content.mac().keys().map(|k| k.as_str()).collect::<Vec<_>>();
|
||||||
keys.sort();
|
keys.sort_unstable();
|
||||||
|
|
||||||
let keys = sas
|
let keys = sas
|
||||||
.calculate_mac(&keys.join(","), &format!("{}KEY_IDS", &info))
|
.calculate_mac(&keys.join(","), &format!("{}KEY_IDS", &info))
|
||||||
|
@ -296,7 +294,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) -> MacContent {
|
pub fn get_mac_content(sas: &OlmSas, ids: &SasIds, flow_id: &FlowId) -> OutgoingContent {
|
||||||
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());
|
||||||
|
@ -317,10 +315,19 @@ pub fn get_mac_content(sas: &OlmSas, ids: &SasIds, flow_id: &FlowId) -> MacConte
|
||||||
.expect("Can't calculate SAS MAC");
|
.expect("Can't calculate SAS MAC");
|
||||||
|
|
||||||
match flow_id {
|
match flow_id {
|
||||||
FlowId::ToDevice(s) => MacToDeviceEventContent::new(s.to_string(), mac, keys).into(),
|
FlowId::ToDevice(s) => AnyToDeviceEventContent::KeyVerificationMac(
|
||||||
FlowId::InRoom(r, e) => {
|
MacToDeviceEventContent::new(s.to_string(), mac, keys),
|
||||||
(r.clone(), MacEventContent::new(mac, keys, Relation::new(e.clone()))).into()
|
)
|
||||||
}
|
.into(),
|
||||||
|
FlowId::InRoom(r, e) => (
|
||||||
|
r.clone(),
|
||||||
|
AnyMessageEventContent::KeyVerificationMac(MacEventContent::new(
|
||||||
|
mac,
|
||||||
|
keys,
|
||||||
|
Relation::new(e.clone()),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,6 +565,7 @@ mod test {
|
||||||
bytes_to_decimal, bytes_to_emoji, bytes_to_emoji_index, calculate_commitment,
|
bytes_to_decimal, bytes_to_emoji, bytes_to_emoji_index, calculate_commitment,
|
||||||
emoji_from_index,
|
emoji_from_index,
|
||||||
};
|
};
|
||||||
|
use crate::verification::event_enums::StartContent;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn commitment_calculation() {
|
fn commitment_calculation() {
|
||||||
|
@ -575,7 +583,8 @@ mod test {
|
||||||
});
|
});
|
||||||
|
|
||||||
let content: StartToDeviceEventContent = serde_json::from_value(content).unwrap();
|
let content: StartToDeviceEventContent = serde_json::from_value(content).unwrap();
|
||||||
let calculated_commitment = calculate_commitment(public_key, content);
|
let content = StartContent::from(&content);
|
||||||
|
let calculated_commitment = calculate_commitment(public_key, &content);
|
||||||
|
|
||||||
assert_eq!(commitment, &calculated_commitment);
|
assert_eq!(commitment, &calculated_commitment);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,23 +17,23 @@ use std::sync::Arc;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
events::{
|
events::key::verification::{cancel::CancelCode, ShortAuthenticationString},
|
||||||
key::verification::{cancel::CancelCode, ShortAuthenticationString},
|
identifiers::{EventId, RoomId, UserId},
|
||||||
AnyMessageEvent, AnyToDeviceEvent,
|
|
||||||
},
|
|
||||||
identifiers::{EventId, RoomId},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
event_enums::{AcceptContent, CancelContent, MacContent, OutgoingContent},
|
event_enums::OutgoingContent,
|
||||||
sas_state::{
|
sas_state::{
|
||||||
Accepted, Confirmed, Created, KeyReceived, MacReceived, SasState, Started, WaitingForDone,
|
Accepted, Confirmed, Created, KeyReceived, MacReceived, SasState, Started, WaitingForDone,
|
||||||
},
|
},
|
||||||
FlowId, StartContent,
|
FlowId,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
identities::{ReadOnlyDevice, UserIdentities},
|
identities::{ReadOnlyDevice, UserIdentities},
|
||||||
verification::{Cancelled, Done},
|
verification::{
|
||||||
|
event_enums::{AnyVerificationContent, OwnedAcceptContent, StartContent},
|
||||||
|
Cancelled, Done,
|
||||||
|
},
|
||||||
ReadOnlyAccount,
|
ReadOnlyAccount,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -57,10 +57,10 @@ impl InnerSas {
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
transaction_id: Option<String>,
|
transaction_id: Option<String>,
|
||||||
) -> (InnerSas, StartContent) {
|
) -> (InnerSas, OutgoingContent) {
|
||||||
let sas = SasState::<Created>::new(account, other_device, other_identity, transaction_id);
|
let sas = SasState::<Created>::new(account, other_device, other_identity, transaction_id);
|
||||||
let content = sas.as_content();
|
let content = sas.as_content();
|
||||||
(InnerSas::Created(sas), content)
|
(InnerSas::Created(sas), content.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn supports_emoji(&self) -> bool {
|
pub fn supports_emoji(&self) -> bool {
|
||||||
|
@ -100,7 +100,7 @@ impl InnerSas {
|
||||||
account: ReadOnlyAccount,
|
account: ReadOnlyAccount,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
) -> (InnerSas, StartContent) {
|
) -> (InnerSas, OutgoingContent) {
|
||||||
let sas = SasState::<Created>::new_in_room(
|
let sas = SasState::<Created>::new_in_room(
|
||||||
room_id,
|
room_id,
|
||||||
event_id,
|
event_id,
|
||||||
|
@ -109,23 +109,31 @@ impl InnerSas {
|
||||||
other_identity,
|
other_identity,
|
||||||
);
|
);
|
||||||
let content = sas.as_content();
|
let content = sas.as_content();
|
||||||
(InnerSas::Created(sas), content)
|
(InnerSas::Created(sas), content.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_start_event(
|
pub fn from_start_event(
|
||||||
account: ReadOnlyAccount,
|
account: ReadOnlyAccount,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
content: impl Into<StartContent>,
|
flow_id: FlowId,
|
||||||
|
content: &StartContent,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
) -> Result<InnerSas, CancelContent> {
|
started_from_request: bool,
|
||||||
match SasState::<Started>::from_start_event(account, other_device, other_identity, content)
|
) -> Result<InnerSas, OutgoingContent> {
|
||||||
{
|
match SasState::<Started>::from_start_event(
|
||||||
|
account,
|
||||||
|
other_device,
|
||||||
|
other_identity,
|
||||||
|
flow_id,
|
||||||
|
content,
|
||||||
|
started_from_request,
|
||||||
|
) {
|
||||||
Ok(s) => Ok(InnerSas::Started(s)),
|
Ok(s) => Ok(InnerSas::Started(s)),
|
||||||
Err(s) => Err(s.as_content()),
|
Err(s) => Err(s.as_content()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn accept(&self) -> Option<AcceptContent> {
|
pub fn accept(&self) -> Option<OwnedAcceptContent> {
|
||||||
if let InnerSas::Started(s) = self {
|
if let InnerSas::Started(s) = self {
|
||||||
Some(s.as_content())
|
Some(s.as_content())
|
||||||
} else {
|
} else {
|
||||||
|
@ -150,7 +158,7 @@ impl InnerSas {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cancel(self, code: CancelCode) -> (InnerSas, Option<CancelContent>) {
|
pub fn cancel(self, code: CancelCode) -> (InnerSas, Option<OutgoingContent>) {
|
||||||
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),
|
||||||
|
@ -165,7 +173,7 @@ impl InnerSas {
|
||||||
(InnerSas::Cancelled(sas), Some(content))
|
(InnerSas::Cancelled(sas), Some(content))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn confirm(self) -> (InnerSas, Option<MacContent>) {
|
pub fn confirm(self) -> (InnerSas, Option<OutgoingContent>) {
|
||||||
match self {
|
match self {
|
||||||
InnerSas::KeyReceived(s) => {
|
InnerSas::KeyReceived(s) => {
|
||||||
let sas = s.confirm();
|
let sas = s.confirm();
|
||||||
|
@ -189,149 +197,104 @@ impl InnerSas {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
pub fn receive_any_event(
|
||||||
pub fn receive_room_event(
|
|
||||||
self,
|
self,
|
||||||
event: &AnyMessageEvent,
|
sender: &UserId,
|
||||||
) -> (InnerSas, Option<OutgoingContent>) {
|
content: &AnyVerificationContent,
|
||||||
match event {
|
) -> (Self, Option<OutgoingContent>) {
|
||||||
AnyMessageEvent::KeyVerificationKey(e) => match self {
|
match content {
|
||||||
InnerSas::Accepted(s) => {
|
AnyVerificationContent::Accept(c) => {
|
||||||
match s.into_key_received(&e.sender, (e.room_id.clone(), e.content.clone())) {
|
|
||||||
Ok(s) => (InnerSas::KeyReceived(s), None),
|
|
||||||
Err(s) => {
|
|
||||||
let content = s.as_content();
|
|
||||||
(InnerSas::Cancelled(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::KeyReceived(s), Some(content.into()))
|
|
||||||
}
|
|
||||||
Err(s) => {
|
|
||||||
let content = s.as_content();
|
|
||||||
(InnerSas::Cancelled(s), Some(content.into()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => (self, None),
|
|
||||||
},
|
|
||||||
AnyMessageEvent::KeyVerificationMac(e) => match self {
|
|
||||||
InnerSas::KeyReceived(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::Cancelled(s), Some(content.into()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InnerSas::Confirmed(s) => {
|
|
||||||
match s.into_waiting_for_done(&e.sender, (e.room_id.clone(), e.content.clone()))
|
|
||||||
{
|
|
||||||
Ok(s) => {
|
|
||||||
let content = s.done_content();
|
|
||||||
(InnerSas::WaitingForDone(s), Some(content.into()))
|
|
||||||
}
|
|
||||||
Err(s) => {
|
|
||||||
let content = s.as_content();
|
|
||||||
(InnerSas::Cancelled(s), Some(content.into()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => (self, None),
|
|
||||||
},
|
|
||||||
AnyMessageEvent::KeyVerificationDone(e) => match self {
|
|
||||||
InnerSas::WaitingForDone(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::Cancelled(s), Some(content.into()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InnerSas::WaitingForDoneUnconfirmed(s) => {
|
|
||||||
match s.into_done(&e.sender, (e.room_id.clone(), e.content.clone())) {
|
|
||||||
Ok(s) => {
|
|
||||||
let content = s.done_content();
|
|
||||||
(InnerSas::Done(s), Some(content.into()))
|
|
||||||
}
|
|
||||||
Err(s) => {
|
|
||||||
let content = s.as_content();
|
|
||||||
(InnerSas::Cancelled(s), Some(content.into()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => (self, None),
|
|
||||||
},
|
|
||||||
_ => (self, None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn receive_event(self, event: &AnyToDeviceEvent) -> (InnerSas, Option<OutgoingContent>) {
|
|
||||||
match event {
|
|
||||||
AnyToDeviceEvent::KeyVerificationAccept(e) => {
|
|
||||||
if let InnerSas::Created(s) = self {
|
if let InnerSas::Created(s) = self {
|
||||||
match s.into_accepted(&e.sender, e.content.clone()) {
|
match s.into_accepted(sender, c) {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
let content = s.as_content();
|
let content = s.as_content();
|
||||||
(InnerSas::Accepted(s), Some(content.into()))
|
(InnerSas::Accepted(s), Some(content))
|
||||||
}
|
}
|
||||||
Err(s) => {
|
Err(s) => {
|
||||||
let content = s.as_content();
|
let content = s.as_content();
|
||||||
(InnerSas::Cancelled(s), Some(content.into()))
|
(InnerSas::Cancelled(s), Some(content))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(self, None)
|
(self, None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AnyToDeviceEvent::KeyVerificationKey(e) => match self {
|
AnyVerificationContent::Cancel(c) => {
|
||||||
InnerSas::Accepted(s) => match s.into_key_received(&e.sender, e.content.clone()) {
|
let (sas, _) = self.cancel(c.cancel_code().to_owned());
|
||||||
|
(sas, None)
|
||||||
|
}
|
||||||
|
AnyVerificationContent::Key(c) => match self {
|
||||||
|
InnerSas::Accepted(s) => match s.into_key_received(sender, c) {
|
||||||
Ok(s) => (InnerSas::KeyReceived(s), None),
|
Ok(s) => (InnerSas::KeyReceived(s), None),
|
||||||
Err(s) => {
|
Err(s) => {
|
||||||
let content = s.as_content();
|
let content = s.as_content();
|
||||||
(InnerSas::Cancelled(s), Some(content.into()))
|
(InnerSas::Cancelled(s), Some(content))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
InnerSas::Started(s) => match s.into_key_received(&e.sender, e.content.clone()) {
|
InnerSas::Started(s) => match s.into_key_received(sender, c) {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
let content = s.as_content();
|
let content = s.as_content();
|
||||||
(InnerSas::KeyReceived(s), Some(content.into()))
|
(InnerSas::KeyReceived(s), Some(content))
|
||||||
}
|
}
|
||||||
Err(s) => {
|
Err(s) => {
|
||||||
let content = s.as_content();
|
let content = s.as_content();
|
||||||
(InnerSas::Cancelled(s), Some(content.into()))
|
(InnerSas::Cancelled(s), Some(content))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => (self, None),
|
_ => (self, None),
|
||||||
},
|
},
|
||||||
AnyToDeviceEvent::KeyVerificationMac(e) => match self {
|
AnyVerificationContent::Mac(c) => match self {
|
||||||
InnerSas::KeyReceived(s) => {
|
InnerSas::KeyReceived(s) => match s.into_mac_received(sender, c) {
|
||||||
match s.into_mac_received(&e.sender, e.content.clone()) {
|
Ok(s) => (InnerSas::MacReceived(s), None),
|
||||||
Ok(s) => (InnerSas::MacReceived(s), None),
|
Err(s) => {
|
||||||
|
let content = s.as_content();
|
||||||
|
(InnerSas::Cancelled(s), Some(content))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
InnerSas::Confirmed(s) =>
|
||||||
|
// TODO remove the else branch when we remove the ability to
|
||||||
|
// start from a `m.key.verification.start` event.
|
||||||
|
{
|
||||||
|
match if s.started_from_request {
|
||||||
|
s.into_waiting_for_done(sender, c)
|
||||||
|
.map(|s| (Some(s.done_content()), InnerSas::WaitingForDone(s)))
|
||||||
|
} else {
|
||||||
|
s.into_done(sender, c).map(|s| (None, InnerSas::Done(s)))
|
||||||
|
} {
|
||||||
|
Ok((c, s)) => (s, c),
|
||||||
Err(s) => {
|
Err(s) => {
|
||||||
let content = s.as_content();
|
let content = s.as_content();
|
||||||
(InnerSas::Cancelled(s), Some(content.into()))
|
(InnerSas::Cancelled(s), Some(content))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InnerSas::Confirmed(s) => match s.into_done(&e.sender, e.content.clone()) {
|
_ => (self, None),
|
||||||
|
},
|
||||||
|
AnyVerificationContent::Done(c) => match self {
|
||||||
|
InnerSas::WaitingForDone(s) => match s.into_done(sender, c) {
|
||||||
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::Cancelled(s), Some(content.into()))
|
(InnerSas::Cancelled(s), Some(content))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
InnerSas::WaitingForDoneUnconfirmed(s) => match s.into_done(sender, c) {
|
||||||
|
Ok(s) => {
|
||||||
|
let content = s.done_content();
|
||||||
|
(InnerSas::Done(s), Some(content))
|
||||||
|
}
|
||||||
|
Err(s) => {
|
||||||
|
let content = s.as_content();
|
||||||
|
(InnerSas::Cancelled(s), Some(content))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_ => (self, None),
|
_ => (self, None),
|
||||||
},
|
},
|
||||||
_ => (self, None),
|
AnyVerificationContent::Request(_)
|
||||||
|
| AnyVerificationContent::Ready(_)
|
||||||
|
| AnyVerificationContent::Start(_) => (self, None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,7 @@ use std::sync::{Arc, Mutex};
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use event_enums::AcceptContent;
|
pub use event_enums::OutgoingContent;
|
||||||
pub use event_enums::{CancelContent, OutgoingContent, StartContent};
|
|
||||||
pub use helpers::content_to_request;
|
pub use helpers::content_to_request;
|
||||||
use inner_sas::InnerSas;
|
use inner_sas::InnerSas;
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
|
@ -33,13 +32,16 @@ use matrix_sdk_common::{
|
||||||
cancel::CancelCode,
|
cancel::CancelCode,
|
||||||
ShortAuthenticationString,
|
ShortAuthenticationString,
|
||||||
},
|
},
|
||||||
AnyMessageEvent, AnyMessageEventContent, AnyToDeviceEvent, AnyToDeviceEventContent,
|
AnyMessageEventContent, AnyToDeviceEventContent,
|
||||||
},
|
},
|
||||||
identifiers::{DeviceId, EventId, RoomId, UserId},
|
identifiers::{DeviceId, EventId, RoomId, UserId},
|
||||||
uuid::Uuid,
|
uuid::Uuid,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{FlowId, IdentitiesBeingVerified, VerificationResult};
|
use super::{
|
||||||
|
event_enums::{AnyVerificationContent, OwnedAcceptContent, StartContent},
|
||||||
|
FlowId, IdentitiesBeingVerified, VerificationResult,
|
||||||
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
identities::{ReadOnlyDevice, UserIdentities},
|
identities::{ReadOnlyDevice, UserIdentities},
|
||||||
olm::PrivateCrossSigningIdentity,
|
olm::PrivateCrossSigningIdentity,
|
||||||
|
@ -111,10 +113,10 @@ impl Sas {
|
||||||
let flow_id = inner_sas.verification_flow_id();
|
let flow_id = inner_sas.verification_flow_id();
|
||||||
|
|
||||||
let identities = IdentitiesBeingVerified {
|
let identities = IdentitiesBeingVerified {
|
||||||
private_identity: private_identity.clone(),
|
private_identity,
|
||||||
store: store.clone(),
|
store: store.clone(),
|
||||||
device_being_verified: other_device.clone(),
|
device_being_verified: other_device,
|
||||||
identity_being_verified: other_identity.clone(),
|
identity_being_verified: other_identity,
|
||||||
};
|
};
|
||||||
|
|
||||||
Sas {
|
Sas {
|
||||||
|
@ -142,7 +144,7 @@ impl Sas {
|
||||||
store: Arc<Box<dyn CryptoStore>>,
|
store: Arc<Box<dyn CryptoStore>>,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
transaction_id: Option<String>,
|
transaction_id: Option<String>,
|
||||||
) -> (Sas, StartContent) {
|
) -> (Sas, OutgoingContent) {
|
||||||
let (inner, content) = InnerSas::start(
|
let (inner, content) = InnerSas::start(
|
||||||
account.clone(),
|
account.clone(),
|
||||||
other_device.clone(),
|
other_device.clone(),
|
||||||
|
@ -181,7 +183,7 @@ impl Sas {
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
store: Arc<Box<dyn CryptoStore>>,
|
store: Arc<Box<dyn CryptoStore>>,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
) -> (Sas, StartContent) {
|
) -> (Sas, OutgoingContent) {
|
||||||
let (inner, content) = InnerSas::start_in_room(
|
let (inner, content) = InnerSas::start_in_room(
|
||||||
flow_id,
|
flow_id,
|
||||||
room_id,
|
room_id,
|
||||||
|
@ -214,18 +216,22 @@ impl Sas {
|
||||||
/// * `event` - The m.key.verification.start event that was sent to us by
|
/// * `event` - The m.key.verification.start event that was sent to us by
|
||||||
/// the other side.
|
/// the other side.
|
||||||
pub(crate) fn from_start_event(
|
pub(crate) fn from_start_event(
|
||||||
content: impl Into<StartContent>,
|
flow_id: FlowId,
|
||||||
|
content: &StartContent,
|
||||||
store: Arc<Box<dyn CryptoStore>>,
|
store: Arc<Box<dyn CryptoStore>>,
|
||||||
account: ReadOnlyAccount,
|
account: ReadOnlyAccount,
|
||||||
private_identity: PrivateCrossSigningIdentity,
|
private_identity: PrivateCrossSigningIdentity,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
|
started_from_request: bool,
|
||||||
) -> Result<Sas, OutgoingContent> {
|
) -> Result<Sas, OutgoingContent> {
|
||||||
let inner = InnerSas::from_start_event(
|
let inner = InnerSas::from_start_event(
|
||||||
account.clone(),
|
account.clone(),
|
||||||
other_device.clone(),
|
other_device.clone(),
|
||||||
|
flow_id,
|
||||||
content,
|
content,
|
||||||
other_identity.clone(),
|
other_identity.clone(),
|
||||||
|
started_from_request,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(Self::start_helper(
|
Ok(Self::start_helper(
|
||||||
|
@ -257,11 +263,11 @@ impl Sas {
|
||||||
settings: AcceptSettings,
|
settings: AcceptSettings,
|
||||||
) -> Option<OutgoingVerificationRequest> {
|
) -> Option<OutgoingVerificationRequest> {
|
||||||
self.inner.lock().unwrap().accept().map(|c| match settings.apply(c) {
|
self.inner.lock().unwrap().accept().map(|c| match settings.apply(c) {
|
||||||
AcceptContent::ToDevice(c) => {
|
OwnedAcceptContent::ToDevice(c) => {
|
||||||
let content = AnyToDeviceEventContent::KeyVerificationAccept(c);
|
let content = AnyToDeviceEventContent::KeyVerificationAccept(c);
|
||||||
self.content_to_request(content).into()
|
self.content_to_request(content).into()
|
||||||
}
|
}
|
||||||
AcceptContent::Room(room_id, content) => RoomMessageRequest {
|
OwnedAcceptContent::Room(room_id, content) => RoomMessageRequest {
|
||||||
room_id,
|
room_id,
|
||||||
txn_id: Uuid::new_v4(),
|
txn_id: Uuid::new_v4(),
|
||||||
content: AnyMessageEventContent::KeyVerificationAccept(content),
|
content: AnyMessageEventContent::KeyVerificationAccept(content),
|
||||||
|
@ -293,15 +299,10 @@ impl Sas {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mac_request = content.map(|c| match c {
|
let mac_request = content.map(|c| match c {
|
||||||
event_enums::MacContent::ToDevice(c) => {
|
OutgoingContent::ToDevice(c) => self.content_to_request(c).into(),
|
||||||
self.content_to_request(AnyToDeviceEventContent::KeyVerificationMac(c)).into()
|
OutgoingContent::Room(r, c) => {
|
||||||
|
RoomMessageRequest { room_id: r, txn_id: Uuid::new_v4(), content: 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 {
|
||||||
|
@ -337,15 +338,10 @@ impl Sas {
|
||||||
let (sas, content) = sas.cancel(code);
|
let (sas, content) = sas.cancel(code);
|
||||||
*guard = sas;
|
*guard = sas;
|
||||||
content.map(|c| match c {
|
content.map(|c| match c {
|
||||||
CancelContent::Room(room_id, content) => RoomMessageRequest {
|
OutgoingContent::Room(room_id, content) => {
|
||||||
room_id,
|
RoomMessageRequest { room_id, txn_id: Uuid::new_v4(), content }.into()
|
||||||
txn_id: Uuid::new_v4(),
|
|
||||||
content: AnyMessageEventContent::KeyVerificationCancel(content),
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
CancelContent::ToDevice(c) => {
|
|
||||||
self.content_to_request(AnyToDeviceEventContent::KeyVerificationCancel(c)).into()
|
|
||||||
}
|
}
|
||||||
|
OutgoingContent::ToDevice(c) => self.content_to_request(c).into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,19 +402,14 @@ impl Sas {
|
||||||
self.inner.lock().unwrap().decimals()
|
self.inner.lock().unwrap().decimals()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn receive_room_event(&self, event: &AnyMessageEvent) -> Option<OutgoingContent> {
|
pub(crate) fn receive_any_event(
|
||||||
|
&self,
|
||||||
|
sender: &UserId,
|
||||||
|
content: &AnyVerificationContent,
|
||||||
|
) -> 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();
|
||||||
let (sas, content) = sas.receive_room_event(event);
|
let (sas, content) = sas.receive_any_event(sender, content);
|
||||||
*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();
|
|
||||||
let (sas, content) = sas.receive_event(event);
|
|
||||||
*guard = sas;
|
*guard = sas;
|
||||||
|
|
||||||
content
|
content
|
||||||
|
@ -465,13 +456,16 @@ impl AcceptSettings {
|
||||||
Self { allowed_methods: methods }
|
Self { allowed_methods: methods }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply(self, mut content: AcceptContent) -> AcceptContent {
|
fn apply(self, mut content: OwnedAcceptContent) -> OwnedAcceptContent {
|
||||||
match &mut content {
|
match &mut content {
|
||||||
AcceptContent::ToDevice(AcceptToDeviceEventContent {
|
OwnedAcceptContent::ToDevice(AcceptToDeviceEventContent {
|
||||||
method: AcceptMethod::MSasV1(c),
|
method: AcceptMethod::MSasV1(c),
|
||||||
..
|
..
|
||||||
})
|
})
|
||||||
| AcceptContent::Room(_, AcceptEventContent { method: AcceptMethod::MSasV1(c), .. }) => {
|
| OwnedAcceptContent::Room(
|
||||||
|
_,
|
||||||
|
AcceptEventContent { method: AcceptMethod::MSasV1(c), .. },
|
||||||
|
) => {
|
||||||
c.short_authentication_string.retain(|sas| self.allowed_methods.contains(sas));
|
c.short_authentication_string.retain(|sas| self.allowed_methods.contains(sas));
|
||||||
content
|
content
|
||||||
}
|
}
|
||||||
|
@ -490,7 +484,10 @@ mod test {
|
||||||
use crate::{
|
use crate::{
|
||||||
olm::PrivateCrossSigningIdentity,
|
olm::PrivateCrossSigningIdentity,
|
||||||
store::{CryptoStore, MemoryStore},
|
store::{CryptoStore, MemoryStore},
|
||||||
verification::test::{get_content_from_request, wrap_any_to_device_content},
|
verification::{
|
||||||
|
event_enums::{AcceptContent, KeyContent, MacContent, StartContent},
|
||||||
|
sas::OutgoingContent,
|
||||||
|
},
|
||||||
ReadOnlyAccount, ReadOnlyDevice,
|
ReadOnlyAccount, ReadOnlyDevice,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -534,47 +531,51 @@ mod test {
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let flow_id = alice.flow_id().to_owned();
|
||||||
|
let content = StartContent::try_from(&content).unwrap();
|
||||||
|
|
||||||
let bob = Sas::from_start_event(
|
let bob = Sas::from_start_event(
|
||||||
content,
|
flow_id,
|
||||||
|
&content,
|
||||||
bob_store,
|
bob_store,
|
||||||
bob,
|
bob,
|
||||||
PrivateCrossSigningIdentity::empty(bob_id()),
|
PrivateCrossSigningIdentity::empty(bob_id()),
|
||||||
alice_device,
|
alice_device,
|
||||||
None,
|
None,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let event = wrap_any_to_device_content(
|
|
||||||
bob.user_id(),
|
|
||||||
get_content_from_request(&bob.accept().unwrap()),
|
|
||||||
);
|
|
||||||
|
|
||||||
let content = alice.receive_event(&event);
|
let request = bob.accept().unwrap();
|
||||||
|
let content = OutgoingContent::try_from(request).unwrap();
|
||||||
|
let content = AcceptContent::try_from(&content).unwrap();
|
||||||
|
|
||||||
|
let content = alice.receive_any_event(bob.user_id(), &content.into()).unwrap();
|
||||||
|
|
||||||
assert!(!alice.can_be_presented());
|
assert!(!alice.can_be_presented());
|
||||||
assert!(!bob.can_be_presented());
|
assert!(!bob.can_be_presented());
|
||||||
|
|
||||||
let event = wrap_any_to_device_content(alice.user_id(), content.unwrap());
|
let content = KeyContent::try_from(&content).unwrap();
|
||||||
let event = wrap_any_to_device_content(bob.user_id(), bob.receive_event(&event).unwrap());
|
let content = bob.receive_any_event(alice.user_id(), &content.into()).unwrap();
|
||||||
|
|
||||||
assert!(bob.can_be_presented());
|
assert!(bob.can_be_presented());
|
||||||
|
|
||||||
alice.receive_event(&event);
|
let content = KeyContent::try_from(&content).unwrap();
|
||||||
|
alice.receive_any_event(bob.user_id(), &content.into());
|
||||||
assert!(alice.can_be_presented());
|
assert!(alice.can_be_presented());
|
||||||
|
|
||||||
assert_eq!(alice.emoji().unwrap(), bob.emoji().unwrap());
|
assert_eq!(alice.emoji().unwrap(), bob.emoji().unwrap());
|
||||||
assert_eq!(alice.decimals().unwrap(), bob.decimals().unwrap());
|
assert_eq!(alice.decimals().unwrap(), bob.decimals().unwrap());
|
||||||
|
|
||||||
let event = wrap_any_to_device_content(
|
let request = alice.confirm().await.unwrap().0.unwrap();
|
||||||
alice.user_id(),
|
let content = OutgoingContent::try_from(request).unwrap();
|
||||||
get_content_from_request(&alice.confirm().await.unwrap().0.unwrap()),
|
let content = MacContent::try_from(&content).unwrap();
|
||||||
);
|
bob.receive_any_event(alice.user_id(), &content.into());
|
||||||
bob.receive_event(&event);
|
|
||||||
|
|
||||||
let event = wrap_any_to_device_content(
|
let request = bob.confirm().await.unwrap().0.unwrap();
|
||||||
bob.user_id(),
|
let content = OutgoingContent::try_from(request).unwrap();
|
||||||
get_content_from_request(&bob.confirm().await.unwrap().0.unwrap()),
|
let content = MacContent::try_from(&content).unwrap();
|
||||||
);
|
alice.receive_any_event(bob.user_id(), &content.into());
|
||||||
alice.receive_event(&event);
|
|
||||||
|
|
||||||
assert!(alice.verified_devices().unwrap().contains(&alice.other_device()));
|
assert!(alice.verified_devices().unwrap().contains(&alice.other_device()));
|
||||||
assert!(bob.verified_devices().unwrap().contains(&bob.other_device()));
|
assert!(bob.verified_devices().unwrap().contains(&bob.other_device()));
|
||||||
|
|
|
@ -20,20 +20,23 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
events::key::verification::{
|
events::{
|
||||||
accept::{
|
key::verification::{
|
||||||
AcceptEventContent, AcceptMethod, AcceptToDeviceEventContent,
|
accept::{
|
||||||
SasV1Content as AcceptV1Content, SasV1ContentInit as AcceptV1ContentInit,
|
AcceptEventContent, AcceptMethod, AcceptToDeviceEventContent,
|
||||||
|
SasV1Content as AcceptV1Content, SasV1ContentInit as AcceptV1ContentInit,
|
||||||
|
},
|
||||||
|
cancel::CancelCode,
|
||||||
|
done::{DoneEventContent, DoneToDeviceEventContent},
|
||||||
|
key::{KeyEventContent, KeyToDeviceEventContent},
|
||||||
|
start::{
|
||||||
|
SasV1Content, SasV1ContentInit, StartEventContent, StartMethod,
|
||||||
|
StartToDeviceEventContent,
|
||||||
|
},
|
||||||
|
HashAlgorithm, KeyAgreementProtocol, MessageAuthenticationCode, Relation,
|
||||||
|
ShortAuthenticationString, VerificationMethod,
|
||||||
},
|
},
|
||||||
cancel::CancelCode,
|
AnyMessageEventContent, AnyToDeviceEventContent,
|
||||||
done::DoneEventContent,
|
|
||||||
key::{KeyEventContent, KeyToDeviceEventContent},
|
|
||||||
start::{
|
|
||||||
SasV1Content, SasV1ContentInit, StartEventContent, StartMethod,
|
|
||||||
StartToDeviceEventContent,
|
|
||||||
},
|
|
||||||
HashAlgorithm, KeyAgreementProtocol, MessageAuthenticationCode, Relation,
|
|
||||||
ShortAuthenticationString, VerificationMethod,
|
|
||||||
},
|
},
|
||||||
identifiers::{DeviceId, EventId, RoomId, UserId},
|
identifiers::{DeviceId, EventId, RoomId, UserId},
|
||||||
uuid::Uuid,
|
uuid::Uuid,
|
||||||
|
@ -42,17 +45,21 @@ use olm_rs::sas::OlmSas;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
event_enums::{
|
|
||||||
AcceptContent, CancelContent, DoneContent, KeyContent, MacContent, StartContent,
|
|
||||||
},
|
|
||||||
helpers::{
|
helpers::{
|
||||||
calculate_commitment, get_decimal, get_emoji, get_emoji_index, get_mac_content,
|
calculate_commitment, get_decimal, get_emoji, get_emoji_index, get_mac_content,
|
||||||
receive_mac_event, SasIds,
|
receive_mac_event, SasIds,
|
||||||
},
|
},
|
||||||
|
OutgoingContent,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
identities::{ReadOnlyDevice, UserIdentities},
|
identities::{ReadOnlyDevice, UserIdentities},
|
||||||
verification::{Cancelled, Done, FlowId},
|
verification::{
|
||||||
|
event_enums::{
|
||||||
|
AcceptContent, DoneContent, KeyContent, MacContent, OwnedAcceptContent,
|
||||||
|
OwnedStartContent, StartContent,
|
||||||
|
},
|
||||||
|
Cancelled, Done, FlowId,
|
||||||
|
},
|
||||||
ReadOnlyAccount,
|
ReadOnlyAccount,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -196,6 +203,9 @@ pub struct SasState<S: Clone> {
|
||||||
|
|
||||||
/// The SAS state we're in.
|
/// The SAS state we're in.
|
||||||
pub state: Arc<S>,
|
pub state: Arc<S>,
|
||||||
|
|
||||||
|
/// Did the SAS verification start from a `m.verification.request`.
|
||||||
|
pub started_from_request: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(tarpaulin_include))]
|
#[cfg(not(tarpaulin_include))]
|
||||||
|
@ -227,7 +237,7 @@ pub struct Started {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Accepted {
|
pub struct Accepted {
|
||||||
pub accepted_protocols: Arc<AcceptedProtocols>,
|
pub accepted_protocols: Arc<AcceptedProtocols>,
|
||||||
start_content: Arc<StartContent>,
|
start_content: Arc<OwnedStartContent>,
|
||||||
commitment: String,
|
commitment: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,6 +306,7 @@ impl<S: Clone> SasState<S> {
|
||||||
last_event_time: self.last_event_time,
|
last_event_time: self.last_event_time,
|
||||||
verification_flow_id: self.verification_flow_id,
|
verification_flow_id: self.verification_flow_id,
|
||||||
state: Arc::new(Cancelled::new(cancel_code)),
|
state: Arc::new(Cancelled::new(cancel_code)),
|
||||||
|
started_from_request: self.started_from_request,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,9 +355,10 @@ impl SasState<Created> {
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
transaction_id: Option<String>,
|
transaction_id: Option<String>,
|
||||||
) -> SasState<Created> {
|
) -> SasState<Created> {
|
||||||
|
let started_from_request = transaction_id.is_some();
|
||||||
let flow_id =
|
let flow_id =
|
||||||
FlowId::ToDevice(transaction_id.unwrap_or_else(|| Uuid::new_v4().to_string()));
|
FlowId::ToDevice(transaction_id.unwrap_or_else(|| Uuid::new_v4().to_string()));
|
||||||
Self::new_helper(flow_id, account, other_device, other_identity)
|
Self::new_helper(flow_id, account, other_device, other_identity, started_from_request)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new SAS in-room verification flow.
|
/// Create a new SAS in-room verification flow.
|
||||||
|
@ -369,7 +381,7 @@ impl SasState<Created> {
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
) -> SasState<Created> {
|
) -> SasState<Created> {
|
||||||
let flow_id = FlowId::InRoom(room_id, event_id);
|
let flow_id = FlowId::InRoom(room_id, event_id);
|
||||||
Self::new_helper(flow_id, account, other_device, other_identity)
|
Self::new_helper(flow_id, account, other_device, other_identity, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_helper(
|
fn new_helper(
|
||||||
|
@ -377,6 +389,7 @@ impl SasState<Created> {
|
||||||
account: ReadOnlyAccount,
|
account: ReadOnlyAccount,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
|
started_from_request: bool,
|
||||||
) -> SasState<Created> {
|
) -> SasState<Created> {
|
||||||
SasState {
|
SasState {
|
||||||
inner: Arc::new(Mutex::new(OlmSas::new())),
|
inner: Arc::new(Mutex::new(OlmSas::new())),
|
||||||
|
@ -385,6 +398,7 @@ impl SasState<Created> {
|
||||||
|
|
||||||
creation_time: Arc::new(Instant::now()),
|
creation_time: Arc::new(Instant::now()),
|
||||||
last_event_time: Arc::new(Instant::now()),
|
last_event_time: Arc::new(Instant::now()),
|
||||||
|
started_from_request,
|
||||||
|
|
||||||
state: Arc::new(Created {
|
state: Arc::new(Created {
|
||||||
protocol_definitions: SasV1ContentInit {
|
protocol_definitions: SasV1ContentInit {
|
||||||
|
@ -397,9 +411,9 @@ impl SasState<Created> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_content(&self) -> StartContent {
|
pub fn as_content(&self) -> OwnedStartContent {
|
||||||
match self.verification_flow_id.as_ref() {
|
match self.verification_flow_id.as_ref() {
|
||||||
FlowId::ToDevice(s) => StartContent::ToDevice(StartToDeviceEventContent::new(
|
FlowId::ToDevice(s) => OwnedStartContent::ToDevice(StartToDeviceEventContent::new(
|
||||||
self.device_id().into(),
|
self.device_id().into(),
|
||||||
s.to_string(),
|
s.to_string(),
|
||||||
StartMethod::SasV1(
|
StartMethod::SasV1(
|
||||||
|
@ -407,7 +421,7 @@ impl SasState<Created> {
|
||||||
.expect("Invalid initial protocol definitions."),
|
.expect("Invalid initial protocol definitions."),
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
FlowId::InRoom(r, e) => StartContent::Room(
|
FlowId::InRoom(r, e) => OwnedStartContent::Room(
|
||||||
r.clone(),
|
r.clone(),
|
||||||
StartEventContent::new(
|
StartEventContent::new(
|
||||||
self.device_id().into(),
|
self.device_id().into(),
|
||||||
|
@ -431,11 +445,9 @@ impl SasState<Created> {
|
||||||
pub fn into_accepted(
|
pub fn into_accepted(
|
||||||
self,
|
self,
|
||||||
sender: &UserId,
|
sender: &UserId,
|
||||||
content: impl Into<AcceptContent>,
|
content: &AcceptContent,
|
||||||
) -> Result<SasState<Accepted>, SasState<Cancelled>> {
|
) -> Result<SasState<Accepted>, SasState<Cancelled>> {
|
||||||
let content = content.into();
|
self.check_event(&sender, content.flow_id()).map_err(|c| self.clone().cancel(c))?;
|
||||||
self.check_event(&sender, content.flow_id().as_str())
|
|
||||||
.map_err(|c| self.clone().cancel(c))?;
|
|
||||||
|
|
||||||
if let AcceptMethod::MSasV1(content) = content.method() {
|
if let AcceptMethod::MSasV1(content) = content.method() {
|
||||||
let accepted_protocols =
|
let accepted_protocols =
|
||||||
|
@ -449,6 +461,7 @@ impl SasState<Created> {
|
||||||
verification_flow_id: self.verification_flow_id,
|
verification_flow_id: self.verification_flow_id,
|
||||||
creation_time: self.creation_time,
|
creation_time: self.creation_time,
|
||||||
last_event_time: self.last_event_time,
|
last_event_time: self.last_event_time,
|
||||||
|
started_from_request: self.started_from_request,
|
||||||
state: Arc::new(Accepted {
|
state: Arc::new(Accepted {
|
||||||
start_content,
|
start_content,
|
||||||
commitment: content.commitment.clone(),
|
commitment: content.commitment.clone(),
|
||||||
|
@ -479,22 +492,18 @@ impl SasState<Started> {
|
||||||
account: ReadOnlyAccount,
|
account: ReadOnlyAccount,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
content: impl Into<StartContent>,
|
flow_id: FlowId,
|
||||||
) -> Result<SasState<Started>, SasState<Cancelled>> {
|
|
||||||
Self::from_start_helper(account, other_device, other_identity, &content.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_start_helper(
|
|
||||||
account: ReadOnlyAccount,
|
|
||||||
other_device: ReadOnlyDevice,
|
|
||||||
other_identity: Option<UserIdentities>,
|
|
||||||
content: &StartContent,
|
content: &StartContent,
|
||||||
|
started_from_request: bool,
|
||||||
) -> Result<SasState<Started>, SasState<Cancelled>> {
|
) -> Result<SasState<Started>, SasState<Cancelled>> {
|
||||||
|
let flow_id = Arc::new(flow_id);
|
||||||
|
|
||||||
let canceled = || SasState {
|
let canceled = || SasState {
|
||||||
inner: Arc::new(Mutex::new(OlmSas::new())),
|
inner: Arc::new(Mutex::new(OlmSas::new())),
|
||||||
|
|
||||||
creation_time: Arc::new(Instant::now()),
|
creation_time: Arc::new(Instant::now()),
|
||||||
last_event_time: Arc::new(Instant::now()),
|
last_event_time: Arc::new(Instant::now()),
|
||||||
|
started_from_request,
|
||||||
|
|
||||||
ids: SasIds {
|
ids: SasIds {
|
||||||
account: account.clone(),
|
account: account.clone(),
|
||||||
|
@ -502,7 +511,7 @@ impl SasState<Started> {
|
||||||
other_identity: other_identity.clone(),
|
other_identity: other_identity.clone(),
|
||||||
},
|
},
|
||||||
|
|
||||||
verification_flow_id: content.flow_id().into(),
|
verification_flow_id: flow_id.clone(),
|
||||||
state: Arc::new(Cancelled::new(CancelCode::UnknownMethod)),
|
state: Arc::new(Cancelled::new(CancelCode::UnknownMethod)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -510,7 +519,7 @@ impl SasState<Started> {
|
||||||
let sas = OlmSas::new();
|
let sas = OlmSas::new();
|
||||||
|
|
||||||
let pubkey = sas.public_key();
|
let pubkey = sas.public_key();
|
||||||
let commitment = calculate_commitment(&pubkey, content.clone());
|
let commitment = calculate_commitment(&pubkey, content);
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Calculated commitment for pubkey {} and content {:?} {}",
|
"Calculated commitment for pubkey {} and content {:?} {}",
|
||||||
|
@ -525,8 +534,9 @@ impl SasState<Started> {
|
||||||
|
|
||||||
creation_time: Arc::new(Instant::now()),
|
creation_time: Arc::new(Instant::now()),
|
||||||
last_event_time: Arc::new(Instant::now()),
|
last_event_time: Arc::new(Instant::now()),
|
||||||
|
started_from_request,
|
||||||
|
|
||||||
verification_flow_id: content.flow_id().into(),
|
verification_flow_id: flow_id,
|
||||||
|
|
||||||
state: Arc::new(Started {
|
state: Arc::new(Started {
|
||||||
accepted_protocols: accepted_protocols.into(),
|
accepted_protocols: accepted_protocols.into(),
|
||||||
|
@ -548,7 +558,7 @@ impl SasState<Started> {
|
||||||
/// This should be sent out automatically if the SAS verification flow has
|
/// This should be sent out automatically if the SAS verification flow has
|
||||||
/// been started because of a
|
/// been started because of a
|
||||||
/// m.key.verification.request -> m.key.verification.ready flow.
|
/// m.key.verification.request -> m.key.verification.ready flow.
|
||||||
pub fn as_content(&self) -> AcceptContent {
|
pub fn as_content(&self) -> OwnedAcceptContent {
|
||||||
let method = AcceptMethod::MSasV1(
|
let method = AcceptMethod::MSasV1(
|
||||||
AcceptV1ContentInit {
|
AcceptV1ContentInit {
|
||||||
commitment: self.state.commitment.clone(),
|
commitment: self.state.commitment.clone(),
|
||||||
|
@ -591,12 +601,9 @@ impl SasState<Started> {
|
||||||
pub fn into_key_received(
|
pub fn into_key_received(
|
||||||
self,
|
self,
|
||||||
sender: &UserId,
|
sender: &UserId,
|
||||||
content: impl Into<KeyContent>,
|
content: &KeyContent,
|
||||||
) -> Result<SasState<KeyReceived>, SasState<Cancelled>> {
|
) -> Result<SasState<KeyReceived>, SasState<Cancelled>> {
|
||||||
let content = content.into();
|
self.check_event(&sender, &content.flow_id()).map_err(|c| self.clone().cancel(c))?;
|
||||||
|
|
||||||
self.check_event(&sender, &content.flow_id().as_str())
|
|
||||||
.map_err(|c| self.clone().cancel(c))?;
|
|
||||||
|
|
||||||
let their_pubkey = content.public_key().to_owned();
|
let their_pubkey = content.public_key().to_owned();
|
||||||
|
|
||||||
|
@ -612,6 +619,7 @@ impl SasState<Started> {
|
||||||
verification_flow_id: self.verification_flow_id,
|
verification_flow_id: self.verification_flow_id,
|
||||||
creation_time: self.creation_time,
|
creation_time: self.creation_time,
|
||||||
last_event_time: self.last_event_time,
|
last_event_time: self.last_event_time,
|
||||||
|
started_from_request: self.started_from_request,
|
||||||
state: Arc::new(KeyReceived {
|
state: Arc::new(KeyReceived {
|
||||||
we_started: false,
|
we_started: false,
|
||||||
their_pubkey,
|
their_pubkey,
|
||||||
|
@ -633,15 +641,14 @@ impl SasState<Accepted> {
|
||||||
pub fn into_key_received(
|
pub fn into_key_received(
|
||||||
self,
|
self,
|
||||||
sender: &UserId,
|
sender: &UserId,
|
||||||
content: impl Into<KeyContent>,
|
content: &KeyContent,
|
||||||
) -> Result<SasState<KeyReceived>, SasState<Cancelled>> {
|
) -> Result<SasState<KeyReceived>, SasState<Cancelled>> {
|
||||||
let content = content.into();
|
self.check_event(&sender, content.flow_id()).map_err(|c| self.clone().cancel(c))?;
|
||||||
|
|
||||||
self.check_event(&sender, content.flow_id().as_str())
|
let commitment = calculate_commitment(
|
||||||
.map_err(|c| self.clone().cancel(c))?;
|
content.public_key(),
|
||||||
|
&self.state.start_content.as_start_content(),
|
||||||
let commitment =
|
);
|
||||||
calculate_commitment(content.public_key(), 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))
|
||||||
|
@ -660,6 +667,7 @@ impl SasState<Accepted> {
|
||||||
verification_flow_id: self.verification_flow_id,
|
verification_flow_id: self.verification_flow_id,
|
||||||
creation_time: self.creation_time,
|
creation_time: self.creation_time,
|
||||||
last_event_time: self.last_event_time,
|
last_event_time: self.last_event_time,
|
||||||
|
started_from_request: self.started_from_request,
|
||||||
state: Arc::new(KeyReceived {
|
state: Arc::new(KeyReceived {
|
||||||
their_pubkey,
|
their_pubkey,
|
||||||
we_started: true,
|
we_started: true,
|
||||||
|
@ -672,19 +680,21 @@ 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) -> KeyContent {
|
pub fn as_content(&self) -> OutgoingContent {
|
||||||
match &*self.verification_flow_id {
|
match &*self.verification_flow_id {
|
||||||
FlowId::ToDevice(s) => KeyToDeviceEventContent {
|
FlowId::ToDevice(s) => {
|
||||||
transaction_id: s.to_string(),
|
AnyToDeviceEventContent::KeyVerificationKey(KeyToDeviceEventContent {
|
||||||
key: self.inner.lock().unwrap().public_key(),
|
transaction_id: s.to_string(),
|
||||||
|
key: self.inner.lock().unwrap().public_key(),
|
||||||
|
})
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
.into(),
|
|
||||||
FlowId::InRoom(r, e) => (
|
FlowId::InRoom(r, e) => (
|
||||||
r.clone(),
|
r.clone(),
|
||||||
KeyEventContent::new(
|
AnyMessageEventContent::KeyVerificationKey(KeyEventContent::new(
|
||||||
self.inner.lock().unwrap().public_key(),
|
self.inner.lock().unwrap().public_key(),
|
||||||
Relation::new(e.clone()),
|
Relation::new(e.clone()),
|
||||||
),
|
)),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
}
|
}
|
||||||
|
@ -696,19 +706,21 @@ 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) -> KeyContent {
|
pub fn as_content(&self) -> OutgoingContent {
|
||||||
match &*self.verification_flow_id {
|
match &*self.verification_flow_id {
|
||||||
FlowId::ToDevice(s) => KeyToDeviceEventContent {
|
FlowId::ToDevice(s) => {
|
||||||
transaction_id: s.to_string(),
|
AnyToDeviceEventContent::KeyVerificationKey(KeyToDeviceEventContent {
|
||||||
key: self.inner.lock().unwrap().public_key(),
|
transaction_id: s.to_string(),
|
||||||
|
key: self.inner.lock().unwrap().public_key(),
|
||||||
|
})
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
.into(),
|
|
||||||
FlowId::InRoom(r, e) => (
|
FlowId::InRoom(r, e) => (
|
||||||
r.clone(),
|
r.clone(),
|
||||||
KeyEventContent::new(
|
AnyMessageEventContent::KeyVerificationKey(KeyEventContent::new(
|
||||||
self.inner.lock().unwrap().public_key(),
|
self.inner.lock().unwrap().public_key(),
|
||||||
Relation::new(e.clone()),
|
Relation::new(e.clone()),
|
||||||
),
|
)),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
}
|
}
|
||||||
|
@ -766,12 +778,9 @@ impl SasState<KeyReceived> {
|
||||||
pub fn into_mac_received(
|
pub fn into_mac_received(
|
||||||
self,
|
self,
|
||||||
sender: &UserId,
|
sender: &UserId,
|
||||||
content: impl Into<MacContent>,
|
content: &MacContent,
|
||||||
) -> Result<SasState<MacReceived>, SasState<Cancelled>> {
|
) -> Result<SasState<MacReceived>, SasState<Cancelled>> {
|
||||||
let content = content.into();
|
self.check_event(&sender, content.flow_id()).map_err(|c| self.clone().cancel(c))?;
|
||||||
|
|
||||||
self.check_event(&sender, content.flow_id().as_str())
|
|
||||||
.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(),
|
||||||
|
@ -788,6 +797,7 @@ impl SasState<KeyReceived> {
|
||||||
creation_time: self.creation_time,
|
creation_time: self.creation_time,
|
||||||
last_event_time: self.last_event_time,
|
last_event_time: self.last_event_time,
|
||||||
ids: self.ids,
|
ids: self.ids,
|
||||||
|
started_from_request: self.started_from_request,
|
||||||
state: Arc::new(MacReceived {
|
state: Arc::new(MacReceived {
|
||||||
we_started: self.state.we_started,
|
we_started: self.state.we_started,
|
||||||
their_pubkey: self.state.their_pubkey.clone(),
|
their_pubkey: self.state.their_pubkey.clone(),
|
||||||
|
@ -805,6 +815,7 @@ impl SasState<KeyReceived> {
|
||||||
pub fn confirm(self) -> SasState<Confirmed> {
|
pub fn confirm(self) -> SasState<Confirmed> {
|
||||||
SasState {
|
SasState {
|
||||||
inner: self.inner,
|
inner: self.inner,
|
||||||
|
started_from_request: self.started_from_request,
|
||||||
verification_flow_id: self.verification_flow_id,
|
verification_flow_id: self.verification_flow_id,
|
||||||
creation_time: self.creation_time,
|
creation_time: self.creation_time,
|
||||||
last_event_time: self.last_event_time,
|
last_event_time: self.last_event_time,
|
||||||
|
@ -827,12 +838,9 @@ impl SasState<Confirmed> {
|
||||||
pub fn into_done(
|
pub fn into_done(
|
||||||
self,
|
self,
|
||||||
sender: &UserId,
|
sender: &UserId,
|
||||||
content: impl Into<MacContent>,
|
content: &MacContent,
|
||||||
) -> Result<SasState<Done>, SasState<Cancelled>> {
|
) -> Result<SasState<Done>, SasState<Cancelled>> {
|
||||||
let content = content.into();
|
self.check_event(sender, content.flow_id()).map_err(|c| self.clone().cancel(c))?;
|
||||||
|
|
||||||
self.check_event(&sender, &content.flow_id().as_str())
|
|
||||||
.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(),
|
||||||
|
@ -848,6 +856,7 @@ impl SasState<Confirmed> {
|
||||||
creation_time: self.creation_time,
|
creation_time: self.creation_time,
|
||||||
last_event_time: self.last_event_time,
|
last_event_time: self.last_event_time,
|
||||||
verification_flow_id: self.verification_flow_id,
|
verification_flow_id: self.verification_flow_id,
|
||||||
|
started_from_request: self.started_from_request,
|
||||||
ids: self.ids,
|
ids: self.ids,
|
||||||
|
|
||||||
state: Arc::new(Done {
|
state: Arc::new(Done {
|
||||||
|
@ -869,12 +878,9 @@ impl SasState<Confirmed> {
|
||||||
pub fn into_waiting_for_done(
|
pub fn into_waiting_for_done(
|
||||||
self,
|
self,
|
||||||
sender: &UserId,
|
sender: &UserId,
|
||||||
content: impl Into<MacContent>,
|
content: &MacContent,
|
||||||
) -> Result<SasState<WaitingForDone>, SasState<Cancelled>> {
|
) -> Result<SasState<WaitingForDone>, SasState<Cancelled>> {
|
||||||
let content = content.into();
|
self.check_event(&sender, &content.flow_id()).map_err(|c| self.clone().cancel(c))?;
|
||||||
|
|
||||||
self.check_event(&sender, &content.flow_id().as_str())
|
|
||||||
.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(),
|
||||||
|
@ -890,6 +896,7 @@ impl SasState<Confirmed> {
|
||||||
creation_time: self.creation_time,
|
creation_time: self.creation_time,
|
||||||
last_event_time: self.last_event_time,
|
last_event_time: self.last_event_time,
|
||||||
verification_flow_id: self.verification_flow_id,
|
verification_flow_id: self.verification_flow_id,
|
||||||
|
started_from_request: self.started_from_request,
|
||||||
ids: self.ids,
|
ids: self.ids,
|
||||||
|
|
||||||
state: Arc::new(WaitingForDone {
|
state: Arc::new(WaitingForDone {
|
||||||
|
@ -902,7 +909,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) -> MacContent {
|
pub fn as_content(&self) -> OutgoingContent {
|
||||||
get_mac_content(&self.inner.lock().unwrap(), &self.ids, &self.verification_flow_id)
|
get_mac_content(&self.inner.lock().unwrap(), &self.ids, &self.verification_flow_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -917,6 +924,7 @@ impl SasState<MacReceived> {
|
||||||
inner: self.inner,
|
inner: self.inner,
|
||||||
verification_flow_id: self.verification_flow_id,
|
verification_flow_id: self.verification_flow_id,
|
||||||
creation_time: self.creation_time,
|
creation_time: self.creation_time,
|
||||||
|
started_from_request: self.started_from_request,
|
||||||
last_event_time: self.last_event_time,
|
last_event_time: self.last_event_time,
|
||||||
ids: self.ids,
|
ids: self.ids,
|
||||||
state: Arc::new(Done {
|
state: Arc::new(Done {
|
||||||
|
@ -937,6 +945,7 @@ impl SasState<MacReceived> {
|
||||||
inner: self.inner,
|
inner: self.inner,
|
||||||
verification_flow_id: self.verification_flow_id,
|
verification_flow_id: self.verification_flow_id,
|
||||||
creation_time: self.creation_time,
|
creation_time: self.creation_time,
|
||||||
|
started_from_request: self.started_from_request,
|
||||||
last_event_time: self.last_event_time,
|
last_event_time: self.last_event_time,
|
||||||
ids: self.ids,
|
ids: self.ids,
|
||||||
state: Arc::new(WaitingForDone {
|
state: Arc::new(WaitingForDone {
|
||||||
|
@ -994,18 +1003,23 @@ impl SasState<WaitingForDone> {
|
||||||
///
|
///
|
||||||
/// 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) -> MacContent {
|
pub fn as_content(&self) -> OutgoingContent {
|
||||||
get_mac_content(&self.inner.lock().unwrap(), &self.ids, &self.verification_flow_id)
|
get_mac_content(&self.inner.lock().unwrap(), &self.ids, &self.verification_flow_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn done_content(&self) -> DoneContent {
|
pub fn done_content(&self) -> OutgoingContent {
|
||||||
match self.verification_flow_id.as_ref() {
|
match self.verification_flow_id.as_ref() {
|
||||||
FlowId::ToDevice(_) => {
|
FlowId::ToDevice(t) => AnyToDeviceEventContent::KeyVerificationDone(
|
||||||
unreachable!("The done content isn't supported yet for to-device verifications")
|
DoneToDeviceEventContent::new(t.to_owned()),
|
||||||
}
|
)
|
||||||
FlowId::InRoom(r, e) => {
|
.into(),
|
||||||
(r.clone(), DoneEventContent::new(Relation::new(e.clone()))).into()
|
FlowId::InRoom(r, e) => (
|
||||||
}
|
r.clone(),
|
||||||
|
AnyMessageEventContent::KeyVerificationDone(DoneEventContent::new(Relation::new(
|
||||||
|
e.clone(),
|
||||||
|
))),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1019,18 +1033,16 @@ impl SasState<WaitingForDone> {
|
||||||
pub fn into_done(
|
pub fn into_done(
|
||||||
self,
|
self,
|
||||||
sender: &UserId,
|
sender: &UserId,
|
||||||
content: impl Into<DoneContent>,
|
content: &DoneContent,
|
||||||
) -> Result<SasState<Done>, SasState<Cancelled>> {
|
) -> Result<SasState<Done>, SasState<Cancelled>> {
|
||||||
let content = content.into();
|
self.check_event(&sender, content.flow_id()).map_err(|c| self.clone().cancel(c))?;
|
||||||
|
|
||||||
self.check_event(&sender, &content.flow_id().as_str())
|
|
||||||
.map_err(|c| self.clone().cancel(c))?;
|
|
||||||
|
|
||||||
Ok(SasState {
|
Ok(SasState {
|
||||||
inner: self.inner,
|
inner: self.inner,
|
||||||
creation_time: self.creation_time,
|
creation_time: self.creation_time,
|
||||||
last_event_time: self.last_event_time,
|
last_event_time: self.last_event_time,
|
||||||
verification_flow_id: self.verification_flow_id,
|
verification_flow_id: self.verification_flow_id,
|
||||||
|
started_from_request: self.started_from_request,
|
||||||
ids: self.ids,
|
ids: self.ids,
|
||||||
|
|
||||||
state: Arc::new(Done {
|
state: Arc::new(Done {
|
||||||
|
@ -1046,18 +1058,23 @@ 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) -> MacContent {
|
pub fn as_content(&self) -> OutgoingContent {
|
||||||
get_mac_content(&self.inner.lock().unwrap(), &self.ids, &self.verification_flow_id)
|
get_mac_content(&self.inner.lock().unwrap(), &self.ids, &self.verification_flow_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn done_content(&self) -> DoneContent {
|
pub fn done_content(&self) -> OutgoingContent {
|
||||||
match self.verification_flow_id.as_ref() {
|
match self.verification_flow_id.as_ref() {
|
||||||
FlowId::ToDevice(_) => {
|
FlowId::ToDevice(t) => AnyToDeviceEventContent::KeyVerificationDone(
|
||||||
unreachable!("The done content isn't supported yet for to-device verifications")
|
DoneToDeviceEventContent::new(t.to_owned()),
|
||||||
}
|
)
|
||||||
FlowId::InRoom(r, e) => {
|
.into(),
|
||||||
(r.clone(), DoneEventContent::new(Relation::new(e.clone()))).into()
|
FlowId::InRoom(r, e) => (
|
||||||
}
|
r.clone(),
|
||||||
|
AnyMessageEventContent::KeyVerificationDone(DoneEventContent::new(Relation::new(
|
||||||
|
e.clone(),
|
||||||
|
))),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1073,7 +1090,7 @@ impl SasState<Done> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SasState<Cancelled> {
|
impl SasState<Cancelled> {
|
||||||
pub fn as_content(&self) -> CancelContent {
|
pub fn as_content(&self) -> OutgoingContent {
|
||||||
self.state.as_content(&self.verification_flow_id)
|
self.state.as_content(&self.verification_flow_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1092,7 +1109,7 @@ mod test {
|
||||||
|
|
||||||
use super::{Accepted, Created, SasState, Started};
|
use super::{Accepted, Created, SasState, Started};
|
||||||
use crate::{
|
use crate::{
|
||||||
verification::sas::{event_enums::AcceptContent, StartContent},
|
verification::event_enums::{AcceptContent, KeyContent, MacContent, StartContent},
|
||||||
ReadOnlyAccount, ReadOnlyDevice,
|
ReadOnlyAccount, ReadOnlyDevice,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1122,9 +1139,16 @@ mod test {
|
||||||
let alice_sas = SasState::<Created>::new(alice.clone(), bob_device, None, None);
|
let alice_sas = SasState::<Created>::new(alice.clone(), bob_device, None, None);
|
||||||
|
|
||||||
let start_content = alice_sas.as_content();
|
let start_content = alice_sas.as_content();
|
||||||
|
let flow_id = start_content.flow_id();
|
||||||
|
|
||||||
let bob_sas =
|
let bob_sas = SasState::<Started>::from_start_event(
|
||||||
SasState::<Started>::from_start_event(bob.clone(), alice_device, None, start_content);
|
bob.clone(),
|
||||||
|
alice_device,
|
||||||
|
None,
|
||||||
|
flow_id,
|
||||||
|
&start_content.as_start_content(),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
(alice_sas, bob_sas.unwrap())
|
(alice_sas, bob_sas.unwrap())
|
||||||
}
|
}
|
||||||
|
@ -1137,10 +1161,10 @@ mod test {
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn sas_accept() {
|
async fn sas_accept() {
|
||||||
let (alice, bob) = get_sas_pair().await;
|
let (alice, bob) = get_sas_pair().await;
|
||||||
|
let content = bob.as_content();
|
||||||
|
let content = AcceptContent::from(&content);
|
||||||
|
|
||||||
let event = bob.as_content();
|
alice.into_accepted(bob.user_id(), &content).unwrap();
|
||||||
|
|
||||||
alice.into_accepted(bob.user_id(), event).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
@ -1148,15 +1172,18 @@ mod test {
|
||||||
let (alice, bob) = get_sas_pair().await;
|
let (alice, bob) = get_sas_pair().await;
|
||||||
|
|
||||||
let content = bob.as_content();
|
let content = bob.as_content();
|
||||||
|
let content = AcceptContent::from(&content);
|
||||||
|
|
||||||
let alice: SasState<Accepted> = alice.into_accepted(bob.user_id(), content).unwrap();
|
let alice: SasState<Accepted> = alice.into_accepted(bob.user_id(), &content).unwrap();
|
||||||
let content = alice.as_content();
|
let content = alice.as_content();
|
||||||
|
let content = KeyContent::try_from(&content).unwrap();
|
||||||
|
|
||||||
let bob = bob.into_key_received(alice.user_id(), content).unwrap();
|
let bob = bob.into_key_received(alice.user_id(), &content).unwrap();
|
||||||
|
|
||||||
let content = bob.as_content();
|
let content = bob.as_content();
|
||||||
|
let content = KeyContent::try_from(&content).unwrap();
|
||||||
|
|
||||||
let alice = alice.into_key_received(bob.user_id(), content).unwrap();
|
let alice = alice.into_key_received(bob.user_id(), &content).unwrap();
|
||||||
|
|
||||||
assert_eq!(alice.get_decimal(), bob.get_decimal());
|
assert_eq!(alice.get_decimal(), bob.get_decimal());
|
||||||
assert_eq!(alice.get_emoji(), bob.get_emoji());
|
assert_eq!(alice.get_emoji(), bob.get_emoji());
|
||||||
|
@ -1167,15 +1194,18 @@ mod test {
|
||||||
let (alice, bob) = get_sas_pair().await;
|
let (alice, bob) = get_sas_pair().await;
|
||||||
|
|
||||||
let content = bob.as_content();
|
let content = bob.as_content();
|
||||||
|
let content = AcceptContent::from(&content);
|
||||||
|
|
||||||
let alice: SasState<Accepted> = alice.into_accepted(bob.user_id(), content).unwrap();
|
let alice: SasState<Accepted> = alice.into_accepted(bob.user_id(), &content).unwrap();
|
||||||
let content = alice.as_content();
|
let content = alice.as_content();
|
||||||
|
let content = KeyContent::try_from(&content).unwrap();
|
||||||
|
|
||||||
let bob = bob.into_key_received(alice.user_id(), content).unwrap();
|
let bob = bob.into_key_received(alice.user_id(), &content).unwrap();
|
||||||
|
|
||||||
let content = bob.as_content();
|
let content = bob.as_content();
|
||||||
|
let content = KeyContent::try_from(&content).unwrap();
|
||||||
|
|
||||||
let alice = alice.into_key_received(bob.user_id(), content).unwrap();
|
let alice = alice.into_key_received(bob.user_id(), &content).unwrap();
|
||||||
|
|
||||||
assert_eq!(alice.get_decimal(), bob.get_decimal());
|
assert_eq!(alice.get_decimal(), bob.get_decimal());
|
||||||
assert_eq!(alice.get_emoji(), bob.get_emoji());
|
assert_eq!(alice.get_emoji(), bob.get_emoji());
|
||||||
|
@ -1185,14 +1215,16 @@ mod test {
|
||||||
let bob = bob.confirm();
|
let bob = bob.confirm();
|
||||||
|
|
||||||
let content = bob.as_content();
|
let content = bob.as_content();
|
||||||
|
let content = MacContent::try_from(&content).unwrap();
|
||||||
|
|
||||||
let alice = alice.into_mac_received(bob.user_id(), content).unwrap();
|
let alice = alice.into_mac_received(bob.user_id(), &content).unwrap();
|
||||||
assert!(!alice.get_emoji().is_empty());
|
assert!(!alice.get_emoji().is_empty());
|
||||||
assert_eq!(alice.get_decimal(), bob_decimals);
|
assert_eq!(alice.get_decimal(), bob_decimals);
|
||||||
let alice = alice.confirm();
|
let alice = alice.confirm();
|
||||||
|
|
||||||
let content = alice.as_content();
|
let content = alice.as_content();
|
||||||
let bob = bob.into_done(alice.user_id(), content).unwrap();
|
let content = MacContent::try_from(&content).unwrap();
|
||||||
|
let bob = bob.into_done(alice.user_id(), &content).unwrap();
|
||||||
|
|
||||||
assert!(bob.verified_devices().contains(&bob.other_device()));
|
assert!(bob.verified_devices().contains(&bob.other_device()));
|
||||||
assert!(alice.verified_devices().contains(&alice.other_device()));
|
assert!(alice.verified_devices().contains(&alice.other_device()));
|
||||||
|
@ -1203,11 +1235,7 @@ mod test {
|
||||||
let (alice, bob) = get_sas_pair().await;
|
let (alice, bob) = get_sas_pair().await;
|
||||||
|
|
||||||
let mut content = bob.as_content();
|
let mut content = bob.as_content();
|
||||||
|
let mut method = content.method_mut();
|
||||||
let mut method = match &mut content {
|
|
||||||
AcceptContent::ToDevice(c) => &mut c.method,
|
|
||||||
AcceptContent::Room(_, c) => &mut c.method,
|
|
||||||
};
|
|
||||||
|
|
||||||
match &mut method {
|
match &mut method {
|
||||||
AcceptMethod::MSasV1(ref mut c) => {
|
AcceptMethod::MSasV1(ref mut c) => {
|
||||||
|
@ -1216,14 +1244,18 @@ mod test {
|
||||||
_ => panic!("Unknown accept event content"),
|
_ => panic!("Unknown accept event content"),
|
||||||
}
|
}
|
||||||
|
|
||||||
let alice: SasState<Accepted> = alice.into_accepted(bob.user_id(), content).unwrap();
|
let content = AcceptContent::from(&content);
|
||||||
|
|
||||||
|
let alice: SasState<Accepted> = alice.into_accepted(bob.user_id(), &content).unwrap();
|
||||||
|
|
||||||
let content = alice.as_content();
|
let content = alice.as_content();
|
||||||
let bob = bob.into_key_received(alice.user_id(), content).unwrap();
|
let content = KeyContent::try_from(&content).unwrap();
|
||||||
|
let bob = bob.into_key_received(alice.user_id(), &content).unwrap();
|
||||||
let content = bob.as_content();
|
let content = bob.as_content();
|
||||||
|
let content = KeyContent::try_from(&content).unwrap();
|
||||||
|
|
||||||
alice
|
alice
|
||||||
.into_key_received(bob.user_id(), content)
|
.into_key_received(bob.user_id(), &content)
|
||||||
.expect_err("Didn't cancel on invalid commitment");
|
.expect_err("Didn't cancel on invalid commitment");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1232,8 +1264,9 @@ mod test {
|
||||||
let (alice, bob) = get_sas_pair().await;
|
let (alice, bob) = get_sas_pair().await;
|
||||||
|
|
||||||
let content = bob.as_content();
|
let content = bob.as_content();
|
||||||
|
let content = AcceptContent::from(&content);
|
||||||
let sender = UserId::try_from("@malory:example.org").unwrap();
|
let sender = UserId::try_from("@malory:example.org").unwrap();
|
||||||
alice.into_accepted(&sender, content).expect_err("Didn't cancel on a invalid sender");
|
alice.into_accepted(&sender, &content).expect_err("Didn't cancel on a invalid sender");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
@ -1241,11 +1274,7 @@ mod test {
|
||||||
let (alice, bob) = get_sas_pair().await;
|
let (alice, bob) = get_sas_pair().await;
|
||||||
|
|
||||||
let mut content = bob.as_content();
|
let mut content = bob.as_content();
|
||||||
|
let mut method = content.method_mut();
|
||||||
let mut method = match &mut content {
|
|
||||||
AcceptContent::ToDevice(c) => &mut c.method,
|
|
||||||
AcceptContent::Room(_, c) => &mut c.method,
|
|
||||||
};
|
|
||||||
|
|
||||||
match &mut method {
|
match &mut method {
|
||||||
AcceptMethod::MSasV1(ref mut c) => {
|
AcceptMethod::MSasV1(ref mut c) => {
|
||||||
|
@ -1254,8 +1283,10 @@ mod test {
|
||||||
_ => panic!("Unknown accept event content"),
|
_ => panic!("Unknown accept event content"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let content = AcceptContent::from(&content);
|
||||||
|
|
||||||
alice
|
alice
|
||||||
.into_accepted(bob.user_id(), content)
|
.into_accepted(bob.user_id(), &content)
|
||||||
.expect_err("Didn't cancel on an invalid SAS method");
|
.expect_err("Didn't cancel on an invalid SAS method");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1264,19 +1295,17 @@ mod test {
|
||||||
let (alice, bob) = get_sas_pair().await;
|
let (alice, bob) = get_sas_pair().await;
|
||||||
|
|
||||||
let mut content = bob.as_content();
|
let mut content = bob.as_content();
|
||||||
|
let method = content.method_mut();
|
||||||
let method = match &mut content {
|
|
||||||
AcceptContent::ToDevice(c) => &mut c.method,
|
|
||||||
AcceptContent::Room(_, c) => &mut c.method,
|
|
||||||
};
|
|
||||||
|
|
||||||
*method = AcceptMethod::Custom(CustomContent {
|
*method = AcceptMethod::Custom(CustomContent {
|
||||||
method: "m.sas.custom".to_string(),
|
method: "m.sas.custom".to_string(),
|
||||||
data: Default::default(),
|
data: Default::default(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let content = AcceptContent::from(&content);
|
||||||
|
|
||||||
alice
|
alice
|
||||||
.into_accepted(bob.user_id(), content)
|
.into_accepted(bob.user_id(), &content)
|
||||||
.expect_err("Didn't cancel on an unknown SAS method");
|
.expect_err("Didn't cancel on an unknown SAS method");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1291,11 +1320,7 @@ mod test {
|
||||||
let alice_sas = SasState::<Created>::new(alice.clone(), bob_device, None, None);
|
let alice_sas = SasState::<Created>::new(alice.clone(), bob_device, None, None);
|
||||||
|
|
||||||
let mut start_content = alice_sas.as_content();
|
let mut start_content = alice_sas.as_content();
|
||||||
|
let method = start_content.method_mut();
|
||||||
let method = match &mut start_content {
|
|
||||||
StartContent::ToDevice(c) => &mut c.method,
|
|
||||||
StartContent::Room(_, c) => &mut c.method,
|
|
||||||
};
|
|
||||||
|
|
||||||
match method {
|
match method {
|
||||||
StartMethod::SasV1(ref mut c) => {
|
StartMethod::SasV1(ref mut c) => {
|
||||||
|
@ -1304,27 +1329,38 @@ mod test {
|
||||||
_ => panic!("Unknown SAS start method"),
|
_ => panic!("Unknown SAS start method"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let flow_id = start_content.flow_id();
|
||||||
|
let content = StartContent::from(&start_content);
|
||||||
|
|
||||||
SasState::<Started>::from_start_event(
|
SasState::<Started>::from_start_event(
|
||||||
bob.clone(),
|
bob.clone(),
|
||||||
alice_device.clone(),
|
alice_device.clone(),
|
||||||
None,
|
None,
|
||||||
start_content,
|
flow_id,
|
||||||
|
&content,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.expect_err("Didn't cancel on invalid MAC method");
|
.expect_err("Didn't cancel on invalid MAC method");
|
||||||
|
|
||||||
let mut start_content = alice_sas.as_content();
|
let mut start_content = alice_sas.as_content();
|
||||||
|
let method = start_content.method_mut();
|
||||||
let method = match &mut start_content {
|
|
||||||
StartContent::ToDevice(c) => &mut c.method,
|
|
||||||
StartContent::Room(_, c) => &mut c.method,
|
|
||||||
};
|
|
||||||
|
|
||||||
*method = StartMethod::Custom(CustomStartContent {
|
*method = StartMethod::Custom(CustomStartContent {
|
||||||
method: "m.sas.custom".to_string(),
|
method: "m.sas.custom".to_string(),
|
||||||
data: Default::default(),
|
data: Default::default(),
|
||||||
});
|
});
|
||||||
|
|
||||||
SasState::<Started>::from_start_event(bob.clone(), alice_device, None, start_content)
|
let flow_id = start_content.flow_id();
|
||||||
.expect_err("Didn't cancel on unknown sas method");
|
let content = StartContent::from(&start_content);
|
||||||
|
|
||||||
|
SasState::<Started>::from_start_event(
|
||||||
|
bob.clone(),
|
||||||
|
alice_device,
|
||||||
|
None,
|
||||||
|
flow_id,
|
||||||
|
&content,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.expect_err("Didn't cancel on unknown sas method");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue