crypto: Make the cancelations output only CancelContents.
This commit is contained in:
parent
b6e28e2280
commit
79102b3390
10 changed files with 498 additions and 127 deletions
|
@ -135,19 +135,42 @@ async fn login(
|
|||
if !initial.load(Ordering::SeqCst) {
|
||||
for (_room_id, room_info) in response.rooms.join {
|
||||
for event in room_info.timeline.events {
|
||||
if let Ok(AnySyncRoomEvent::Message(AnySyncMessageEvent::RoomMessage(m))) =
|
||||
event.deserialize()
|
||||
{
|
||||
if let MessageEventContent::VerificationRequest(_) = &m.content {
|
||||
let request = client
|
||||
.get_verification_request(&m.event_id)
|
||||
.await
|
||||
.expect("Request object wasn't created");
|
||||
if let AnySyncRoomEvent::Message(event) = event.deserialize().unwrap() {
|
||||
match event {
|
||||
AnySyncMessageEvent::RoomMessage(m) => {
|
||||
if let MessageEventContent::VerificationRequest(_) = &m.content
|
||||
{
|
||||
let request = client
|
||||
.get_verification_request(&m.event_id)
|
||||
.await
|
||||
.expect("Request object wasn't created");
|
||||
|
||||
request
|
||||
.accept()
|
||||
.await
|
||||
.expect("Can't accept verification request");
|
||||
request
|
||||
.accept()
|
||||
.await
|
||||
.expect("Can't accept verification request");
|
||||
}
|
||||
}
|
||||
AnySyncMessageEvent::KeyVerificationKey(e) => {
|
||||
let sas = client
|
||||
.get_verification(&e.content.relation.event_id.as_str())
|
||||
.await
|
||||
.expect("Sas object wasn't created");
|
||||
|
||||
tokio::spawn(wait_for_confirmation((*client).clone(), sas));
|
||||
}
|
||||
AnySyncMessageEvent::KeyVerificationMac(e) => {
|
||||
let sas = client
|
||||
.get_verification(&e.content.relation.event_id.as_str())
|
||||
.await
|
||||
.expect("Sas object wasn't created");
|
||||
|
||||
if sas.is_done() {
|
||||
print_result(&sas);
|
||||
print_devices(&e.sender, &client).await;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1160,7 +1160,7 @@ impl Client {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn room_send_helper(
|
||||
pub(crate) async fn room_send_helper(
|
||||
&self,
|
||||
request: &RoomMessageRequest,
|
||||
) -> Result<send_message_event::Response> {
|
||||
|
|
|
@ -39,10 +39,18 @@ impl Sas {
|
|||
|
||||
/// Confirm that the short auth strings match on both sides.
|
||||
pub async fn confirm(&self) -> Result<()> {
|
||||
let (to_device, signature) = self.inner.confirm().await?;
|
||||
let (request, signature) = self.inner.confirm().await?;
|
||||
|
||||
if let Some(request) = to_device {
|
||||
self.client.send_to_device(&request).await?;
|
||||
match request {
|
||||
Some(OutgoingVerificationRequest::InRoom(r)) => {
|
||||
self.client.room_send_helper(&r).await?;
|
||||
}
|
||||
|
||||
Some(OutgoingVerificationRequest::ToDevice(r)) => {
|
||||
self.client.send_to_device(&r).await?;
|
||||
}
|
||||
|
||||
None => (),
|
||||
}
|
||||
|
||||
if let Some(s) = signature {
|
||||
|
@ -55,7 +63,14 @@ impl Sas {
|
|||
/// Cancel the interactive verification flow.
|
||||
pub async fn cancel(&self) -> Result<()> {
|
||||
if let Some(request) = self.inner.cancel() {
|
||||
self.client.send_to_device(&request).await?;
|
||||
match request {
|
||||
OutgoingVerificationRequest::ToDevice(r) => {
|
||||
self.client.send_to_device(&r).await?;
|
||||
}
|
||||
OutgoingVerificationRequest::InRoom(r) => {
|
||||
self.client.room_send_helper(&r).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -166,6 +166,24 @@ impl From<SignatureUploadRequest> for OutgoingRequests {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<OutgoingVerificationRequest> for OutgoingRequest {
|
||||
fn from(r: OutgoingVerificationRequest) -> Self {
|
||||
Self {
|
||||
request_id: r.request_id(),
|
||||
request: Arc::new(r.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SignatureUploadRequest> for OutgoingRequest {
|
||||
fn from(r: SignatureUploadRequest) -> Self {
|
||||
Self {
|
||||
request_id: Uuid::new_v4(),
|
||||
request: Arc::new(r.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Enum over all the incoming responses we need to receive.
|
||||
#[derive(Debug)]
|
||||
pub enum IncomingResponse<'a> {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::{convert::TryFrom, sync::Arc};
|
||||
|
||||
use dashmap::DashMap;
|
||||
|
||||
|
@ -20,7 +20,7 @@ use tracing::{info, trace, warn};
|
|||
|
||||
use matrix_sdk_common::{
|
||||
events::{
|
||||
room::message::MessageEventContent, AnySyncMessageEvent, AnySyncRoomEvent,
|
||||
room::message::MessageEventContent, AnyMessageEvent, AnySyncMessageEvent, AnySyncRoomEvent,
|
||||
AnyToDeviceEvent, AnyToDeviceEventContent,
|
||||
},
|
||||
identifiers::{DeviceId, EventId, RoomId, UserId},
|
||||
|
@ -112,8 +112,19 @@ impl VerificationMachine {
|
|||
}
|
||||
|
||||
pub fn get_sas(&self, transaction_id: &str) -> Option<Sas> {
|
||||
#[allow(clippy::map_clone)]
|
||||
self.verifications.get(transaction_id).map(|s| s.clone())
|
||||
let sas = if let Ok(e) = EventId::try_from(transaction_id) {
|
||||
#[allow(clippy::map_clone)]
|
||||
self.room_verifications.get(&e).map(|s| s.clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if sas.is_some() {
|
||||
sas
|
||||
} else {
|
||||
#[allow(clippy::map_clone)]
|
||||
self.verifications.get(transaction_id).map(|s| s.clone())
|
||||
}
|
||||
}
|
||||
|
||||
fn queue_up_content(
|
||||
|
@ -155,6 +166,13 @@ impl VerificationMachine {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn receive_room_event_helper(&self, sas: &Sas, event: &AnyMessageEvent) {
|
||||
if let Some(c) = sas.receive_room_event(event) {
|
||||
self.queue_up_content(sas.other_user_id(), sas.other_device_id(), c);
|
||||
}
|
||||
}
|
||||
|
||||
fn receive_event_helper(&self, sas: &Sas, event: &AnyToDeviceEvent) {
|
||||
if let Some(c) = sas.receive_event(event) {
|
||||
self.queue_up_content(sas.other_user_id(), sas.other_device_id(), c);
|
||||
|
@ -188,9 +206,9 @@ impl VerificationMachine {
|
|||
for sas in self.verifications.iter() {
|
||||
if let Some(r) = sas.cancel_if_timed_out() {
|
||||
self.outgoing_to_device_messages.insert(
|
||||
r.txn_id,
|
||||
r.request_id(),
|
||||
OutgoingRequest {
|
||||
request_id: r.txn_id,
|
||||
request_id: r.request_id(),
|
||||
request: Arc::new(r.into()),
|
||||
},
|
||||
);
|
||||
|
@ -204,6 +222,12 @@ impl VerificationMachine {
|
|||
event: &AnySyncRoomEvent,
|
||||
) -> Result<(), CryptoStoreError> {
|
||||
if let AnySyncRoomEvent::Message(m) = event {
|
||||
// Since this are room events we will get events that we send out on
|
||||
// our own as well.
|
||||
if m.sender() == self.account.user_id() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match m {
|
||||
AnySyncMessageEvent::RoomMessage(m) => {
|
||||
if let MessageEventContent::VerificationRequest(r) = &m.content {
|
||||
|
@ -245,25 +269,19 @@ impl VerificationMachine {
|
|||
self.store.get_user_identity(&e.sender).await?,
|
||||
) {
|
||||
Ok(s) => {
|
||||
// TODO we need to queue up the accept event
|
||||
// here.
|
||||
info!(
|
||||
"Started a new SAS verification, \
|
||||
automatically accepting because of in-room"
|
||||
);
|
||||
|
||||
// TODO remove this unwrap
|
||||
let accept_request = s.accept().unwrap();
|
||||
|
||||
self.room_verifications
|
||||
.insert(e.content.relation.event_id.clone(), s);
|
||||
|
||||
self.outgoing_room_messages.insert(
|
||||
accept_request.request_id(),
|
||||
OutgoingRequest {
|
||||
request_id: accept_request.request_id(),
|
||||
request: Arc::new(accept_request.into()),
|
||||
},
|
||||
);
|
||||
self.outgoing_room_messages
|
||||
.insert(accept_request.request_id(), accept_request.into());
|
||||
}
|
||||
Err(c) => {
|
||||
warn!(
|
||||
|
@ -276,6 +294,38 @@ impl VerificationMachine {
|
|||
}
|
||||
}
|
||||
}
|
||||
AnySyncMessageEvent::KeyVerificationKey(e) => {
|
||||
if let Some(s) = self.room_verifications.get(&e.content.relation.event_id) {
|
||||
self.receive_room_event_helper(
|
||||
&s,
|
||||
&m.clone().into_full_event(room_id.clone()),
|
||||
)
|
||||
};
|
||||
}
|
||||
AnySyncMessageEvent::KeyVerificationMac(e) => {
|
||||
if let Some(s) = self.room_verifications.get(&e.content.relation.event_id) {
|
||||
self.receive_room_event_helper(
|
||||
&s,
|
||||
&m.clone().into_full_event(room_id.clone()),
|
||||
);
|
||||
|
||||
if s.is_done() {
|
||||
match s.mark_as_done().await? {
|
||||
VerificationResult::Ok => (),
|
||||
VerificationResult::Cancel(r) => {
|
||||
self.outgoing_to_device_messages
|
||||
.insert(r.request_id(), r.into());
|
||||
}
|
||||
VerificationResult::SignatureUpload(r) => {
|
||||
let request: OutgoingRequest = r.into();
|
||||
|
||||
self.outgoing_to_device_messages
|
||||
.insert(request.request_id, request);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
@ -350,9 +400,9 @@ impl VerificationMachine {
|
|||
VerificationResult::Ok => (),
|
||||
VerificationResult::Cancel(r) => {
|
||||
self.outgoing_to_device_messages.insert(
|
||||
r.txn_id,
|
||||
r.request_id(),
|
||||
OutgoingRequest {
|
||||
request_id: r.txn_id,
|
||||
request_id: r.request_id(),
|
||||
request: Arc::new(r.into()),
|
||||
},
|
||||
);
|
||||
|
|
|
@ -14,16 +14,18 @@
|
|||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::convert::TryInto;
|
||||
use std::{collections::BTreeMap, convert::TryInto};
|
||||
|
||||
use matrix_sdk_common::{
|
||||
events::{
|
||||
key::verification::{
|
||||
accept::{AcceptEventContent, AcceptToDeviceEventContent},
|
||||
cancel::{CancelEventContent, CancelToDeviceEventContent},
|
||||
key::{KeyEventContent, KeyToDeviceEventContent},
|
||||
mac::{MacEventContent, MacToDeviceEventContent},
|
||||
start::{StartEventContent, StartMethod, StartToDeviceEventContent},
|
||||
KeyAgreementProtocol,
|
||||
},
|
||||
AnyMessageEventContent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent,
|
||||
AnyMessageEventContent, AnyToDeviceEventContent,
|
||||
},
|
||||
identifiers::RoomId,
|
||||
CanonicalJsonValue,
|
||||
|
@ -95,6 +97,96 @@ impl From<(RoomId, AcceptEventContent)> for AcceptContent {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum KeyContent {
|
||||
ToDevice(KeyToDeviceEventContent),
|
||||
Room(RoomId, KeyEventContent),
|
||||
}
|
||||
|
||||
impl KeyContent {
|
||||
pub fn flow_id(&self) -> FlowId {
|
||||
match self {
|
||||
KeyContent::ToDevice(c) => FlowId::ToDevice(c.transaction_id.clone()),
|
||||
KeyContent::Room(r, c) => FlowId::InRoom(r.clone(), c.relation.event_id.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn public_key(&self) -> &str {
|
||||
match self {
|
||||
KeyContent::ToDevice(c) => &c.key,
|
||||
KeyContent::Room(_, c) => &c.key,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KeyToDeviceEventContent> for KeyContent {
|
||||
fn from(content: KeyToDeviceEventContent) -> Self {
|
||||
KeyContent::ToDevice(content)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(RoomId, KeyEventContent)> for KeyContent {
|
||||
fn from(content: (RoomId, KeyEventContent)) -> Self {
|
||||
KeyContent::Room(content.0, content.1)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum MacContent {
|
||||
ToDevice(MacToDeviceEventContent),
|
||||
Room(RoomId, MacEventContent),
|
||||
}
|
||||
|
||||
impl MacContent {
|
||||
pub fn flow_id(&self) -> FlowId {
|
||||
match self {
|
||||
MacContent::ToDevice(c) => FlowId::ToDevice(c.transaction_id.clone()),
|
||||
MacContent::Room(r, c) => FlowId::InRoom(r.clone(), c.relation.event_id.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mac(&self) -> &BTreeMap<String, String> {
|
||||
match self {
|
||||
MacContent::ToDevice(c) => &c.mac,
|
||||
MacContent::Room(_, c) => &c.mac,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn keys(&self) -> &str {
|
||||
match self {
|
||||
MacContent::ToDevice(c) => &c.keys,
|
||||
MacContent::Room(_, c) => &c.keys,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MacToDeviceEventContent> for MacContent {
|
||||
fn from(content: MacToDeviceEventContent) -> Self {
|
||||
MacContent::ToDevice(content)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(RoomId, MacEventContent)> for MacContent {
|
||||
fn from(content: (RoomId, MacEventContent)) -> Self {
|
||||
MacContent::Room(content.0, content.1)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum CancelContent {
|
||||
ToDevice(CancelToDeviceEventContent),
|
||||
Room(RoomId, CancelEventContent),
|
||||
}
|
||||
|
||||
impl From<(RoomId, CancelEventContent)> for CancelContent {
|
||||
fn from(content: (RoomId, CancelEventContent)) -> Self {
|
||||
CancelContent::Room(content.0, content.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CancelToDeviceEventContent> for CancelContent {
|
||||
fn from(content: CancelToDeviceEventContent) -> Self {
|
||||
CancelContent::ToDevice(content)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum OutgoingContent {
|
||||
Room(RoomId, AnyMessageEventContent),
|
||||
|
@ -110,6 +202,26 @@ impl From<StartContent> for OutgoingContent {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<CancelContent> for OutgoingContent {
|
||||
fn from(content: CancelContent) -> Self {
|
||||
match content {
|
||||
CancelContent::Room(r, c) => {
|
||||
(r, AnyMessageEventContent::KeyVerificationCancel(c)).into()
|
||||
}
|
||||
CancelContent::ToDevice(c) => AnyToDeviceEventContent::KeyVerificationCancel(c).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KeyContent> for OutgoingContent {
|
||||
fn from(content: KeyContent) -> Self {
|
||||
match content {
|
||||
KeyContent::Room(r, c) => (r, AnyMessageEventContent::KeyVerificationKey(c)).into(),
|
||||
KeyContent::ToDevice(c) => AnyToDeviceEventContent::KeyVerificationKey(c).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AnyToDeviceEventContent> for OutgoingContent {
|
||||
fn from(content: AnyToDeviceEventContent) -> Self {
|
||||
OutgoingContent::ToDevice(content)
|
||||
|
|
|
@ -23,7 +23,10 @@ use matrix_sdk_common::{
|
|||
api::r0::to_device::DeviceIdOrAllDevices,
|
||||
events::{
|
||||
key::verification::{
|
||||
cancel::CancelCode, mac::MacToDeviceEventContent, start::StartToDeviceEventContent,
|
||||
cancel::CancelCode,
|
||||
mac::{MacEventContent, MacToDeviceEventContent},
|
||||
start::StartToDeviceEventContent,
|
||||
Relation,
|
||||
},
|
||||
AnyToDeviceEventContent, EventType, ToDeviceEvent,
|
||||
},
|
||||
|
@ -38,7 +41,10 @@ use crate::{
|
|||
ReadOnlyAccount, ToDeviceRequest,
|
||||
};
|
||||
|
||||
use super::{event_enums::StartContent, sas_state::FlowId};
|
||||
use super::{
|
||||
event_enums::{MacContent, StartContent},
|
||||
sas_state::FlowId,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SasIds {
|
||||
|
@ -186,7 +192,8 @@ pub fn receive_mac_event(
|
|||
sas: &OlmSas,
|
||||
ids: &SasIds,
|
||||
flow_id: &str,
|
||||
event: &ToDeviceEvent<MacToDeviceEventContent>,
|
||||
sender: &UserId,
|
||||
content: &MacContent,
|
||||
) -> Result<(Vec<ReadOnlyDevice>, Vec<UserIdentities>), CancelCode> {
|
||||
let mut verified_devices = Vec::new();
|
||||
let mut verified_identities = Vec::new();
|
||||
|
@ -195,25 +202,25 @@ pub fn receive_mac_event(
|
|||
|
||||
trace!(
|
||||
"Received a key.verification.mac event from {} {}",
|
||||
event.sender,
|
||||
sender,
|
||||
ids.other_device.device_id()
|
||||
);
|
||||
|
||||
let mut keys = event.content.mac.keys().cloned().collect::<Vec<String>>();
|
||||
let mut keys = content.mac().keys().cloned().collect::<Vec<String>>();
|
||||
keys.sort();
|
||||
let keys = sas
|
||||
.calculate_mac(&keys.join(","), &format!("{}KEY_IDS", &info))
|
||||
.expect("Can't calculate SAS MAC");
|
||||
|
||||
if keys != event.content.keys {
|
||||
if keys != content.keys() {
|
||||
return Err(CancelCode::KeyMismatch);
|
||||
}
|
||||
|
||||
for (key_id, key_mac) in &event.content.mac {
|
||||
for (key_id, key_mac) in content.mac() {
|
||||
trace!(
|
||||
"Checking MAC for the key id {} from {} {}",
|
||||
key_id,
|
||||
event.sender,
|
||||
sender,
|
||||
ids.other_device.device_id()
|
||||
);
|
||||
let key_id: DeviceKeyId = match key_id.as_str().try_into() {
|
||||
|
@ -227,6 +234,12 @@ pub fn receive_mac_event(
|
|||
.calculate_mac(key, &format!("{}{}", info, key_id))
|
||||
.expect("Can't calculate SAS MAC")
|
||||
{
|
||||
trace!(
|
||||
"Successfully verified the device key {} from {}",
|
||||
key_id,
|
||||
sender
|
||||
);
|
||||
|
||||
verified_devices.push(ids.other_device.clone());
|
||||
} else {
|
||||
return Err(CancelCode::KeyMismatch);
|
||||
|
@ -243,7 +256,7 @@ pub fn receive_mac_event(
|
|||
trace!(
|
||||
"Successfully verified the master key {} from {}",
|
||||
key_id,
|
||||
event.sender
|
||||
sender
|
||||
);
|
||||
verified_identities.push(identity.clone())
|
||||
} else {
|
||||
|
@ -255,7 +268,7 @@ pub fn receive_mac_event(
|
|||
"Key ID {} in MAC event from {} {} doesn't belong to any device \
|
||||
or user identity",
|
||||
key_id,
|
||||
event.sender,
|
||||
sender,
|
||||
ids.other_device.device_id()
|
||||
);
|
||||
}
|
||||
|
@ -297,7 +310,7 @@ fn extra_mac_info_send(ids: &SasIds, flow_id: &str) -> String {
|
|||
/// # Panics
|
||||
///
|
||||
/// This will panic if the public key of the other side wasn't set.
|
||||
pub fn get_mac_content(sas: &OlmSas, ids: &SasIds, flow_id: &FlowId) -> MacToDeviceEventContent {
|
||||
pub fn get_mac_content(sas: &OlmSas, ids: &SasIds, flow_id: &FlowId) -> MacContent {
|
||||
let mut mac: BTreeMap<String, String> = BTreeMap::new();
|
||||
|
||||
let key_id = DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, ids.account.device_id());
|
||||
|
@ -323,8 +336,19 @@ pub fn get_mac_content(sas: &OlmSas, ids: &SasIds, flow_id: &FlowId) -> MacToDev
|
|||
transaction_id: s.to_string(),
|
||||
keys,
|
||||
mac,
|
||||
},
|
||||
_ => todo!(),
|
||||
}
|
||||
.into(),
|
||||
FlowId::InRoom(r, e) => (
|
||||
r.clone(),
|
||||
MacEventContent {
|
||||
mac,
|
||||
keys,
|
||||
relation: Relation {
|
||||
event_id: e.clone(),
|
||||
},
|
||||
},
|
||||
)
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,8 @@ use matrix_sdk_common::{
|
|||
mac::MacToDeviceEventContent,
|
||||
start::{StartEventContent, StartToDeviceEventContent},
|
||||
},
|
||||
AnyToDeviceEvent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent,
|
||||
AnyMessageEvent, AnyMessageEventContent, AnySyncMessageEvent, AnyToDeviceEvent,
|
||||
AnyToDeviceEventContent, MessageEvent, ToDeviceEvent,
|
||||
},
|
||||
identifiers::{EventId, RoomId, UserId},
|
||||
};
|
||||
|
@ -36,7 +37,7 @@ use crate::{
|
|||
};
|
||||
|
||||
use super::{
|
||||
event_enums::{AcceptContent, OutgoingContent},
|
||||
event_enums::{AcceptContent, CancelContent, MacContent, OutgoingContent},
|
||||
sas_state::{
|
||||
Accepted, Canceled, Confirmed, Created, Done, FlowId, KeyReceived, MacReceived, SasState,
|
||||
Started,
|
||||
|
@ -91,7 +92,7 @@ impl InnerSas {
|
|||
sender: &UserId,
|
||||
content: impl Into<StartContent>,
|
||||
other_identity: Option<UserIdentities>,
|
||||
) -> Result<InnerSas, OutgoingContent> {
|
||||
) -> Result<InnerSas, CancelContent> {
|
||||
match SasState::<Started>::from_start_event(
|
||||
account,
|
||||
other_device,
|
||||
|
@ -127,7 +128,7 @@ impl InnerSas {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn cancel(self, code: CancelCode) -> (InnerSas, Option<OutgoingContent>) {
|
||||
pub fn cancel(self, code: CancelCode) -> (InnerSas, Option<CancelContent>) {
|
||||
let sas = match self {
|
||||
InnerSas::Created(s) => s.cancel(code),
|
||||
InnerSas::Started(s) => s.cancel(code),
|
||||
|
@ -142,7 +143,7 @@ impl InnerSas {
|
|||
(InnerSas::Canceled(sas), Some(content))
|
||||
}
|
||||
|
||||
pub fn confirm(self) -> (InnerSas, Option<MacToDeviceEventContent>) {
|
||||
pub fn confirm(self) -> (InnerSas, Option<MacContent>) {
|
||||
match self {
|
||||
InnerSas::KeyRecieved(s) => {
|
||||
let sas = s.confirm();
|
||||
|
@ -158,6 +159,62 @@ impl InnerSas {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn receive_room_event(
|
||||
self,
|
||||
event: &AnyMessageEvent,
|
||||
) -> (InnerSas, Option<OutgoingContent>) {
|
||||
match event {
|
||||
AnyMessageEvent::KeyVerificationKey(e) => match self {
|
||||
InnerSas::Accepted(s) => {
|
||||
match s.into_key_received(&e.sender, (e.room_id.clone(), e.content.clone())) {
|
||||
Ok(s) => (InnerSas::KeyRecieved(s), None),
|
||||
Err(s) => {
|
||||
let content = s.as_content();
|
||||
(InnerSas::Canceled(s), Some(content.into()))
|
||||
}
|
||||
}
|
||||
}
|
||||
InnerSas::Started(s) => {
|
||||
match s.into_key_received(&e.sender, (e.room_id.clone(), e.content.clone())) {
|
||||
Ok(s) => {
|
||||
let content = s.as_content();
|
||||
(InnerSas::KeyRecieved(s), Some(content.into()))
|
||||
}
|
||||
Err(s) => {
|
||||
let content = s.as_content();
|
||||
(InnerSas::Canceled(s), Some(content.into()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => (self, None),
|
||||
},
|
||||
AnyMessageEvent::KeyVerificationMac(e) => match self {
|
||||
InnerSas::KeyRecieved(s) => {
|
||||
match s.into_mac_received(&e.sender, (e.room_id.clone(), e.content.clone())) {
|
||||
Ok(s) => (InnerSas::MacReceived(s), None),
|
||||
Err(s) => {
|
||||
let content = s.as_content();
|
||||
(InnerSas::Canceled(s), Some(content.into()))
|
||||
}
|
||||
}
|
||||
}
|
||||
InnerSas::Confirmed(s) => {
|
||||
match s.into_done(&e.sender, (e.room_id.clone(), e.content.clone())) {
|
||||
Ok(s) => (InnerSas::Done(s), None),
|
||||
Err(s) => {
|
||||
let content = s.as_content();
|
||||
(InnerSas::Canceled(s), Some(content.into()))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (self, None),
|
||||
},
|
||||
_ => (self, None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receive_event(self, event: &AnyToDeviceEvent) -> (InnerSas, Option<OutgoingContent>) {
|
||||
match event {
|
||||
AnyToDeviceEvent::KeyVerificationAccept(e) => {
|
||||
|
@ -165,14 +222,11 @@ impl InnerSas {
|
|||
match s.into_accepted(e) {
|
||||
Ok(s) => {
|
||||
let content = s.as_content();
|
||||
(
|
||||
InnerSas::Accepted(s),
|
||||
Some(AnyToDeviceEventContent::KeyVerificationKey(content).into()),
|
||||
)
|
||||
(InnerSas::Accepted(s), Some(content.into()))
|
||||
}
|
||||
Err(s) => {
|
||||
let content = s.as_content();
|
||||
(InnerSas::Canceled(s), Some(content))
|
||||
(InnerSas::Canceled(s), Some(content.into()))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -180,41 +234,39 @@ impl InnerSas {
|
|||
}
|
||||
}
|
||||
AnyToDeviceEvent::KeyVerificationKey(e) => match self {
|
||||
InnerSas::Accepted(s) => match s.into_key_received(e) {
|
||||
InnerSas::Accepted(s) => match s.into_key_received(&e.sender, e.content.clone()) {
|
||||
Ok(s) => (InnerSas::KeyRecieved(s), None),
|
||||
Err(s) => {
|
||||
let content = s.as_content();
|
||||
(InnerSas::Canceled(s), Some(content))
|
||||
(InnerSas::Canceled(s), Some(content.into()))
|
||||
}
|
||||
},
|
||||
InnerSas::Started(s) => match s.into_key_received(e) {
|
||||
InnerSas::Started(s) => match s.into_key_received(&e.sender, e.content.clone()) {
|
||||
Ok(s) => {
|
||||
let content = s.as_content();
|
||||
(
|
||||
InnerSas::KeyRecieved(s),
|
||||
Some(AnyToDeviceEventContent::KeyVerificationKey(content).into()),
|
||||
)
|
||||
(InnerSas::KeyRecieved(s), Some(content.into()))
|
||||
}
|
||||
Err(s) => {
|
||||
let content = s.as_content();
|
||||
(InnerSas::Canceled(s), Some(content))
|
||||
(InnerSas::Canceled(s), Some(content.into()))
|
||||
}
|
||||
},
|
||||
_ => (self, None),
|
||||
},
|
||||
AnyToDeviceEvent::KeyVerificationMac(e) => match self {
|
||||
InnerSas::KeyRecieved(s) => match s.into_mac_received(e) {
|
||||
InnerSas::KeyRecieved(s) => match s.into_mac_received(&e.sender, e.content.clone())
|
||||
{
|
||||
Ok(s) => (InnerSas::MacReceived(s), None),
|
||||
Err(s) => {
|
||||
let content = s.as_content();
|
||||
(InnerSas::Canceled(s), Some(content))
|
||||
(InnerSas::Canceled(s), Some(content.into()))
|
||||
}
|
||||
},
|
||||
InnerSas::Confirmed(s) => match s.into_done(e) {
|
||||
InnerSas::Confirmed(s) => match s.into_done(&e.sender, e.content.clone()) {
|
||||
Ok(s) => (InnerSas::Done(s), None),
|
||||
Err(s) => {
|
||||
let content = s.as_content();
|
||||
(InnerSas::Canceled(s), Some(content))
|
||||
(InnerSas::Canceled(s), Some(content.into()))
|
||||
}
|
||||
},
|
||||
_ => (self, None),
|
||||
|
|
|
@ -31,8 +31,8 @@ use matrix_sdk_common::{
|
|||
cancel::CancelCode,
|
||||
start::{StartEventContent, StartToDeviceEventContent},
|
||||
},
|
||||
AnyMessageEventContent, AnyToDeviceEvent, AnyToDeviceEventContent, MessageEvent,
|
||||
ToDeviceEvent,
|
||||
AnyMessageEvent, AnyMessageEventContent, AnySyncMessageEvent, AnyToDeviceEvent,
|
||||
AnyToDeviceEventContent, MessageEvent, ToDeviceEvent,
|
||||
},
|
||||
identifiers::{DeviceId, EventId, RoomId, UserId},
|
||||
uuid::Uuid,
|
||||
|
@ -53,13 +53,15 @@ pub use sas_state::FlowId;
|
|||
|
||||
pub use event_enums::{OutgoingContent, StartContent};
|
||||
|
||||
use self::event_enums::CancelContent;
|
||||
|
||||
#[derive(Debug)]
|
||||
/// A result of a verification flow.
|
||||
pub enum VerificationResult {
|
||||
/// The verification succeeded, nothing needs to be done.
|
||||
Ok,
|
||||
/// The verification was canceled.
|
||||
Cancel(ToDeviceRequest),
|
||||
Cancel(OutgoingVerificationRequest),
|
||||
/// The verification is done and has signatures that need to be uploaded.
|
||||
SignatureUpload(SignatureUploadRequest),
|
||||
}
|
||||
|
@ -278,7 +280,13 @@ impl Sas {
|
|||
/// the server.
|
||||
pub async fn confirm(
|
||||
&self,
|
||||
) -> Result<(Option<ToDeviceRequest>, Option<SignatureUploadRequest>), CryptoStoreError> {
|
||||
) -> Result<
|
||||
(
|
||||
Option<OutgoingVerificationRequest>,
|
||||
Option<SignatureUploadRequest>,
|
||||
),
|
||||
CryptoStoreError,
|
||||
> {
|
||||
let (content, done) = {
|
||||
let mut guard = self.inner.lock().unwrap();
|
||||
let sas: InnerSas = (*guard).clone();
|
||||
|
@ -288,8 +296,17 @@ impl Sas {
|
|||
(content, guard.is_done())
|
||||
};
|
||||
|
||||
let mac_request = content
|
||||
.map(|c| self.content_to_request(AnyToDeviceEventContent::KeyVerificationMac(c)));
|
||||
let mac_request = content.map(|c| match c {
|
||||
event_enums::MacContent::ToDevice(c) => self
|
||||
.content_to_request(AnyToDeviceEventContent::KeyVerificationMac(c))
|
||||
.into(),
|
||||
event_enums::MacContent::Room(r, c) => RoomMessageRequest {
|
||||
room_id: r,
|
||||
txn_id: Uuid::new_v4(),
|
||||
content: AnyMessageEventContent::KeyVerificationMac(c),
|
||||
}
|
||||
.into(),
|
||||
});
|
||||
|
||||
if done {
|
||||
match self.mark_as_done().await? {
|
||||
|
@ -530,22 +547,26 @@ impl Sas {
|
|||
///
|
||||
/// Returns None if the `Sas` object is already in a canceled state,
|
||||
/// otherwise it returns a request that needs to be sent out.
|
||||
pub fn cancel(&self) -> Option<ToDeviceRequest> {
|
||||
pub fn cancel(&self) -> Option<OutgoingVerificationRequest> {
|
||||
let mut guard = self.inner.lock().unwrap();
|
||||
let sas: InnerSas = (*guard).clone();
|
||||
let (sas, content) = sas.cancel(CancelCode::User);
|
||||
*guard = sas;
|
||||
|
||||
content.map(|c| {
|
||||
if let OutgoingContent::ToDevice(c) = c {
|
||||
self.content_to_request(c)
|
||||
} else {
|
||||
todo!()
|
||||
content.map(|c| match c {
|
||||
CancelContent::Room(room_id, content) => RoomMessageRequest {
|
||||
room_id,
|
||||
txn_id: Uuid::new_v4(),
|
||||
content: AnyMessageEventContent::KeyVerificationCancel(content),
|
||||
}
|
||||
.into(),
|
||||
CancelContent::ToDevice(c) => self
|
||||
.content_to_request(AnyToDeviceEventContent::KeyVerificationCancel(c))
|
||||
.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn cancel_if_timed_out(&self) -> Option<ToDeviceRequest> {
|
||||
pub(crate) fn cancel_if_timed_out(&self) -> Option<OutgoingVerificationRequest> {
|
||||
if self.is_canceled() || self.is_done() {
|
||||
None
|
||||
} else if self.timed_out() {
|
||||
|
@ -553,12 +574,16 @@ impl Sas {
|
|||
let sas: InnerSas = (*guard).clone();
|
||||
let (sas, content) = sas.cancel(CancelCode::Timeout);
|
||||
*guard = sas;
|
||||
content.map(|c| {
|
||||
if let OutgoingContent::ToDevice(c) = c {
|
||||
self.content_to_request(c)
|
||||
} else {
|
||||
todo!()
|
||||
content.map(|c| match c {
|
||||
CancelContent::Room(room_id, content) => RoomMessageRequest {
|
||||
room_id,
|
||||
txn_id: Uuid::new_v4(),
|
||||
content: AnyMessageEventContent::KeyVerificationCancel(content),
|
||||
}
|
||||
.into(),
|
||||
CancelContent::ToDevice(c) => self
|
||||
.content_to_request(AnyToDeviceEventContent::KeyVerificationCancel(c))
|
||||
.into(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
@ -602,6 +627,15 @@ impl Sas {
|
|||
self.inner.lock().unwrap().decimals()
|
||||
}
|
||||
|
||||
pub(crate) fn receive_room_event(&self, event: &AnyMessageEvent) -> Option<OutgoingContent> {
|
||||
let mut guard = self.inner.lock().unwrap();
|
||||
let sas: InnerSas = (*guard).clone();
|
||||
let (sas, content) = sas.receive_room_event(event);
|
||||
*guard = sas;
|
||||
|
||||
content
|
||||
}
|
||||
|
||||
pub(crate) fn receive_event(&self, event: &AnyToDeviceEvent) -> Option<OutgoingContent> {
|
||||
let mut guard = self.inner.lock().unwrap();
|
||||
let sas: InnerSas = (*guard).clone();
|
||||
|
|
|
@ -28,8 +28,8 @@ use matrix_sdk_common::{
|
|||
AcceptEventContent, AcceptMethod, AcceptToDeviceEventContent,
|
||||
MSasV1Content as AcceptV1Content, MSasV1ContentInit as AcceptV1ContentInit,
|
||||
},
|
||||
cancel::{CancelCode, CancelToDeviceEventContent},
|
||||
key::KeyToDeviceEventContent,
|
||||
cancel::{CancelCode, CancelEventContent, CancelToDeviceEventContent},
|
||||
key::{KeyEventContent, KeyToDeviceEventContent},
|
||||
mac::MacToDeviceEventContent,
|
||||
start::{
|
||||
MSasV1Content, MSasV1ContentInit, StartEventContent, StartMethod,
|
||||
|
@ -46,7 +46,9 @@ use matrix_sdk_common::{
|
|||
use tracing::error;
|
||||
|
||||
use super::{
|
||||
event_enums::{AcceptContent, OutgoingContent, StartContent},
|
||||
event_enums::{
|
||||
AcceptContent, CancelContent, KeyContent, MacContent, OutgoingContent, StartContent,
|
||||
},
|
||||
helpers::{
|
||||
calculate_commitment, get_decimal, get_emoji, get_mac_content, receive_mac_event, SasIds,
|
||||
},
|
||||
|
@ -618,14 +620,17 @@ impl SasState<Started> {
|
|||
/// anymore.
|
||||
pub fn into_key_received(
|
||||
self,
|
||||
event: &ToDeviceEvent<KeyToDeviceEventContent>,
|
||||
sender: &UserId,
|
||||
content: impl Into<KeyContent>,
|
||||
) -> Result<SasState<KeyReceived>, SasState<Canceled>> {
|
||||
self.check_event(&event.sender, &event.content.transaction_id)
|
||||
let content = content.into();
|
||||
|
||||
self.check_event(&sender, &content.flow_id().as_str())
|
||||
.map_err(|c| self.clone().cancel(c))?;
|
||||
|
||||
let accepted_protocols = AcceptedProtocols::default();
|
||||
|
||||
let their_pubkey = event.content.key.clone();
|
||||
let their_pubkey = content.public_key().to_owned();
|
||||
|
||||
self.inner
|
||||
.lock()
|
||||
|
@ -659,20 +664,23 @@ impl SasState<Accepted> {
|
|||
/// anymore.
|
||||
pub fn into_key_received(
|
||||
self,
|
||||
event: &ToDeviceEvent<KeyToDeviceEventContent>,
|
||||
sender: &UserId,
|
||||
content: impl Into<KeyContent>,
|
||||
) -> Result<SasState<KeyReceived>, SasState<Canceled>> {
|
||||
self.check_event(&event.sender, &event.content.transaction_id)
|
||||
let content = content.into();
|
||||
|
||||
self.check_event(&sender, content.flow_id().as_str())
|
||||
.map_err(|c| self.clone().cancel(c))?;
|
||||
|
||||
let commitment = calculate_commitment(
|
||||
&event.content.key,
|
||||
content.public_key(),
|
||||
self.state.start_content.as_ref().clone(),
|
||||
);
|
||||
|
||||
if self.state.commitment != commitment {
|
||||
Err(self.cancel(CancelCode::InvalidMessage))
|
||||
} else {
|
||||
let their_pubkey = event.content.key.clone();
|
||||
let their_pubkey = content.public_key().to_owned();
|
||||
|
||||
self.inner
|
||||
.lock()
|
||||
|
@ -698,15 +706,23 @@ impl SasState<Accepted> {
|
|||
/// Get the content for the key event.
|
||||
///
|
||||
/// The content needs to be automatically sent to the other side.
|
||||
pub fn as_content(&self) -> KeyToDeviceEventContent {
|
||||
pub fn as_content(&self) -> OutgoingContent {
|
||||
match &*self.verification_flow_id {
|
||||
FlowId::ToDevice(s) => KeyToDeviceEventContent {
|
||||
FlowId::ToDevice(s) => KeyContent::ToDevice(KeyToDeviceEventContent {
|
||||
transaction_id: s.to_string(),
|
||||
key: self.inner.lock().unwrap().public_key(),
|
||||
},
|
||||
FlowId::InRoom(_, r) => {
|
||||
todo!("In-room verifications aren't implemented")
|
||||
}
|
||||
})
|
||||
.into(),
|
||||
FlowId::InRoom(r, e) => KeyContent::Room(
|
||||
r.clone(),
|
||||
KeyEventContent {
|
||||
key: self.inner.lock().unwrap().public_key(),
|
||||
relation: Relation {
|
||||
event_id: e.clone(),
|
||||
},
|
||||
},
|
||||
)
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -716,13 +732,23 @@ impl SasState<KeyReceived> {
|
|||
///
|
||||
/// The content needs to be automatically sent to the other side if and only
|
||||
/// if we_started is false.
|
||||
pub fn as_content(&self) -> KeyToDeviceEventContent {
|
||||
match self.verification_flow_id.as_ref() {
|
||||
FlowId::ToDevice(s) => KeyToDeviceEventContent {
|
||||
pub fn as_content(&self) -> KeyContent {
|
||||
match &*self.verification_flow_id {
|
||||
FlowId::ToDevice(s) => KeyContent::ToDevice(KeyToDeviceEventContent {
|
||||
transaction_id: s.to_string(),
|
||||
key: self.inner.lock().unwrap().public_key(),
|
||||
},
|
||||
_ => todo!(),
|
||||
})
|
||||
.into(),
|
||||
FlowId::InRoom(r, e) => KeyContent::Room(
|
||||
r.clone(),
|
||||
KeyEventContent {
|
||||
key: self.inner.lock().unwrap().public_key(),
|
||||
relation: Relation {
|
||||
event_id: e.clone(),
|
||||
},
|
||||
},
|
||||
)
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -763,16 +789,20 @@ impl SasState<KeyReceived> {
|
|||
/// the other side.
|
||||
pub fn into_mac_received(
|
||||
self,
|
||||
event: &ToDeviceEvent<MacToDeviceEventContent>,
|
||||
sender: &UserId,
|
||||
content: impl Into<MacContent>,
|
||||
) -> Result<SasState<MacReceived>, SasState<Canceled>> {
|
||||
self.check_event(&event.sender, &event.content.transaction_id)
|
||||
let content = content.into();
|
||||
|
||||
self.check_event(&sender, content.flow_id().as_str())
|
||||
.map_err(|c| self.clone().cancel(c))?;
|
||||
|
||||
let (devices, master_keys) = receive_mac_event(
|
||||
&self.inner.lock().unwrap(),
|
||||
&self.ids,
|
||||
self.verification_flow_id.as_str(),
|
||||
event,
|
||||
sender,
|
||||
&content,
|
||||
)
|
||||
.map_err(|c| self.clone().cancel(c))?;
|
||||
|
||||
|
@ -819,16 +849,20 @@ impl SasState<Confirmed> {
|
|||
/// the other side.
|
||||
pub fn into_done(
|
||||
self,
|
||||
event: &ToDeviceEvent<MacToDeviceEventContent>,
|
||||
sender: &UserId,
|
||||
content: impl Into<MacContent>,
|
||||
) -> Result<SasState<Done>, SasState<Canceled>> {
|
||||
self.check_event(&event.sender, &event.content.transaction_id)
|
||||
let content = content.into();
|
||||
|
||||
self.check_event(&sender, &content.flow_id().as_str())
|
||||
.map_err(|c| self.clone().cancel(c))?;
|
||||
|
||||
let (devices, master_keys) = receive_mac_event(
|
||||
&self.inner.lock().unwrap(),
|
||||
&self.ids,
|
||||
&self.verification_flow_id.as_str(),
|
||||
event,
|
||||
sender,
|
||||
&content,
|
||||
)
|
||||
.map_err(|c| self.clone().cancel(c))?;
|
||||
|
||||
|
@ -849,7 +883,7 @@ impl SasState<Confirmed> {
|
|||
/// Get the content for the mac event.
|
||||
///
|
||||
/// The content needs to be automatically sent to the other side.
|
||||
pub fn as_content(&self) -> MacToDeviceEventContent {
|
||||
pub fn as_content(&self) -> MacContent {
|
||||
get_mac_content(
|
||||
&self.inner.lock().unwrap(),
|
||||
&self.ids,
|
||||
|
@ -911,7 +945,7 @@ impl SasState<Done> {
|
|||
///
|
||||
/// The content needs to be automatically sent to the other side if it
|
||||
/// wasn't already sent.
|
||||
pub fn as_content(&self) -> MacToDeviceEventContent {
|
||||
pub fn as_content(&self) -> MacContent {
|
||||
get_mac_content(
|
||||
&self.inner.lock().unwrap(),
|
||||
&self.ids,
|
||||
|
@ -959,17 +993,26 @@ impl Canceled {
|
|||
}
|
||||
|
||||
impl SasState<Canceled> {
|
||||
pub fn as_content(&self) -> OutgoingContent {
|
||||
pub fn as_content(&self) -> CancelContent {
|
||||
match self.verification_flow_id.as_ref() {
|
||||
FlowId::ToDevice(s) => {
|
||||
AnyToDeviceEventContent::KeyVerificationCancel(CancelToDeviceEventContent {
|
||||
transaction_id: self.verification_flow_id.to_string(),
|
||||
FlowId::ToDevice(s) => CancelToDeviceEventContent {
|
||||
transaction_id: s.clone(),
|
||||
reason: self.state.reason.to_string(),
|
||||
code: self.state.cancel_code.clone(),
|
||||
}
|
||||
.into(),
|
||||
|
||||
FlowId::InRoom(r, e) => (
|
||||
r.clone(),
|
||||
CancelEventContent {
|
||||
reason: self.state.reason.to_string(),
|
||||
code: self.state.cancel_code.clone(),
|
||||
})
|
||||
.into()
|
||||
}
|
||||
_ => todo!(),
|
||||
relation: Relation {
|
||||
event_id: e.clone(),
|
||||
},
|
||||
},
|
||||
)
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue