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::{
|
||||
room::encrypted::{EncryptedEventContent, EncryptedEventScheme},
|
||||
room_key::RoomKeyToDeviceEventContent,
|
||||
AnyMessageEventContent, AnyToDeviceEvent, SyncMessageEvent, ToDeviceEvent,
|
||||
AnyMessageEventContent, AnyRoomEvent, AnyToDeviceEvent, SyncMessageEvent, ToDeviceEvent,
|
||||
},
|
||||
identifiers::{
|
||||
DeviceId, DeviceIdBox, DeviceKeyAlgorithm, EventEncryptionAlgorithm, RoomId, UserId,
|
||||
|
@ -703,7 +703,7 @@ impl OlmMachine {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -986,7 +986,11 @@ impl OlmMachine {
|
|||
trace!("Successfully decrypted a Megolm event {:?}", decrypted_event);
|
||||
|
||||
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 =
|
||||
|
|
|
@ -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 matrix_sdk_common::{
|
||||
events::{
|
||||
room::message::MessageType, AnyMessageEvent, AnySyncMessageEvent, AnySyncRoomEvent,
|
||||
AnyToDeviceEvent,
|
||||
},
|
||||
identifiers::{DeviceId, EventId, RoomId, UserId},
|
||||
identifiers::{DeviceId, EventId, UserId},
|
||||
locks::Mutex,
|
||||
uuid::Uuid,
|
||||
};
|
||||
use tracing::{info, trace, warn};
|
||||
use tracing::info;
|
||||
|
||||
use super::{
|
||||
event_enums::{AnyEvent, AnyVerificationContent},
|
||||
requests::VerificationRequest,
|
||||
sas::{content_to_request, OutgoingContent, Sas},
|
||||
VerificationResult,
|
||||
FlowId, VerificationResult,
|
||||
};
|
||||
use crate::{
|
||||
olm::PrivateCrossSigningIdentity,
|
||||
|
@ -59,10 +56,6 @@ impl VerificationCache {
|
|||
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) {
|
||||
match sas.flow_id() {
|
||||
super::FlowId::ToDevice(t) => self.sas_verification.insert(t.to_owned(), sas),
|
||||
|
@ -194,7 +187,7 @@ impl VerificationMachine {
|
|||
None,
|
||||
);
|
||||
|
||||
let request = match content.into() {
|
||||
let request = match content {
|
||||
OutgoingContent::Room(r, c) => {
|
||||
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)
|
||||
}
|
||||
|
||||
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) {
|
||||
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,
|
||||
room_id: &RoomId,
|
||||
event: &AnySyncRoomEvent,
|
||||
sas: Sas,
|
||||
out_content: Option<OutgoingContent>,
|
||||
) -> Result<(), CryptoStoreError> {
|
||||
if let AnySyncRoomEvent::Message(m) = event {
|
||||
// Since these are room events we will get events that we send out on
|
||||
// our own as well.
|
||||
if m.sender() == self.account.user_id() {
|
||||
if let AnySyncMessageEvent::KeyVerificationReady(_e) = m {
|
||||
// TODO if there is a verification request, go into passive
|
||||
// mode since another device is handling this request.
|
||||
match sas.mark_as_done().await? {
|
||||
VerificationResult::Ok => {
|
||||
if let Some(c) = out_content {
|
||||
self.queue_up_content(sas.other_user_id(), sas.other_device_id(), c);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match m {
|
||||
AnySyncMessageEvent::RoomMessage(m) => {
|
||||
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::Cancel(c) => {
|
||||
if let Some(r) = sas.cancel_with_code(c) {
|
||||
self.verifications.add_request(r.into());
|
||||
}
|
||||
}
|
||||
VerificationResult::SignatureUpload(r) => {
|
||||
self.verifications.add_request(r.into());
|
||||
|
||||
AnySyncMessageEvent::KeyVerificationDone(e) => {
|
||||
if let Some(s) = self.verifications.get_room_sas(&e.content.relation.event_id) {
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if let Some(c) = out_content {
|
||||
self.queue_up_content(sas.other_user_id(), sas.other_device_id(), c);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn receive_event(&self, event: &AnyToDeviceEvent) -> Result<(), CryptoStoreError> {
|
||||
trace!("Received a key verification event {:?}", event);
|
||||
pub async fn receive_any_event(
|
||||
&self,
|
||||
event: impl Into<AnyEvent<'_>>,
|
||||
) -> Result<(), CryptoStoreError> {
|
||||
let event = event.into();
|
||||
|
||||
match event {
|
||||
AnyToDeviceEvent::KeyVerificationRequest(e) => {
|
||||
let request = VerificationRequest::from_request(
|
||||
self.verifications.clone(),
|
||||
self.account.clone(),
|
||||
self.private_identity.lock().await.clone(),
|
||||
self.store.clone(),
|
||||
&e.sender,
|
||||
&e.content,
|
||||
);
|
||||
let flow_id = if let Ok(flow_id) = FlowId::try_from(&event) {
|
||||
flow_id
|
||||
} else {
|
||||
// This isn't a verification event, return early.
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
self.requests.insert(request.flow_id().as_str().to_string(), request);
|
||||
}
|
||||
AnyToDeviceEvent::KeyVerificationReady(e) => {
|
||||
if let Some(request) = self.requests.get(&e.content.transaction_id) {
|
||||
if &e.sender == request.other_user() {
|
||||
// TODO remove this unwrap.
|
||||
request.receive_ready(&e.sender, &e.content).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
if let Some(content) = event.verification_content() {
|
||||
match &content {
|
||||
AnyVerificationContent::Request(r) => {
|
||||
info!(
|
||||
sender = event.sender().as_str(),
|
||||
from_device = r.from_device().as_str(),
|
||||
"Received a new verification request",
|
||||
);
|
||||
}
|
||||
}
|
||||
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() {
|
||||
match s.mark_as_done().await? {
|
||||
VerificationResult::Ok => (),
|
||||
VerificationResult::Cancel(c) => {
|
||||
if let Some(r) = s.cancel_with_code(c) {
|
||||
self.verifications.add_request(r.into());
|
||||
let request = VerificationRequest::from_request(
|
||||
self.verifications.clone(),
|
||||
self.account.clone(),
|
||||
self.private_identity.lock().await.clone(),
|
||||
self.store.clone(),
|
||||
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);
|
||||
}
|
||||
}
|
||||
VerificationResult::SignatureUpload(r) => {
|
||||
self.verifications.add_request(r.into());
|
||||
Err(cancellation) => self.queue_up_content(
|
||||
event.sender(),
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
@ -491,9 +407,12 @@ mod test {
|
|||
use super::{Sas, VerificationMachine};
|
||||
use crate::{
|
||||
olm::PrivateCrossSigningIdentity,
|
||||
requests::OutgoingRequests,
|
||||
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,
|
||||
};
|
||||
|
||||
|
@ -538,7 +457,7 @@ mod test {
|
|||
);
|
||||
|
||||
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
|
||||
.unwrap();
|
||||
|
||||
|
@ -559,53 +478,41 @@ mod test {
|
|||
|
||||
let alice = alice_machine.get_sas(bob.flow_id().as_str()).unwrap();
|
||||
|
||||
let event = alice
|
||||
.accept()
|
||||
.map(|c| wrap_any_to_device_content(alice.user_id(), get_content_from_request(&c)))
|
||||
.unwrap();
|
||||
let request = alice.accept().unwrap();
|
||||
|
||||
let event = bob
|
||||
.receive_event(&event)
|
||||
.map(|c| wrap_any_to_device_content(bob.user_id(), c))
|
||||
.unwrap();
|
||||
let content = OutgoingContent::try_from(request).unwrap();
|
||||
let content = AcceptContent::try_from(&content).unwrap().into();
|
||||
|
||||
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());
|
||||
alice_machine.receive_event(&event).await.unwrap();
|
||||
alice_machine.receive_any_event(&event).await.unwrap();
|
||||
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 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);
|
||||
|
||||
assert!(bob.receive_event(&event).is_none());
|
||||
assert!(bob.receive_any_event(alice.user_id(), &content).is_none());
|
||||
|
||||
assert!(alice.emoji().is_some());
|
||||
assert!(bob.emoji().is_some());
|
||||
|
||||
assert_eq!(alice.emoji(), bob.emoji());
|
||||
|
||||
let event = wrap_any_to_device_content(
|
||||
alice.user_id(),
|
||||
get_content_from_request(&alice.confirm().await.unwrap().0.unwrap()),
|
||||
);
|
||||
bob.receive_event(&event);
|
||||
let request = alice.confirm().await.unwrap().0.unwrap();
|
||||
let content = OutgoingContent::try_from(request).unwrap();
|
||||
let content = MacContent::try_from(&content).unwrap().into();
|
||||
bob.receive_any_event(alice.user_id(), &content);
|
||||
|
||||
let event = wrap_any_to_device_content(
|
||||
bob.user_id(),
|
||||
get_content_from_request(&bob.confirm().await.unwrap().0.unwrap()),
|
||||
);
|
||||
alice.receive_event(&event);
|
||||
let request = bob.confirm().await.unwrap().0.unwrap();
|
||||
let content = OutgoingContent::try_from(request).unwrap();
|
||||
let content = MacContent::try_from(&content).unwrap().into();
|
||||
alice.receive_any_event(bob.user_id(), &content);
|
||||
|
||||
assert!(alice.is_done());
|
||||
assert!(bob.is_done());
|
||||
|
|
|
@ -12,26 +12,30 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
mod event_enums;
|
||||
mod machine;
|
||||
mod requests;
|
||||
mod sas;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use machine::{VerificationCache, VerificationMachine};
|
||||
use matrix_sdk_common::{
|
||||
api::r0::keys::upload_signatures::Request as SignatureUploadRequest,
|
||||
events::key::verification::{
|
||||
cancel::{CancelCode, CancelEventContent, CancelToDeviceEventContent},
|
||||
Relation,
|
||||
events::{
|
||||
key::verification::{
|
||||
cancel::{CancelCode, CancelEventContent, CancelToDeviceEventContent},
|
||||
Relation,
|
||||
},
|
||||
AnyMessageEventContent, AnyToDeviceEventContent,
|
||||
},
|
||||
identifiers::{DeviceId, EventId, RoomId, UserId},
|
||||
};
|
||||
|
||||
pub use machine::{VerificationCache, VerificationMachine};
|
||||
pub use requests::VerificationRequest;
|
||||
pub use sas::{AcceptSettings, Sas};
|
||||
use tracing::{error, info, trace, warn};
|
||||
|
||||
use self::sas::OutgoingContent;
|
||||
use crate::{
|
||||
error::SignatureError,
|
||||
olm::PrivateCrossSigningIdentity,
|
||||
|
@ -39,8 +43,6 @@ use crate::{
|
|||
CryptoStoreError, LocalTrust, ReadOnlyDevice, UserIdentities,
|
||||
};
|
||||
|
||||
use self::sas::CancelContent;
|
||||
|
||||
/// The verification state indicating that the verification finished
|
||||
/// successfully.
|
||||
///
|
||||
|
@ -82,22 +84,24 @@ impl Cancelled {
|
|||
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 {
|
||||
FlowId::ToDevice(s) => CancelToDeviceEventContent::new(
|
||||
s.clone(),
|
||||
self.reason.to_string(),
|
||||
self.cancel_code.clone(),
|
||||
)
|
||||
.into(),
|
||||
FlowId::ToDevice(s) => {
|
||||
AnyToDeviceEventContent::KeyVerificationCancel(CancelToDeviceEventContent::new(
|
||||
s.clone(),
|
||||
self.reason.to_string(),
|
||||
self.cancel_code.clone(),
|
||||
))
|
||||
.into()
|
||||
}
|
||||
|
||||
FlowId::InRoom(r, e) => (
|
||||
r.clone(),
|
||||
CancelEventContent::new(
|
||||
AnyMessageEventContent::KeyVerificationCancel(CancelEventContent::new(
|
||||
self.reason.to_string(),
|
||||
self.cancel_code.clone(),
|
||||
Relation::new(e.clone()),
|
||||
),
|
||||
)),
|
||||
)
|
||||
.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.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum VerificationResult {
|
||||
|
@ -158,7 +168,6 @@ pub struct IdentitiesBeingVerified {
|
|||
identity_being_verified: Option<UserIdentities>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl IdentitiesBeingVerified {
|
||||
fn user_id(&self) -> &UserId {
|
||||
self.private_identity.user_id()
|
||||
|
@ -298,7 +307,10 @@ impl IdentitiesBeingVerified {
|
|||
.map_or(false, |i| i.master_key() == identity.master_key())
|
||||
{
|
||||
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 {
|
||||
i.mark_as_verified();
|
||||
|
@ -307,28 +319,28 @@ impl IdentitiesBeingVerified {
|
|||
Ok(Some(identity))
|
||||
} else {
|
||||
info!(
|
||||
user_id = self.other_user_id().as_str(),
|
||||
"The interactive verification process didn't verify \
|
||||
the user identity of {} {:?}",
|
||||
identity.user_id(),
|
||||
verified_identities,
|
||||
the user identity of the user that participated in \
|
||||
the interactive verification",
|
||||
);
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
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.",
|
||||
identity.user_id(),
|
||||
);
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
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.",
|
||||
self.other_user_id(),
|
||||
);
|
||||
Ok(None)
|
||||
}
|
||||
|
|
|
@ -14,19 +14,15 @@
|
|||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::{
|
||||
convert::TryFrom,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use matrix_sdk_common::{
|
||||
api::r0::to_device::DeviceIdOrAllDevices,
|
||||
events::{
|
||||
key::verification::{
|
||||
done::{DoneEventContent, DoneToDeviceEventContent},
|
||||
ready::{ReadyEventContent, ReadyToDeviceEventContent},
|
||||
request::RequestToDeviceEventContent,
|
||||
start::{StartEventContent, StartMethod, StartToDeviceEventContent},
|
||||
start::StartMethod,
|
||||
Relation, VerificationMethod,
|
||||
},
|
||||
room::message::KeyVerificationRequestEventContent,
|
||||
|
@ -36,10 +32,11 @@ use matrix_sdk_common::{
|
|||
uuid::Uuid,
|
||||
MilliSecondsSinceUnixEpoch,
|
||||
};
|
||||
use tracing::{info, trace, warn};
|
||||
use tracing::{info, warn};
|
||||
|
||||
use super::{
|
||||
sas::{content_to_request, OutgoingContent, StartContent as OwnedStartContent},
|
||||
event_enums::{ReadyContent, RequestContent, StartContent},
|
||||
sas::{content_to_request, OutgoingContent},
|
||||
FlowId, VerificationCache,
|
||||
};
|
||||
use crate::{
|
||||
|
@ -51,184 +48,6 @@ use crate::{
|
|||
|
||||
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)]
|
||||
/// TODO
|
||||
pub struct VerificationRequest {
|
||||
|
@ -311,56 +130,14 @@ impl VerificationRequest {
|
|||
&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(
|
||||
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,
|
||||
account: ReadOnlyAccount,
|
||||
private_cross_signing_identity: PrivateCrossSigningIdentity,
|
||||
store: Arc<Box<dyn CryptoStore>>,
|
||||
sender: &UserId,
|
||||
flow_id: FlowId,
|
||||
content: RequestContent,
|
||||
content: &RequestContent,
|
||||
) -> Self {
|
||||
Self {
|
||||
verification_cache: cache.clone(),
|
||||
|
@ -394,13 +171,8 @@ impl VerificationRequest {
|
|||
}
|
||||
|
||||
#[allow(clippy::unnecessary_wraps)]
|
||||
pub(crate) fn receive_ready<'a>(
|
||||
&self,
|
||||
sender: &UserId,
|
||||
content: impl Into<ReadyContent<'a>>,
|
||||
) -> Result<(), ()> {
|
||||
pub(crate) fn receive_ready(&self, sender: &UserId, content: &ReadyContent) -> Result<(), ()> {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
let content = content.into();
|
||||
|
||||
if let InnerRequest::Created(s) = &*inner {
|
||||
*inner = InnerRequest::Ready(s.clone().into_ready(sender, content));
|
||||
|
@ -409,13 +181,11 @@ impl VerificationRequest {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn receive_start<'a>(
|
||||
pub(crate) async fn receive_start(
|
||||
&self,
|
||||
sender: &UserId,
|
||||
content: impl Into<StartContent<'a>>,
|
||||
content: &StartContent<'_>,
|
||||
) -> Result<(), CryptoStoreError> {
|
||||
let content = content.into();
|
||||
|
||||
let inner = self.inner.lock().unwrap().clone();
|
||||
|
||||
if let InnerRequest::Ready(s) = inner {
|
||||
|
@ -502,9 +272,9 @@ impl InnerRequest {
|
|||
}
|
||||
}
|
||||
|
||||
fn to_started_sas<'a>(
|
||||
fn to_started_sas(
|
||||
&self,
|
||||
content: impl Into<StartContent<'a>>,
|
||||
content: &StartContent,
|
||||
other_device: ReadOnlyDevice,
|
||||
other_identity: Option<UserIdentities>,
|
||||
) -> 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.
|
||||
RequestState {
|
||||
account: self.account,
|
||||
|
@ -600,7 +370,7 @@ impl RequestState<Requested> {
|
|||
store: Arc<Box<dyn CryptoStore>>,
|
||||
sender: &UserId,
|
||||
flow_id: &FlowId,
|
||||
content: RequestContent,
|
||||
content: &RequestContent,
|
||||
) -> RequestState<Requested> {
|
||||
// TODO only create this if we suport the methods
|
||||
RequestState {
|
||||
|
@ -673,39 +443,27 @@ struct Ready {
|
|||
impl RequestState<Ready> {
|
||||
fn to_started_sas<'a>(
|
||||
&self,
|
||||
content: impl Into<StartContent<'a>>,
|
||||
content: &StartContent<'a>,
|
||||
other_device: ReadOnlyDevice,
|
||||
other_identity: Option<UserIdentities>,
|
||||
) -> 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(
|
||||
(&*self.flow_id).to_owned(),
|
||||
content,
|
||||
self.store.clone(),
|
||||
self.account.clone(),
|
||||
self.private_cross_signing_identity.clone(),
|
||||
other_device,
|
||||
other_identity,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
async fn receive_start<'a>(
|
||||
async fn receive_start(
|
||||
&self,
|
||||
sender: &UserId,
|
||||
content: impl Into<StartContent<'a>>,
|
||||
content: &StartContent<'_>,
|
||||
) -> Result<(), CryptoStoreError> {
|
||||
let content = content.into();
|
||||
|
||||
info!(
|
||||
sender = sender.as_str(),
|
||||
device = content.from_device().as_str(),
|
||||
|
@ -747,7 +505,7 @@ impl RequestState<Ready> {
|
|||
}
|
||||
},
|
||||
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,
|
||||
Some(t),
|
||||
);
|
||||
(sas, content.into())
|
||||
(sas, content)
|
||||
}
|
||||
FlowId::InRoom(r, e) => {
|
||||
let (sas, content) = Sas::start_in_room(
|
||||
|
@ -784,7 +542,7 @@ impl RequestState<Ready> {
|
|||
store,
|
||||
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_test::async_test;
|
||||
|
||||
use super::{StartContent, VerificationRequest};
|
||||
use super::VerificationRequest;
|
||||
use crate::{
|
||||
olm::{PrivateCrossSigningIdentity, ReadOnlyAccount},
|
||||
store::{Changes, CryptoStore, MemoryStore},
|
||||
verification::{requests::ReadyContent, sas::OutgoingContent, VerificationCache},
|
||||
verification::{
|
||||
event_enums::{ReadyContent, StartContent},
|
||||
sas::OutgoingContent,
|
||||
FlowId, VerificationCache,
|
||||
},
|
||||
ReadOnlyDevice,
|
||||
};
|
||||
|
||||
|
@ -856,21 +618,22 @@ mod test {
|
|||
&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(),
|
||||
alice,
|
||||
alice_identity,
|
||||
alice_store.into(),
|
||||
&bob_id(),
|
||||
&event_id,
|
||||
&room_id,
|
||||
&content,
|
||||
flow_id,
|
||||
&(&content).into(),
|
||||
);
|
||||
|
||||
let content: OutgoingContent = alice_request.accept().unwrap().into();
|
||||
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!(alice_request.is_ready());
|
||||
|
@ -908,21 +671,22 @@ mod test {
|
|||
&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(),
|
||||
alice,
|
||||
alice_identity,
|
||||
alice_store.into(),
|
||||
&bob_id(),
|
||||
&event_id,
|
||||
&room_id,
|
||||
&content,
|
||||
flow_id,
|
||||
&(&content).into(),
|
||||
);
|
||||
|
||||
let content: OutgoingContent = alice_request.accept().unwrap().into();
|
||||
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!(alice_request.is_ready());
|
||||
|
@ -931,7 +695,7 @@ mod test {
|
|||
|
||||
let content = StartContent::try_from(&start_content).unwrap();
|
||||
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();
|
||||
|
||||
assert!(!bob_sas.is_cancelled());
|
||||
|
|
|
@ -12,254 +12,26 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::{collections::BTreeMap, convert::TryInto};
|
||||
|
||||
use matrix_sdk_common::{
|
||||
events::{
|
||||
key::verification::{
|
||||
accept::{AcceptEventContent, AcceptMethod, AcceptToDeviceEventContent},
|
||||
cancel::{CancelEventContent, CancelToDeviceEventContent},
|
||||
done::DoneEventContent,
|
||||
key::{KeyEventContent, KeyToDeviceEventContent},
|
||||
mac::{MacEventContent, MacToDeviceEventContent},
|
||||
start::{StartEventContent, StartMethod, StartToDeviceEventContent},
|
||||
},
|
||||
AnyMessageEventContent, AnyToDeviceEventContent,
|
||||
},
|
||||
events::{AnyMessageEventContent, AnyToDeviceEventContent},
|
||||
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)]
|
||||
pub enum OutgoingContent {
|
||||
Room(RoomId, AnyMessageEventContent),
|
||||
ToDevice(AnyToDeviceEventContent),
|
||||
}
|
||||
|
||||
impl From<StartContent> for OutgoingContent {
|
||||
fn from(content: StartContent) -> Self {
|
||||
impl From<OwnedStartContent> for OutgoingContent {
|
||||
fn from(content: OwnedStartContent) -> Self {
|
||||
match content {
|
||||
StartContent::Room(r, c) => (r, AnyMessageEventContent::KeyVerificationStart(c)).into(),
|
||||
StartContent::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()
|
||||
OwnedStartContent::Room(r, c) => {
|
||||
(r, AnyMessageEventContent::KeyVerificationStart(c)).into()
|
||||
}
|
||||
OwnedStartContent::ToDevice(c) => {
|
||||
AnyToDeviceEventContent::KeyVerificationStart(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)]
|
||||
use crate::OutgoingVerificationRequest;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use crate::verification::event_enums::OwnedStartContent;
|
||||
#[cfg(test)]
|
||||
use crate::{OutgoingRequest, OutgoingVerificationRequest, RoomMessageRequest, ToDeviceRequest};
|
||||
|
||||
#[cfg(test)]
|
||||
impl From<OutgoingVerificationRequest> for OutgoingContent {
|
||||
fn from(request: OutgoingVerificationRequest) -> Self {
|
||||
use matrix_sdk_common::events::EventType;
|
||||
use serde_json::Value;
|
||||
|
||||
match request {
|
||||
OutgoingVerificationRequest::ToDevice(r) => {
|
||||
let json: Value = serde_json::from_str(
|
||||
r.messages.values().next().unwrap().values().next().unwrap().get(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
match r.event_type {
|
||||
EventType::KeyVerificationRequest => {
|
||||
AnyToDeviceEventContent::KeyVerificationRequest(
|
||||
serde_json::from_value(json).unwrap(),
|
||||
)
|
||||
}
|
||||
EventType::KeyVerificationReady => {
|
||||
AnyToDeviceEventContent::KeyVerificationReady(
|
||||
serde_json::from_value(json).unwrap(),
|
||||
)
|
||||
}
|
||||
EventType::KeyVerificationDone => AnyToDeviceEventContent::KeyVerificationDone(
|
||||
serde_json::from_value(json).unwrap(),
|
||||
),
|
||||
EventType::KeyVerificationStart => {
|
||||
AnyToDeviceEventContent::KeyVerificationStart(
|
||||
serde_json::from_value(json).unwrap(),
|
||||
)
|
||||
}
|
||||
EventType::KeyVerificationKey => AnyToDeviceEventContent::KeyVerificationKey(
|
||||
serde_json::from_value(json).unwrap(),
|
||||
),
|
||||
EventType::KeyVerificationAccept => {
|
||||
AnyToDeviceEventContent::KeyVerificationAccept(
|
||||
serde_json::from_value(json).unwrap(),
|
||||
)
|
||||
}
|
||||
EventType::KeyVerificationMac => AnyToDeviceEventContent::KeyVerificationMac(
|
||||
serde_json::from_value(json).unwrap(),
|
||||
),
|
||||
EventType::KeyVerificationCancel => {
|
||||
AnyToDeviceEventContent::KeyVerificationCancel(
|
||||
serde_json::from_value(json).unwrap(),
|
||||
)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
OutgoingVerificationRequest::InRoom(r) => (r.room_id, r.content).into(),
|
||||
OutgoingVerificationRequest::ToDevice(r) => Self::try_from(r).unwrap(),
|
||||
OutgoingVerificationRequest::InRoom(r) => Self::from(r),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl From<RoomMessageRequest> for OutgoingContent {
|
||||
fn from(value: RoomMessageRequest) -> Self {
|
||||
(value.room_id, value.content).into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl TryFrom<ToDeviceRequest> for OutgoingContent {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: ToDeviceRequest) -> Result<Self, Self::Error> {
|
||||
use matrix_sdk_common::events::EventType;
|
||||
use serde_json::Value;
|
||||
|
||||
let json: Value = serde_json::from_str(
|
||||
value
|
||||
.messages
|
||||
.values()
|
||||
.next()
|
||||
.and_then(|m| m.values().next().map(|j| j.get()))
|
||||
.ok_or(())?,
|
||||
)
|
||||
.map_err(|_| ())?;
|
||||
|
||||
match value.event_type {
|
||||
EventType::KeyVerificationRequest => {
|
||||
Ok(AnyToDeviceEventContent::KeyVerificationRequest(
|
||||
serde_json::from_value(json).map_err(|_| ())?,
|
||||
)
|
||||
.into())
|
||||
}
|
||||
EventType::KeyVerificationReady => Ok(AnyToDeviceEventContent::KeyVerificationReady(
|
||||
serde_json::from_value(json).map_err(|_| ())?,
|
||||
)
|
||||
.into()),
|
||||
EventType::KeyVerificationDone => Ok(AnyToDeviceEventContent::KeyVerificationDone(
|
||||
serde_json::from_value(json).map_err(|_| ())?,
|
||||
)
|
||||
.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},
|
||||
Relation,
|
||||
},
|
||||
AnyToDeviceEventContent, EventType,
|
||||
AnyMessageEventContent, AnyToDeviceEventContent, EventType,
|
||||
},
|
||||
identifiers::{DeviceKeyAlgorithm, DeviceKeyId, UserId},
|
||||
uuid::Uuid,
|
||||
|
@ -31,13 +31,11 @@ use olm_rs::sas::OlmSas;
|
|||
use sha2::{Digest, Sha256};
|
||||
use tracing::{trace, warn};
|
||||
|
||||
use super::{
|
||||
event_enums::{MacContent, StartContent},
|
||||
FlowId,
|
||||
};
|
||||
use super::{FlowId, OutgoingContent};
|
||||
use crate::{
|
||||
identities::{ReadOnlyDevice, UserIdentities},
|
||||
utilities::encode,
|
||||
verification::event_enums::{MacContent, StartContent},
|
||||
ReadOnlyAccount, ToDeviceRequest,
|
||||
};
|
||||
|
||||
|
@ -58,8 +56,8 @@ pub struct SasIds {
|
|||
///
|
||||
/// * `content` - The `m.key.verification.start` event content that started the
|
||||
/// interactive verification process.
|
||||
pub fn calculate_commitment(public_key: &str, content: impl Into<StartContent>) -> String {
|
||||
let content = content.into().canonical_json();
|
||||
pub fn calculate_commitment(public_key: &str, content: &StartContent) -> String {
|
||||
let content = content.canonical_json();
|
||||
let content_string = content.to_string();
|
||||
|
||||
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<_>>();
|
||||
keys.sort();
|
||||
keys.sort_unstable();
|
||||
|
||||
let keys = sas
|
||||
.calculate_mac(&keys.join(","), &format!("{}KEY_IDS", &info))
|
||||
|
@ -296,7 +294,7 @@ fn extra_mac_info_send(ids: &SasIds, flow_id: &str) -> String {
|
|||
/// # Panics
|
||||
///
|
||||
/// This will panic if the public key of the other side wasn't set.
|
||||
pub fn get_mac_content(sas: &OlmSas, ids: &SasIds, flow_id: &FlowId) -> MacContent {
|
||||
pub fn get_mac_content(sas: &OlmSas, ids: &SasIds, flow_id: &FlowId) -> OutgoingContent {
|
||||
let mut mac: BTreeMap<String, String> = BTreeMap::new();
|
||||
|
||||
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");
|
||||
|
||||
match flow_id {
|
||||
FlowId::ToDevice(s) => MacToDeviceEventContent::new(s.to_string(), mac, keys).into(),
|
||||
FlowId::InRoom(r, e) => {
|
||||
(r.clone(), MacEventContent::new(mac, keys, Relation::new(e.clone()))).into()
|
||||
}
|
||||
FlowId::ToDevice(s) => AnyToDeviceEventContent::KeyVerificationMac(
|
||||
MacToDeviceEventContent::new(s.to_string(), mac, keys),
|
||||
)
|
||||
.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,
|
||||
emoji_from_index,
|
||||
};
|
||||
use crate::verification::event_enums::StartContent;
|
||||
|
||||
#[test]
|
||||
fn commitment_calculation() {
|
||||
|
@ -575,7 +583,8 @@ mod test {
|
|||
});
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -17,23 +17,23 @@ use std::sync::Arc;
|
|||
use std::time::Instant;
|
||||
|
||||
use matrix_sdk_common::{
|
||||
events::{
|
||||
key::verification::{cancel::CancelCode, ShortAuthenticationString},
|
||||
AnyMessageEvent, AnyToDeviceEvent,
|
||||
},
|
||||
identifiers::{EventId, RoomId},
|
||||
events::key::verification::{cancel::CancelCode, ShortAuthenticationString},
|
||||
identifiers::{EventId, RoomId, UserId},
|
||||
};
|
||||
|
||||
use super::{
|
||||
event_enums::{AcceptContent, CancelContent, MacContent, OutgoingContent},
|
||||
event_enums::OutgoingContent,
|
||||
sas_state::{
|
||||
Accepted, Confirmed, Created, KeyReceived, MacReceived, SasState, Started, WaitingForDone,
|
||||
},
|
||||
FlowId, StartContent,
|
||||
FlowId,
|
||||
};
|
||||
use crate::{
|
||||
identities::{ReadOnlyDevice, UserIdentities},
|
||||
verification::{Cancelled, Done},
|
||||
verification::{
|
||||
event_enums::{AnyVerificationContent, OwnedAcceptContent, StartContent},
|
||||
Cancelled, Done,
|
||||
},
|
||||
ReadOnlyAccount,
|
||||
};
|
||||
|
||||
|
@ -57,10 +57,10 @@ impl InnerSas {
|
|||
other_device: ReadOnlyDevice,
|
||||
other_identity: Option<UserIdentities>,
|
||||
transaction_id: Option<String>,
|
||||
) -> (InnerSas, StartContent) {
|
||||
) -> (InnerSas, OutgoingContent) {
|
||||
let sas = SasState::<Created>::new(account, other_device, other_identity, transaction_id);
|
||||
let content = sas.as_content();
|
||||
(InnerSas::Created(sas), content)
|
||||
(InnerSas::Created(sas), content.into())
|
||||
}
|
||||
|
||||
pub fn supports_emoji(&self) -> bool {
|
||||
|
@ -100,7 +100,7 @@ impl InnerSas {
|
|||
account: ReadOnlyAccount,
|
||||
other_device: ReadOnlyDevice,
|
||||
other_identity: Option<UserIdentities>,
|
||||
) -> (InnerSas, StartContent) {
|
||||
) -> (InnerSas, OutgoingContent) {
|
||||
let sas = SasState::<Created>::new_in_room(
|
||||
room_id,
|
||||
event_id,
|
||||
|
@ -109,23 +109,31 @@ impl InnerSas {
|
|||
other_identity,
|
||||
);
|
||||
let content = sas.as_content();
|
||||
(InnerSas::Created(sas), content)
|
||||
(InnerSas::Created(sas), content.into())
|
||||
}
|
||||
|
||||
pub fn from_start_event(
|
||||
account: ReadOnlyAccount,
|
||||
other_device: ReadOnlyDevice,
|
||||
content: impl Into<StartContent>,
|
||||
flow_id: FlowId,
|
||||
content: &StartContent,
|
||||
other_identity: Option<UserIdentities>,
|
||||
) -> Result<InnerSas, CancelContent> {
|
||||
match SasState::<Started>::from_start_event(account, other_device, other_identity, content)
|
||||
{
|
||||
started_from_request: bool,
|
||||
) -> 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)),
|
||||
Err(s) => Err(s.as_content()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn accept(&self) -> Option<AcceptContent> {
|
||||
pub fn accept(&self) -> Option<OwnedAcceptContent> {
|
||||
if let InnerSas::Started(s) = self {
|
||||
Some(s.as_content())
|
||||
} 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 {
|
||||
InnerSas::Created(s) => s.cancel(code),
|
||||
InnerSas::Started(s) => s.cancel(code),
|
||||
|
@ -165,7 +173,7 @@ impl InnerSas {
|
|||
(InnerSas::Cancelled(sas), Some(content))
|
||||
}
|
||||
|
||||
pub fn confirm(self) -> (InnerSas, Option<MacContent>) {
|
||||
pub fn confirm(self) -> (InnerSas, Option<OutgoingContent>) {
|
||||
match self {
|
||||
InnerSas::KeyReceived(s) => {
|
||||
let sas = s.confirm();
|
||||
|
@ -189,149 +197,104 @@ impl InnerSas {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn receive_room_event(
|
||||
pub fn receive_any_event(
|
||||
self,
|
||||
event: &AnyMessageEvent,
|
||||
) -> (InnerSas, Option<OutgoingContent>) {
|
||||
match event {
|
||||
AnyMessageEvent::KeyVerificationKey(e) => match self {
|
||||
InnerSas::Accepted(s) => {
|
||||
match s.into_key_received(&e.sender, (e.room_id.clone(), e.content.clone())) {
|
||||
Ok(s) => (InnerSas::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) => {
|
||||
sender: &UserId,
|
||||
content: &AnyVerificationContent,
|
||||
) -> (Self, Option<OutgoingContent>) {
|
||||
match content {
|
||||
AnyVerificationContent::Accept(c) => {
|
||||
if let InnerSas::Created(s) = self {
|
||||
match s.into_accepted(&e.sender, e.content.clone()) {
|
||||
match s.into_accepted(sender, c) {
|
||||
Ok(s) => {
|
||||
let content = s.as_content();
|
||||
(InnerSas::Accepted(s), Some(content.into()))
|
||||
(InnerSas::Accepted(s), Some(content))
|
||||
}
|
||||
Err(s) => {
|
||||
let content = s.as_content();
|
||||
(InnerSas::Cancelled(s), Some(content.into()))
|
||||
(InnerSas::Cancelled(s), Some(content))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(self, None)
|
||||
}
|
||||
}
|
||||
AnyToDeviceEvent::KeyVerificationKey(e) => match self {
|
||||
InnerSas::Accepted(s) => match s.into_key_received(&e.sender, e.content.clone()) {
|
||||
AnyVerificationContent::Cancel(c) => {
|
||||
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),
|
||||
Err(s) => {
|
||||
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) => {
|
||||
let content = s.as_content();
|
||||
(InnerSas::KeyReceived(s), Some(content.into()))
|
||||
(InnerSas::KeyReceived(s), Some(content))
|
||||
}
|
||||
Err(s) => {
|
||||
let content = s.as_content();
|
||||
(InnerSas::Cancelled(s), Some(content.into()))
|
||||
(InnerSas::Cancelled(s), Some(content))
|
||||
}
|
||||
},
|
||||
|
||||
_ => (self, None),
|
||||
},
|
||||
AnyToDeviceEvent::KeyVerificationMac(e) => match self {
|
||||
InnerSas::KeyReceived(s) => {
|
||||
match s.into_mac_received(&e.sender, e.content.clone()) {
|
||||
Ok(s) => (InnerSas::MacReceived(s), None),
|
||||
AnyVerificationContent::Mac(c) => match self {
|
||||
InnerSas::KeyReceived(s) => match s.into_mac_received(sender, c) {
|
||||
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) => {
|
||||
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),
|
||||
Err(s) => {
|
||||
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),
|
||||
AnyVerificationContent::Request(_)
|
||||
| AnyVerificationContent::Ready(_)
|
||||
| AnyVerificationContent::Start(_) => (self, None),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,7 @@ use std::sync::{Arc, Mutex};
|
|||
#[cfg(test)]
|
||||
use std::time::Instant;
|
||||
|
||||
use event_enums::AcceptContent;
|
||||
pub use event_enums::{CancelContent, OutgoingContent, StartContent};
|
||||
pub use event_enums::OutgoingContent;
|
||||
pub use helpers::content_to_request;
|
||||
use inner_sas::InnerSas;
|
||||
use matrix_sdk_common::{
|
||||
|
@ -33,13 +32,16 @@ use matrix_sdk_common::{
|
|||
cancel::CancelCode,
|
||||
ShortAuthenticationString,
|
||||
},
|
||||
AnyMessageEvent, AnyMessageEventContent, AnyToDeviceEvent, AnyToDeviceEventContent,
|
||||
AnyMessageEventContent, AnyToDeviceEventContent,
|
||||
},
|
||||
identifiers::{DeviceId, EventId, RoomId, UserId},
|
||||
uuid::Uuid,
|
||||
};
|
||||
|
||||
use super::{FlowId, IdentitiesBeingVerified, VerificationResult};
|
||||
use super::{
|
||||
event_enums::{AnyVerificationContent, OwnedAcceptContent, StartContent},
|
||||
FlowId, IdentitiesBeingVerified, VerificationResult,
|
||||
};
|
||||
use crate::{
|
||||
identities::{ReadOnlyDevice, UserIdentities},
|
||||
olm::PrivateCrossSigningIdentity,
|
||||
|
@ -111,10 +113,10 @@ impl Sas {
|
|||
let flow_id = inner_sas.verification_flow_id();
|
||||
|
||||
let identities = IdentitiesBeingVerified {
|
||||
private_identity: private_identity.clone(),
|
||||
private_identity,
|
||||
store: store.clone(),
|
||||
device_being_verified: other_device.clone(),
|
||||
identity_being_verified: other_identity.clone(),
|
||||
device_being_verified: other_device,
|
||||
identity_being_verified: other_identity,
|
||||
};
|
||||
|
||||
Sas {
|
||||
|
@ -142,7 +144,7 @@ impl Sas {
|
|||
store: Arc<Box<dyn CryptoStore>>,
|
||||
other_identity: Option<UserIdentities>,
|
||||
transaction_id: Option<String>,
|
||||
) -> (Sas, StartContent) {
|
||||
) -> (Sas, OutgoingContent) {
|
||||
let (inner, content) = InnerSas::start(
|
||||
account.clone(),
|
||||
other_device.clone(),
|
||||
|
@ -181,7 +183,7 @@ impl Sas {
|
|||
other_device: ReadOnlyDevice,
|
||||
store: Arc<Box<dyn CryptoStore>>,
|
||||
other_identity: Option<UserIdentities>,
|
||||
) -> (Sas, StartContent) {
|
||||
) -> (Sas, OutgoingContent) {
|
||||
let (inner, content) = InnerSas::start_in_room(
|
||||
flow_id,
|
||||
room_id,
|
||||
|
@ -214,18 +216,22 @@ impl Sas {
|
|||
/// * `event` - The m.key.verification.start event that was sent to us by
|
||||
/// the other side.
|
||||
pub(crate) fn from_start_event(
|
||||
content: impl Into<StartContent>,
|
||||
flow_id: FlowId,
|
||||
content: &StartContent,
|
||||
store: Arc<Box<dyn CryptoStore>>,
|
||||
account: ReadOnlyAccount,
|
||||
private_identity: PrivateCrossSigningIdentity,
|
||||
other_device: ReadOnlyDevice,
|
||||
other_identity: Option<UserIdentities>,
|
||||
started_from_request: bool,
|
||||
) -> Result<Sas, OutgoingContent> {
|
||||
let inner = InnerSas::from_start_event(
|
||||
account.clone(),
|
||||
other_device.clone(),
|
||||
flow_id,
|
||||
content,
|
||||
other_identity.clone(),
|
||||
started_from_request,
|
||||
)?;
|
||||
|
||||
Ok(Self::start_helper(
|
||||
|
@ -257,11 +263,11 @@ impl Sas {
|
|||
settings: AcceptSettings,
|
||||
) -> Option<OutgoingVerificationRequest> {
|
||||
self.inner.lock().unwrap().accept().map(|c| match settings.apply(c) {
|
||||
AcceptContent::ToDevice(c) => {
|
||||
OwnedAcceptContent::ToDevice(c) => {
|
||||
let content = AnyToDeviceEventContent::KeyVerificationAccept(c);
|
||||
self.content_to_request(content).into()
|
||||
}
|
||||
AcceptContent::Room(room_id, content) => RoomMessageRequest {
|
||||
OwnedAcceptContent::Room(room_id, content) => RoomMessageRequest {
|
||||
room_id,
|
||||
txn_id: Uuid::new_v4(),
|
||||
content: AnyMessageEventContent::KeyVerificationAccept(content),
|
||||
|
@ -293,15 +299,10 @@ impl Sas {
|
|||
};
|
||||
|
||||
let mac_request = content.map(|c| match c {
|
||||
event_enums::MacContent::ToDevice(c) => {
|
||||
self.content_to_request(AnyToDeviceEventContent::KeyVerificationMac(c)).into()
|
||||
OutgoingContent::ToDevice(c) => self.content_to_request(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 {
|
||||
|
@ -337,15 +338,10 @@ impl Sas {
|
|||
let (sas, content) = sas.cancel(code);
|
||||
*guard = sas;
|
||||
content.map(|c| match c {
|
||||
CancelContent::Room(room_id, content) => RoomMessageRequest {
|
||||
room_id,
|
||||
txn_id: Uuid::new_v4(),
|
||||
content: AnyMessageEventContent::KeyVerificationCancel(content),
|
||||
}
|
||||
.into(),
|
||||
CancelContent::ToDevice(c) => {
|
||||
self.content_to_request(AnyToDeviceEventContent::KeyVerificationCancel(c)).into()
|
||||
OutgoingContent::Room(room_id, content) => {
|
||||
RoomMessageRequest { room_id, txn_id: Uuid::new_v4(), content }.into()
|
||||
}
|
||||
OutgoingContent::ToDevice(c) => self.content_to_request(c).into(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -406,19 +402,14 @@ impl Sas {
|
|||
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 sas: InnerSas = (*guard).clone();
|
||||
let (sas, content) = sas.receive_room_event(event);
|
||||
*guard = sas;
|
||||
|
||||
content
|
||||
}
|
||||
|
||||
pub(crate) fn receive_event(&self, event: &AnyToDeviceEvent) -> Option<OutgoingContent> {
|
||||
let mut guard = self.inner.lock().unwrap();
|
||||
let sas: InnerSas = (*guard).clone();
|
||||
let (sas, content) = sas.receive_event(event);
|
||||
let (sas, content) = sas.receive_any_event(sender, content);
|
||||
*guard = sas;
|
||||
|
||||
content
|
||||
|
@ -465,13 +456,16 @@ impl AcceptSettings {
|
|||
Self { allowed_methods: methods }
|
||||
}
|
||||
|
||||
fn apply(self, mut content: AcceptContent) -> AcceptContent {
|
||||
fn apply(self, mut content: OwnedAcceptContent) -> OwnedAcceptContent {
|
||||
match &mut content {
|
||||
AcceptContent::ToDevice(AcceptToDeviceEventContent {
|
||||
OwnedAcceptContent::ToDevice(AcceptToDeviceEventContent {
|
||||
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));
|
||||
content
|
||||
}
|
||||
|
@ -490,7 +484,10 @@ mod test {
|
|||
use crate::{
|
||||
olm::PrivateCrossSigningIdentity,
|
||||
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,
|
||||
};
|
||||
|
||||
|
@ -534,47 +531,51 @@ mod test {
|
|||
None,
|
||||
);
|
||||
|
||||
let flow_id = alice.flow_id().to_owned();
|
||||
let content = StartContent::try_from(&content).unwrap();
|
||||
|
||||
let bob = Sas::from_start_event(
|
||||
content,
|
||||
flow_id,
|
||||
&content,
|
||||
bob_store,
|
||||
bob,
|
||||
PrivateCrossSigningIdentity::empty(bob_id()),
|
||||
alice_device,
|
||||
None,
|
||||
false,
|
||||
)
|
||||
.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!(!bob.can_be_presented());
|
||||
|
||||
let event = wrap_any_to_device_content(alice.user_id(), content.unwrap());
|
||||
let event = wrap_any_to_device_content(bob.user_id(), bob.receive_event(&event).unwrap());
|
||||
let content = KeyContent::try_from(&content).unwrap();
|
||||
let content = bob.receive_any_event(alice.user_id(), &content.into()).unwrap();
|
||||
|
||||
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_eq!(alice.emoji().unwrap(), bob.emoji().unwrap());
|
||||
assert_eq!(alice.decimals().unwrap(), bob.decimals().unwrap());
|
||||
|
||||
let event = wrap_any_to_device_content(
|
||||
alice.user_id(),
|
||||
get_content_from_request(&alice.confirm().await.unwrap().0.unwrap()),
|
||||
);
|
||||
bob.receive_event(&event);
|
||||
let request = alice.confirm().await.unwrap().0.unwrap();
|
||||
let content = OutgoingContent::try_from(request).unwrap();
|
||||
let content = MacContent::try_from(&content).unwrap();
|
||||
bob.receive_any_event(alice.user_id(), &content.into());
|
||||
|
||||
let event = wrap_any_to_device_content(
|
||||
bob.user_id(),
|
||||
get_content_from_request(&bob.confirm().await.unwrap().0.unwrap()),
|
||||
);
|
||||
alice.receive_event(&event);
|
||||
let request = bob.confirm().await.unwrap().0.unwrap();
|
||||
let content = OutgoingContent::try_from(request).unwrap();
|
||||
let content = MacContent::try_from(&content).unwrap();
|
||||
alice.receive_any_event(bob.user_id(), &content.into());
|
||||
|
||||
assert!(alice.verified_devices().unwrap().contains(&alice.other_device()));
|
||||
assert!(bob.verified_devices().unwrap().contains(&bob.other_device()));
|
||||
|
|
|
@ -20,20 +20,23 @@ use std::{
|
|||
};
|
||||
|
||||
use matrix_sdk_common::{
|
||||
events::key::verification::{
|
||||
accept::{
|
||||
AcceptEventContent, AcceptMethod, AcceptToDeviceEventContent,
|
||||
SasV1Content as AcceptV1Content, SasV1ContentInit as AcceptV1ContentInit,
|
||||
events::{
|
||||
key::verification::{
|
||||
accept::{
|
||||
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,
|
||||
done::DoneEventContent,
|
||||
key::{KeyEventContent, KeyToDeviceEventContent},
|
||||
start::{
|
||||
SasV1Content, SasV1ContentInit, StartEventContent, StartMethod,
|
||||
StartToDeviceEventContent,
|
||||
},
|
||||
HashAlgorithm, KeyAgreementProtocol, MessageAuthenticationCode, Relation,
|
||||
ShortAuthenticationString, VerificationMethod,
|
||||
AnyMessageEventContent, AnyToDeviceEventContent,
|
||||
},
|
||||
identifiers::{DeviceId, EventId, RoomId, UserId},
|
||||
uuid::Uuid,
|
||||
|
@ -42,17 +45,21 @@ use olm_rs::sas::OlmSas;
|
|||
use tracing::info;
|
||||
|
||||
use super::{
|
||||
event_enums::{
|
||||
AcceptContent, CancelContent, DoneContent, KeyContent, MacContent, StartContent,
|
||||
},
|
||||
helpers::{
|
||||
calculate_commitment, get_decimal, get_emoji, get_emoji_index, get_mac_content,
|
||||
receive_mac_event, SasIds,
|
||||
},
|
||||
OutgoingContent,
|
||||
};
|
||||
use crate::{
|
||||
identities::{ReadOnlyDevice, UserIdentities},
|
||||
verification::{Cancelled, Done, FlowId},
|
||||
verification::{
|
||||
event_enums::{
|
||||
AcceptContent, DoneContent, KeyContent, MacContent, OwnedAcceptContent,
|
||||
OwnedStartContent, StartContent,
|
||||
},
|
||||
Cancelled, Done, FlowId,
|
||||
},
|
||||
ReadOnlyAccount,
|
||||
};
|
||||
|
||||
|
@ -196,6 +203,9 @@ pub struct SasState<S: Clone> {
|
|||
|
||||
/// The SAS state we're in.
|
||||
pub state: Arc<S>,
|
||||
|
||||
/// Did the SAS verification start from a `m.verification.request`.
|
||||
pub started_from_request: bool,
|
||||
}
|
||||
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
|
@ -227,7 +237,7 @@ pub struct Started {
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct Accepted {
|
||||
pub accepted_protocols: Arc<AcceptedProtocols>,
|
||||
start_content: Arc<StartContent>,
|
||||
start_content: Arc<OwnedStartContent>,
|
||||
commitment: String,
|
||||
}
|
||||
|
||||
|
@ -296,6 +306,7 @@ impl<S: Clone> SasState<S> {
|
|||
last_event_time: self.last_event_time,
|
||||
verification_flow_id: self.verification_flow_id,
|
||||
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>,
|
||||
transaction_id: Option<String>,
|
||||
) -> SasState<Created> {
|
||||
let started_from_request = transaction_id.is_some();
|
||||
let flow_id =
|
||||
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.
|
||||
|
@ -369,7 +381,7 @@ impl SasState<Created> {
|
|||
other_identity: Option<UserIdentities>,
|
||||
) -> SasState<Created> {
|
||||
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(
|
||||
|
@ -377,6 +389,7 @@ impl SasState<Created> {
|
|||
account: ReadOnlyAccount,
|
||||
other_device: ReadOnlyDevice,
|
||||
other_identity: Option<UserIdentities>,
|
||||
started_from_request: bool,
|
||||
) -> SasState<Created> {
|
||||
SasState {
|
||||
inner: Arc::new(Mutex::new(OlmSas::new())),
|
||||
|
@ -385,6 +398,7 @@ impl SasState<Created> {
|
|||
|
||||
creation_time: Arc::new(Instant::now()),
|
||||
last_event_time: Arc::new(Instant::now()),
|
||||
started_from_request,
|
||||
|
||||
state: Arc::new(Created {
|
||||
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() {
|
||||
FlowId::ToDevice(s) => StartContent::ToDevice(StartToDeviceEventContent::new(
|
||||
FlowId::ToDevice(s) => OwnedStartContent::ToDevice(StartToDeviceEventContent::new(
|
||||
self.device_id().into(),
|
||||
s.to_string(),
|
||||
StartMethod::SasV1(
|
||||
|
@ -407,7 +421,7 @@ impl SasState<Created> {
|
|||
.expect("Invalid initial protocol definitions."),
|
||||
),
|
||||
)),
|
||||
FlowId::InRoom(r, e) => StartContent::Room(
|
||||
FlowId::InRoom(r, e) => OwnedStartContent::Room(
|
||||
r.clone(),
|
||||
StartEventContent::new(
|
||||
self.device_id().into(),
|
||||
|
@ -431,11 +445,9 @@ impl SasState<Created> {
|
|||
pub fn into_accepted(
|
||||
self,
|
||||
sender: &UserId,
|
||||
content: impl Into<AcceptContent>,
|
||||
content: &AcceptContent,
|
||||
) -> Result<SasState<Accepted>, SasState<Cancelled>> {
|
||||
let content = content.into();
|
||||
self.check_event(&sender, content.flow_id().as_str())
|
||||
.map_err(|c| self.clone().cancel(c))?;
|
||||
self.check_event(&sender, content.flow_id()).map_err(|c| self.clone().cancel(c))?;
|
||||
|
||||
if let AcceptMethod::MSasV1(content) = content.method() {
|
||||
let accepted_protocols =
|
||||
|
@ -449,6 +461,7 @@ impl SasState<Created> {
|
|||
verification_flow_id: self.verification_flow_id,
|
||||
creation_time: self.creation_time,
|
||||
last_event_time: self.last_event_time,
|
||||
started_from_request: self.started_from_request,
|
||||
state: Arc::new(Accepted {
|
||||
start_content,
|
||||
commitment: content.commitment.clone(),
|
||||
|
@ -479,22 +492,18 @@ impl SasState<Started> {
|
|||
account: ReadOnlyAccount,
|
||||
other_device: ReadOnlyDevice,
|
||||
other_identity: Option<UserIdentities>,
|
||||
content: impl Into<StartContent>,
|
||||
) -> 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>,
|
||||
flow_id: FlowId,
|
||||
content: &StartContent,
|
||||
started_from_request: bool,
|
||||
) -> Result<SasState<Started>, SasState<Cancelled>> {
|
||||
let flow_id = Arc::new(flow_id);
|
||||
|
||||
let canceled = || SasState {
|
||||
inner: Arc::new(Mutex::new(OlmSas::new())),
|
||||
|
||||
creation_time: Arc::new(Instant::now()),
|
||||
last_event_time: Arc::new(Instant::now()),
|
||||
started_from_request,
|
||||
|
||||
ids: SasIds {
|
||||
account: account.clone(),
|
||||
|
@ -502,7 +511,7 @@ impl SasState<Started> {
|
|||
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)),
|
||||
};
|
||||
|
||||
|
@ -510,7 +519,7 @@ impl SasState<Started> {
|
|||
let sas = OlmSas::new();
|
||||
|
||||
let pubkey = sas.public_key();
|
||||
let commitment = calculate_commitment(&pubkey, content.clone());
|
||||
let commitment = calculate_commitment(&pubkey, content);
|
||||
|
||||
info!(
|
||||
"Calculated commitment for pubkey {} and content {:?} {}",
|
||||
|
@ -525,8 +534,9 @@ impl SasState<Started> {
|
|||
|
||||
creation_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 {
|
||||
accepted_protocols: accepted_protocols.into(),
|
||||
|
@ -548,7 +558,7 @@ impl SasState<Started> {
|
|||
/// This should be sent out automatically if the SAS verification flow has
|
||||
/// been started because of a
|
||||
/// 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(
|
||||
AcceptV1ContentInit {
|
||||
commitment: self.state.commitment.clone(),
|
||||
|
@ -591,12 +601,9 @@ impl SasState<Started> {
|
|||
pub fn into_key_received(
|
||||
self,
|
||||
sender: &UserId,
|
||||
content: impl Into<KeyContent>,
|
||||
content: &KeyContent,
|
||||
) -> Result<SasState<KeyReceived>, SasState<Cancelled>> {
|
||||
let content = content.into();
|
||||
|
||||
self.check_event(&sender, &content.flow_id().as_str())
|
||||
.map_err(|c| self.clone().cancel(c))?;
|
||||
self.check_event(&sender, &content.flow_id()).map_err(|c| self.clone().cancel(c))?;
|
||||
|
||||
let their_pubkey = content.public_key().to_owned();
|
||||
|
||||
|
@ -612,6 +619,7 @@ impl SasState<Started> {
|
|||
verification_flow_id: self.verification_flow_id,
|
||||
creation_time: self.creation_time,
|
||||
last_event_time: self.last_event_time,
|
||||
started_from_request: self.started_from_request,
|
||||
state: Arc::new(KeyReceived {
|
||||
we_started: false,
|
||||
their_pubkey,
|
||||
|
@ -633,15 +641,14 @@ impl SasState<Accepted> {
|
|||
pub fn into_key_received(
|
||||
self,
|
||||
sender: &UserId,
|
||||
content: impl Into<KeyContent>,
|
||||
content: &KeyContent,
|
||||
) -> 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 commitment =
|
||||
calculate_commitment(content.public_key(), self.state.start_content.as_ref().clone());
|
||||
let commitment = calculate_commitment(
|
||||
content.public_key(),
|
||||
&self.state.start_content.as_start_content(),
|
||||
);
|
||||
|
||||
if self.state.commitment != commitment {
|
||||
Err(self.cancel(CancelCode::InvalidMessage))
|
||||
|
@ -660,6 +667,7 @@ impl SasState<Accepted> {
|
|||
verification_flow_id: self.verification_flow_id,
|
||||
creation_time: self.creation_time,
|
||||
last_event_time: self.last_event_time,
|
||||
started_from_request: self.started_from_request,
|
||||
state: Arc::new(KeyReceived {
|
||||
their_pubkey,
|
||||
we_started: true,
|
||||
|
@ -672,19 +680,21 @@ impl SasState<Accepted> {
|
|||
/// Get the content for the key event.
|
||||
///
|
||||
/// The content needs to be automatically sent to the other side.
|
||||
pub fn as_content(&self) -> KeyContent {
|
||||
pub fn as_content(&self) -> OutgoingContent {
|
||||
match &*self.verification_flow_id {
|
||||
FlowId::ToDevice(s) => KeyToDeviceEventContent {
|
||||
transaction_id: s.to_string(),
|
||||
key: self.inner.lock().unwrap().public_key(),
|
||||
FlowId::ToDevice(s) => {
|
||||
AnyToDeviceEventContent::KeyVerificationKey(KeyToDeviceEventContent {
|
||||
transaction_id: s.to_string(),
|
||||
key: self.inner.lock().unwrap().public_key(),
|
||||
})
|
||||
.into()
|
||||
}
|
||||
.into(),
|
||||
FlowId::InRoom(r, e) => (
|
||||
r.clone(),
|
||||
KeyEventContent::new(
|
||||
AnyMessageEventContent::KeyVerificationKey(KeyEventContent::new(
|
||||
self.inner.lock().unwrap().public_key(),
|
||||
Relation::new(e.clone()),
|
||||
),
|
||||
)),
|
||||
)
|
||||
.into(),
|
||||
}
|
||||
|
@ -696,19 +706,21 @@ impl SasState<KeyReceived> {
|
|||
///
|
||||
/// The content needs to be automatically sent to the other side if and only
|
||||
/// if we_started is false.
|
||||
pub fn as_content(&self) -> KeyContent {
|
||||
pub fn as_content(&self) -> OutgoingContent {
|
||||
match &*self.verification_flow_id {
|
||||
FlowId::ToDevice(s) => KeyToDeviceEventContent {
|
||||
transaction_id: s.to_string(),
|
||||
key: self.inner.lock().unwrap().public_key(),
|
||||
FlowId::ToDevice(s) => {
|
||||
AnyToDeviceEventContent::KeyVerificationKey(KeyToDeviceEventContent {
|
||||
transaction_id: s.to_string(),
|
||||
key: self.inner.lock().unwrap().public_key(),
|
||||
})
|
||||
.into()
|
||||
}
|
||||
.into(),
|
||||
FlowId::InRoom(r, e) => (
|
||||
r.clone(),
|
||||
KeyEventContent::new(
|
||||
AnyMessageEventContent::KeyVerificationKey(KeyEventContent::new(
|
||||
self.inner.lock().unwrap().public_key(),
|
||||
Relation::new(e.clone()),
|
||||
),
|
||||
)),
|
||||
)
|
||||
.into(),
|
||||
}
|
||||
|
@ -766,12 +778,9 @@ impl SasState<KeyReceived> {
|
|||
pub fn into_mac_received(
|
||||
self,
|
||||
sender: &UserId,
|
||||
content: impl Into<MacContent>,
|
||||
content: &MacContent,
|
||||
) -> Result<SasState<MacReceived>, SasState<Cancelled>> {
|
||||
let content = content.into();
|
||||
|
||||
self.check_event(&sender, content.flow_id().as_str())
|
||||
.map_err(|c| self.clone().cancel(c))?;
|
||||
self.check_event(&sender, content.flow_id()).map_err(|c| self.clone().cancel(c))?;
|
||||
|
||||
let (devices, master_keys) = receive_mac_event(
|
||||
&self.inner.lock().unwrap(),
|
||||
|
@ -788,6 +797,7 @@ impl SasState<KeyReceived> {
|
|||
creation_time: self.creation_time,
|
||||
last_event_time: self.last_event_time,
|
||||
ids: self.ids,
|
||||
started_from_request: self.started_from_request,
|
||||
state: Arc::new(MacReceived {
|
||||
we_started: self.state.we_started,
|
||||
their_pubkey: self.state.their_pubkey.clone(),
|
||||
|
@ -805,6 +815,7 @@ impl SasState<KeyReceived> {
|
|||
pub fn confirm(self) -> SasState<Confirmed> {
|
||||
SasState {
|
||||
inner: self.inner,
|
||||
started_from_request: self.started_from_request,
|
||||
verification_flow_id: self.verification_flow_id,
|
||||
creation_time: self.creation_time,
|
||||
last_event_time: self.last_event_time,
|
||||
|
@ -827,12 +838,9 @@ impl SasState<Confirmed> {
|
|||
pub fn into_done(
|
||||
self,
|
||||
sender: &UserId,
|
||||
content: impl Into<MacContent>,
|
||||
content: &MacContent,
|
||||
) -> Result<SasState<Done>, SasState<Cancelled>> {
|
||||
let content = content.into();
|
||||
|
||||
self.check_event(&sender, &content.flow_id().as_str())
|
||||
.map_err(|c| self.clone().cancel(c))?;
|
||||
self.check_event(sender, content.flow_id()).map_err(|c| self.clone().cancel(c))?;
|
||||
|
||||
let (devices, master_keys) = receive_mac_event(
|
||||
&self.inner.lock().unwrap(),
|
||||
|
@ -848,6 +856,7 @@ impl SasState<Confirmed> {
|
|||
creation_time: self.creation_time,
|
||||
last_event_time: self.last_event_time,
|
||||
verification_flow_id: self.verification_flow_id,
|
||||
started_from_request: self.started_from_request,
|
||||
ids: self.ids,
|
||||
|
||||
state: Arc::new(Done {
|
||||
|
@ -869,12 +878,9 @@ impl SasState<Confirmed> {
|
|||
pub fn into_waiting_for_done(
|
||||
self,
|
||||
sender: &UserId,
|
||||
content: impl Into<MacContent>,
|
||||
content: &MacContent,
|
||||
) -> Result<SasState<WaitingForDone>, SasState<Cancelled>> {
|
||||
let content = content.into();
|
||||
|
||||
self.check_event(&sender, &content.flow_id().as_str())
|
||||
.map_err(|c| self.clone().cancel(c))?;
|
||||
self.check_event(&sender, &content.flow_id()).map_err(|c| self.clone().cancel(c))?;
|
||||
|
||||
let (devices, master_keys) = receive_mac_event(
|
||||
&self.inner.lock().unwrap(),
|
||||
|
@ -890,6 +896,7 @@ impl SasState<Confirmed> {
|
|||
creation_time: self.creation_time,
|
||||
last_event_time: self.last_event_time,
|
||||
verification_flow_id: self.verification_flow_id,
|
||||
started_from_request: self.started_from_request,
|
||||
ids: self.ids,
|
||||
|
||||
state: Arc::new(WaitingForDone {
|
||||
|
@ -902,7 +909,7 @@ impl SasState<Confirmed> {
|
|||
/// Get the content for the mac event.
|
||||
///
|
||||
/// The content needs to be automatically sent to the other side.
|
||||
pub fn as_content(&self) -> MacContent {
|
||||
pub fn as_content(&self) -> OutgoingContent {
|
||||
get_mac_content(&self.inner.lock().unwrap(), &self.ids, &self.verification_flow_id)
|
||||
}
|
||||
}
|
||||
|
@ -917,6 +924,7 @@ impl SasState<MacReceived> {
|
|||
inner: self.inner,
|
||||
verification_flow_id: self.verification_flow_id,
|
||||
creation_time: self.creation_time,
|
||||
started_from_request: self.started_from_request,
|
||||
last_event_time: self.last_event_time,
|
||||
ids: self.ids,
|
||||
state: Arc::new(Done {
|
||||
|
@ -937,6 +945,7 @@ impl SasState<MacReceived> {
|
|||
inner: self.inner,
|
||||
verification_flow_id: self.verification_flow_id,
|
||||
creation_time: self.creation_time,
|
||||
started_from_request: self.started_from_request,
|
||||
last_event_time: self.last_event_time,
|
||||
ids: self.ids,
|
||||
state: Arc::new(WaitingForDone {
|
||||
|
@ -994,18 +1003,23 @@ impl SasState<WaitingForDone> {
|
|||
///
|
||||
/// The content needs to be automatically sent to the other side if it
|
||||
/// 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)
|
||||
}
|
||||
|
||||
pub fn done_content(&self) -> DoneContent {
|
||||
pub fn done_content(&self) -> OutgoingContent {
|
||||
match self.verification_flow_id.as_ref() {
|
||||
FlowId::ToDevice(_) => {
|
||||
unreachable!("The done content isn't supported yet for to-device verifications")
|
||||
}
|
||||
FlowId::InRoom(r, e) => {
|
||||
(r.clone(), DoneEventContent::new(Relation::new(e.clone()))).into()
|
||||
}
|
||||
FlowId::ToDevice(t) => AnyToDeviceEventContent::KeyVerificationDone(
|
||||
DoneToDeviceEventContent::new(t.to_owned()),
|
||||
)
|
||||
.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(
|
||||
self,
|
||||
sender: &UserId,
|
||||
content: impl Into<DoneContent>,
|
||||
content: &DoneContent,
|
||||
) -> Result<SasState<Done>, SasState<Cancelled>> {
|
||||
let content = content.into();
|
||||
|
||||
self.check_event(&sender, &content.flow_id().as_str())
|
||||
.map_err(|c| self.clone().cancel(c))?;
|
||||
self.check_event(&sender, content.flow_id()).map_err(|c| self.clone().cancel(c))?;
|
||||
|
||||
Ok(SasState {
|
||||
inner: self.inner,
|
||||
creation_time: self.creation_time,
|
||||
last_event_time: self.last_event_time,
|
||||
verification_flow_id: self.verification_flow_id,
|
||||
started_from_request: self.started_from_request,
|
||||
ids: self.ids,
|
||||
|
||||
state: Arc::new(Done {
|
||||
|
@ -1046,18 +1058,23 @@ impl SasState<Done> {
|
|||
///
|
||||
/// The content needs to be automatically sent to the other side if it
|
||||
/// wasn't already sent.
|
||||
pub fn as_content(&self) -> MacContent {
|
||||
pub fn as_content(&self) -> OutgoingContent {
|
||||
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() {
|
||||
FlowId::ToDevice(_) => {
|
||||
unreachable!("The done content isn't supported yet for to-device verifications")
|
||||
}
|
||||
FlowId::InRoom(r, e) => {
|
||||
(r.clone(), DoneEventContent::new(Relation::new(e.clone()))).into()
|
||||
}
|
||||
FlowId::ToDevice(t) => AnyToDeviceEventContent::KeyVerificationDone(
|
||||
DoneToDeviceEventContent::new(t.to_owned()),
|
||||
)
|
||||
.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> {
|
||||
pub fn as_content(&self) -> CancelContent {
|
||||
pub fn as_content(&self) -> OutgoingContent {
|
||||
self.state.as_content(&self.verification_flow_id)
|
||||
}
|
||||
}
|
||||
|
@ -1092,7 +1109,7 @@ mod test {
|
|||
|
||||
use super::{Accepted, Created, SasState, Started};
|
||||
use crate::{
|
||||
verification::sas::{event_enums::AcceptContent, StartContent},
|
||||
verification::event_enums::{AcceptContent, KeyContent, MacContent, StartContent},
|
||||
ReadOnlyAccount, ReadOnlyDevice,
|
||||
};
|
||||
|
||||
|
@ -1122,9 +1139,16 @@ mod test {
|
|||
let alice_sas = SasState::<Created>::new(alice.clone(), bob_device, None, None);
|
||||
|
||||
let start_content = alice_sas.as_content();
|
||||
let flow_id = start_content.flow_id();
|
||||
|
||||
let bob_sas =
|
||||
SasState::<Started>::from_start_event(bob.clone(), alice_device, None, start_content);
|
||||
let bob_sas = SasState::<Started>::from_start_event(
|
||||
bob.clone(),
|
||||
alice_device,
|
||||
None,
|
||||
flow_id,
|
||||
&start_content.as_start_content(),
|
||||
false,
|
||||
);
|
||||
|
||||
(alice_sas, bob_sas.unwrap())
|
||||
}
|
||||
|
@ -1137,10 +1161,10 @@ mod test {
|
|||
#[tokio::test]
|
||||
async fn sas_accept() {
|
||||
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(), event).unwrap();
|
||||
alice.into_accepted(bob.user_id(), &content).unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -1148,15 +1172,18 @@ mod test {
|
|||
let (alice, bob) = get_sas_pair().await;
|
||||
|
||||
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 = 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 = 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_emoji(), bob.get_emoji());
|
||||
|
@ -1167,15 +1194,18 @@ mod test {
|
|||
let (alice, bob) = get_sas_pair().await;
|
||||
|
||||
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 = 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 = 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_emoji(), bob.get_emoji());
|
||||
|
@ -1185,14 +1215,16 @@ mod test {
|
|||
let bob = bob.confirm();
|
||||
|
||||
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_eq!(alice.get_decimal(), bob_decimals);
|
||||
let alice = alice.confirm();
|
||||
|
||||
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!(alice.verified_devices().contains(&alice.other_device()));
|
||||
|
@ -1203,11 +1235,7 @@ mod test {
|
|||
let (alice, bob) = get_sas_pair().await;
|
||||
|
||||
let mut content = bob.as_content();
|
||||
|
||||
let mut method = match &mut content {
|
||||
AcceptContent::ToDevice(c) => &mut c.method,
|
||||
AcceptContent::Room(_, c) => &mut c.method,
|
||||
};
|
||||
let mut method = content.method_mut();
|
||||
|
||||
match &mut method {
|
||||
AcceptMethod::MSasV1(ref mut c) => {
|
||||
|
@ -1216,14 +1244,18 @@ mod test {
|
|||
_ => 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 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 = KeyContent::try_from(&content).unwrap();
|
||||
|
||||
alice
|
||||
.into_key_received(bob.user_id(), content)
|
||||
.into_key_received(bob.user_id(), &content)
|
||||
.expect_err("Didn't cancel on invalid commitment");
|
||||
}
|
||||
|
||||
|
@ -1232,8 +1264,9 @@ mod test {
|
|||
let (alice, bob) = get_sas_pair().await;
|
||||
|
||||
let content = bob.as_content();
|
||||
let content = AcceptContent::from(&content);
|
||||
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]
|
||||
|
@ -1241,11 +1274,7 @@ mod test {
|
|||
let (alice, bob) = get_sas_pair().await;
|
||||
|
||||
let mut content = bob.as_content();
|
||||
|
||||
let mut method = match &mut content {
|
||||
AcceptContent::ToDevice(c) => &mut c.method,
|
||||
AcceptContent::Room(_, c) => &mut c.method,
|
||||
};
|
||||
let mut method = content.method_mut();
|
||||
|
||||
match &mut method {
|
||||
AcceptMethod::MSasV1(ref mut c) => {
|
||||
|
@ -1254,8 +1283,10 @@ mod test {
|
|||
_ => panic!("Unknown accept event content"),
|
||||
}
|
||||
|
||||
let content = AcceptContent::from(&content);
|
||||
|
||||
alice
|
||||
.into_accepted(bob.user_id(), content)
|
||||
.into_accepted(bob.user_id(), &content)
|
||||
.expect_err("Didn't cancel on an invalid SAS method");
|
||||
}
|
||||
|
||||
|
@ -1264,19 +1295,17 @@ mod test {
|
|||
let (alice, bob) = get_sas_pair().await;
|
||||
|
||||
let mut content = bob.as_content();
|
||||
|
||||
let method = match &mut content {
|
||||
AcceptContent::ToDevice(c) => &mut c.method,
|
||||
AcceptContent::Room(_, c) => &mut c.method,
|
||||
};
|
||||
let method = content.method_mut();
|
||||
|
||||
*method = AcceptMethod::Custom(CustomContent {
|
||||
method: "m.sas.custom".to_string(),
|
||||
data: Default::default(),
|
||||
});
|
||||
|
||||
let content = AcceptContent::from(&content);
|
||||
|
||||
alice
|
||||
.into_accepted(bob.user_id(), content)
|
||||
.into_accepted(bob.user_id(), &content)
|
||||
.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 mut start_content = alice_sas.as_content();
|
||||
|
||||
let method = match &mut start_content {
|
||||
StartContent::ToDevice(c) => &mut c.method,
|
||||
StartContent::Room(_, c) => &mut c.method,
|
||||
};
|
||||
let method = start_content.method_mut();
|
||||
|
||||
match method {
|
||||
StartMethod::SasV1(ref mut c) => {
|
||||
|
@ -1304,27 +1329,38 @@ mod test {
|
|||
_ => panic!("Unknown SAS start method"),
|
||||
}
|
||||
|
||||
let flow_id = start_content.flow_id();
|
||||
let content = StartContent::from(&start_content);
|
||||
|
||||
SasState::<Started>::from_start_event(
|
||||
bob.clone(),
|
||||
alice_device.clone(),
|
||||
None,
|
||||
start_content,
|
||||
flow_id,
|
||||
&content,
|
||||
false,
|
||||
)
|
||||
.expect_err("Didn't cancel on invalid MAC method");
|
||||
|
||||
let mut start_content = alice_sas.as_content();
|
||||
|
||||
let method = match &mut start_content {
|
||||
StartContent::ToDevice(c) => &mut c.method,
|
||||
StartContent::Room(_, c) => &mut c.method,
|
||||
};
|
||||
let method = start_content.method_mut();
|
||||
|
||||
*method = StartMethod::Custom(CustomStartContent {
|
||||
method: "m.sas.custom".to_string(),
|
||||
data: Default::default(),
|
||||
});
|
||||
|
||||
SasState::<Started>::from_start_event(bob.clone(), alice_device, None, start_content)
|
||||
.expect_err("Didn't cancel on unknown sas method");
|
||||
let flow_id = start_content.flow_id();
|
||||
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