crypto: WIP key verification request handling.
This commit is contained in:
parent
5babd71341
commit
7198b0daba
12 changed files with 439 additions and 25 deletions
|
@ -1,9 +1,20 @@
|
||||||
use std::{env, io, process::exit};
|
use std::{
|
||||||
|
env, io,
|
||||||
|
process::exit,
|
||||||
|
sync::{
|
||||||
|
atomic::{AtomicBool, Ordering},
|
||||||
|
Arc,
|
||||||
|
},
|
||||||
|
};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use matrix_sdk::{
|
use matrix_sdk::{
|
||||||
self, events::AnyToDeviceEvent, identifiers::UserId, Client, ClientConfig, LoopCtrl, Sas,
|
self,
|
||||||
SyncSettings,
|
events::{
|
||||||
|
room::message::MessageEventContent, AnySyncMessageEvent, AnySyncRoomEvent, AnyToDeviceEvent,
|
||||||
|
},
|
||||||
|
identifiers::UserId,
|
||||||
|
Client, ClientConfig, LoopCtrl, Sas, SyncSettings,
|
||||||
};
|
};
|
||||||
|
|
||||||
async fn wait_for_confirmation(client: Client, sas: Sas) {
|
async fn wait_for_confirmation(client: Client, sas: Sas) {
|
||||||
|
@ -68,10 +79,13 @@ async fn login(
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let client_ref = &client;
|
let client_ref = &client;
|
||||||
|
let initial_sync = Arc::new(AtomicBool::from(true));
|
||||||
|
let initial_ref = &initial_sync;
|
||||||
|
|
||||||
client
|
client
|
||||||
.sync_with_callback(SyncSettings::new(), |response| async move {
|
.sync_with_callback(SyncSettings::new(), |response| async move {
|
||||||
let client = &client_ref;
|
let client = &client_ref;
|
||||||
|
let initial = &initial_ref;
|
||||||
|
|
||||||
for event in &response.to_device.events {
|
for event in &response.to_device.events {
|
||||||
let e = event
|
let e = event
|
||||||
|
@ -118,6 +132,30 @@ 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");
|
||||||
|
|
||||||
|
request
|
||||||
|
.accept()
|
||||||
|
.await
|
||||||
|
.expect("Can't accept verification request");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initial.store(false, Ordering::SeqCst);
|
||||||
|
|
||||||
LoopCtrl::Continue
|
LoopCtrl::Continue
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
|
@ -118,6 +118,7 @@ use matrix_sdk_common::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
http_client::{client_with_config, HttpClient, HttpSend},
|
http_client::{client_with_config, HttpClient, HttpSend},
|
||||||
|
verification_request::VerificationRequest,
|
||||||
Error, EventEmitter, OutgoingRequest, Result,
|
Error, EventEmitter, OutgoingRequest, Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1894,6 +1895,19 @@ impl Client {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a `VerificationRequest` object with the given flow id.
|
||||||
|
#[cfg(feature = "encryption")]
|
||||||
|
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
||||||
|
pub async fn get_verification_request(&self, flow_id: &EventId) -> Option<VerificationRequest> {
|
||||||
|
let olm = self.base_client.olm_machine().await?;
|
||||||
|
|
||||||
|
olm.get_verification_request(flow_id)
|
||||||
|
.map(|r| VerificationRequest {
|
||||||
|
inner: r,
|
||||||
|
client: self.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a specific device of a user.
|
/// Get a specific device of a user.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
|
|
@ -88,6 +88,8 @@ mod http_client;
|
||||||
mod device;
|
mod device;
|
||||||
#[cfg(feature = "encryption")]
|
#[cfg(feature = "encryption")]
|
||||||
mod sas;
|
mod sas;
|
||||||
|
#[cfg(feature = "encryption")]
|
||||||
|
mod verification_request;
|
||||||
|
|
||||||
pub use client::{Client, ClientConfig, LoopCtrl, SyncSettings};
|
pub use client::{Client, ClientConfig, LoopCtrl, SyncSettings};
|
||||||
#[cfg(feature = "encryption")]
|
#[cfg(feature = "encryption")]
|
||||||
|
|
41
matrix_sdk/src/verification_request.rs
Normal file
41
matrix_sdk/src/verification_request.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
use matrix_sdk_base::{
|
||||||
|
crypto::VerificationRequest as BaseVerificationRequest, events::AnyMessageEventContent,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{Client, Result};
|
||||||
|
|
||||||
|
/// An object controling the interactive verification flow.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct VerificationRequest {
|
||||||
|
pub(crate) inner: BaseVerificationRequest,
|
||||||
|
pub(crate) client: Client,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VerificationRequest {
|
||||||
|
/// Accept the interactive verification flow.
|
||||||
|
pub async fn accept(&self) -> Result<()> {
|
||||||
|
if let Some(content) = self.inner.accept() {
|
||||||
|
let content = AnyMessageEventContent::KeyVerificationReady(content);
|
||||||
|
|
||||||
|
self.client
|
||||||
|
.room_send(self.inner.room_id(), content, None)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,7 +21,7 @@ js_int = "0.1.9"
|
||||||
[dependencies.ruma]
|
[dependencies.ruma]
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
git = "https://github.com/ruma/ruma"
|
git = "https://github.com/ruma/ruma"
|
||||||
rev = "e8882fe8142d7b55ed4c8ccc6150946945f9e237"
|
rev = "1a4e9aa20abff4786dbb91a19fb72c1dfa4410a7"
|
||||||
features = ["client-api", "unstable-pre-spec"]
|
features = ["client-api", "unstable-pre-spec"]
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
|
|
|
@ -53,4 +53,4 @@ pub(crate) use olm::ReadOnlyAccount;
|
||||||
pub use requests::{
|
pub use requests::{
|
||||||
IncomingResponse, KeysQueryRequest, OutgoingRequest, OutgoingRequests, ToDeviceRequest,
|
IncomingResponse, KeysQueryRequest, OutgoingRequest, OutgoingRequests, ToDeviceRequest,
|
||||||
};
|
};
|
||||||
pub use verification::Sas;
|
pub use verification::{Sas, VerificationRequest};
|
||||||
|
|
|
@ -36,7 +36,8 @@ use matrix_sdk_common::{
|
||||||
ToDeviceEvent,
|
ToDeviceEvent,
|
||||||
},
|
},
|
||||||
identifiers::{
|
identifiers::{
|
||||||
DeviceId, DeviceIdBox, DeviceKeyAlgorithm, EventEncryptionAlgorithm, RoomId, UserId,
|
DeviceId, DeviceIdBox, DeviceKeyAlgorithm, EventEncryptionAlgorithm, EventId, RoomId,
|
||||||
|
UserId,
|
||||||
},
|
},
|
||||||
js_int::UInt,
|
js_int::UInt,
|
||||||
locks::Mutex,
|
locks::Mutex,
|
||||||
|
@ -44,8 +45,6 @@ use matrix_sdk_common::{
|
||||||
Raw,
|
Raw,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "sqlite_cryptostore")]
|
|
||||||
use crate::store::sqlite::SqliteStore;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{EventError, MegolmError, MegolmResult, OlmError, OlmResult},
|
error::{EventError, MegolmError, MegolmResult, OlmError, OlmResult},
|
||||||
identities::{Device, IdentityManager, UserDevices},
|
identities::{Device, IdentityManager, UserDevices},
|
||||||
|
@ -64,6 +63,8 @@ use crate::{
|
||||||
verification::{Sas, VerificationMachine},
|
verification::{Sas, VerificationMachine},
|
||||||
ToDeviceRequest,
|
ToDeviceRequest,
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "sqlite_cryptostore")]
|
||||||
|
use crate::{store::sqlite::SqliteStore, verification::VerificationRequest};
|
||||||
|
|
||||||
/// State machine implementation of the Olm/Megolm encryption protocol used for
|
/// State machine implementation of the Olm/Megolm encryption protocol used for
|
||||||
/// Matrix end to end encryption.
|
/// Matrix end to end encryption.
|
||||||
|
@ -767,6 +768,11 @@ impl OlmMachine {
|
||||||
self.verification_machine.get_sas(flow_id)
|
self.verification_machine.get_sas(flow_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a verification request object with the given flow id.
|
||||||
|
pub fn get_verification_request(&self, flow_id: &EventId) -> Option<VerificationRequest> {
|
||||||
|
self.verification_machine.get_request(flow_id)
|
||||||
|
}
|
||||||
|
|
||||||
async fn update_one_time_key_count(&self, key_count: &BTreeMap<DeviceKeyAlgorithm, UInt>) {
|
async fn update_one_time_key_count(&self, key_count: &BTreeMap<DeviceKeyAlgorithm, UInt>) {
|
||||||
self.account.update_uploaded_key_count(key_count).await;
|
self.account.update_uploaded_key_count(key_count).await;
|
||||||
}
|
}
|
||||||
|
@ -924,6 +930,12 @@ impl OlmMachine {
|
||||||
// TODO set the encryption info on the event (is it verified, was it
|
// TODO set the encryption info on the event (is it verified, was it
|
||||||
// decrypted, sender key...)
|
// decrypted, sender key...)
|
||||||
|
|
||||||
|
if let Ok(e) = decrypted_event.deserialize() {
|
||||||
|
self.verification_machine
|
||||||
|
.receive_room_event(room_id, &e)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(decrypted_event)
|
Ok(decrypted_event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,16 +16,23 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
|
|
||||||
use matrix_sdk_common::locks::Mutex;
|
use tracing::{info, trace, warn};
|
||||||
use tracing::{trace, warn};
|
|
||||||
|
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
events::{AnyToDeviceEvent, AnyToDeviceEventContent},
|
events::{
|
||||||
identifiers::{DeviceId, UserId},
|
room::message::MessageEventContent, AnySyncMessageEvent, AnySyncRoomEvent,
|
||||||
|
AnyToDeviceEvent, AnyToDeviceEventContent,
|
||||||
|
},
|
||||||
|
identifiers::{DeviceId, EventId, RoomId, UserId},
|
||||||
|
locks::Mutex,
|
||||||
uuid::Uuid,
|
uuid::Uuid,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::sas::{content_to_request, Sas, VerificationResult};
|
use super::{
|
||||||
|
requests::VerificationRequest,
|
||||||
|
sas::{content_to_request, Sas, VerificationResult},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
olm::PrivateCrossSigningIdentity,
|
olm::PrivateCrossSigningIdentity,
|
||||||
requests::{OutgoingRequest, ToDeviceRequest},
|
requests::{OutgoingRequest, ToDeviceRequest},
|
||||||
|
@ -39,6 +46,7 @@ pub struct VerificationMachine {
|
||||||
private_identity: Arc<Mutex<PrivateCrossSigningIdentity>>,
|
private_identity: Arc<Mutex<PrivateCrossSigningIdentity>>,
|
||||||
pub(crate) store: Arc<Box<dyn CryptoStore>>,
|
pub(crate) store: Arc<Box<dyn CryptoStore>>,
|
||||||
verifications: Arc<DashMap<String, Sas>>,
|
verifications: Arc<DashMap<String, Sas>>,
|
||||||
|
requests: Arc<DashMap<EventId, VerificationRequest>>,
|
||||||
outgoing_to_device_messages: Arc<DashMap<Uuid, OutgoingRequest>>,
|
outgoing_to_device_messages: Arc<DashMap<Uuid, OutgoingRequest>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,8 +60,9 @@ impl VerificationMachine {
|
||||||
account,
|
account,
|
||||||
private_identity: identity,
|
private_identity: identity,
|
||||||
store,
|
store,
|
||||||
verifications: Arc::new(DashMap::new()),
|
verifications: DashMap::new().into(),
|
||||||
outgoing_to_device_messages: Arc::new(DashMap::new()),
|
requests: DashMap::new().into(),
|
||||||
|
outgoing_to_device_messages: DashMap::new().into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,6 +93,11 @@ impl VerificationMachine {
|
||||||
Ok((sas, request))
|
Ok((sas, request))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_request(&self, flow_id: &EventId) -> Option<VerificationRequest> {
|
||||||
|
#[allow(clippy::map_clone)]
|
||||||
|
self.requests.get(flow_id).map(|s| s.clone())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_sas(&self, transaction_id: &str) -> Option<Sas> {
|
pub fn get_sas(&self, transaction_id: &str) -> Option<Sas> {
|
||||||
#[allow(clippy::map_clone)]
|
#[allow(clippy::map_clone)]
|
||||||
self.verifications.get(transaction_id).map(|s| s.clone())
|
self.verifications.get(transaction_id).map(|s| s.clone())
|
||||||
|
@ -106,7 +120,7 @@ impl VerificationMachine {
|
||||||
self.outgoing_to_device_messages.insert(request_id, request);
|
self.outgoing_to_device_messages.insert(request_id, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_event_helper(&self, sas: &Sas, event: &mut AnyToDeviceEvent) {
|
fn receive_event_helper(&self, sas: &Sas, event: &AnyToDeviceEvent) {
|
||||||
if let Some(c) = sas.receive_event(event) {
|
if let Some(c) = sas.receive_event(event) {
|
||||||
self.queue_up_content(sas.other_user_id(), sas.other_device_id(), c);
|
self.queue_up_content(sas.other_user_id(), sas.other_device_id(), c);
|
||||||
}
|
}
|
||||||
|
@ -141,10 +155,40 @@ impl VerificationMachine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn receive_event(
|
pub async fn receive_room_event(
|
||||||
&self,
|
&self,
|
||||||
event: &mut AnyToDeviceEvent,
|
room_id: &RoomId,
|
||||||
|
event: &AnySyncRoomEvent,
|
||||||
) -> Result<(), CryptoStoreError> {
|
) -> Result<(), CryptoStoreError> {
|
||||||
|
match event {
|
||||||
|
AnySyncRoomEvent::Message(AnySyncMessageEvent::RoomMessage(m)) => {
|
||||||
|
if let MessageEventContent::VerificationRequest(r) = &m.content {
|
||||||
|
if self.account.user_id() == &r.to {
|
||||||
|
info!(
|
||||||
|
"Received a new verification request from {} {}",
|
||||||
|
m.sender, r.from_device
|
||||||
|
);
|
||||||
|
|
||||||
|
let request = VerificationRequest::from_request_event(
|
||||||
|
room_id,
|
||||||
|
self.account.user_id(),
|
||||||
|
self.account.device_id(),
|
||||||
|
&m.sender,
|
||||||
|
&m.event_id,
|
||||||
|
r,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.requests.insert(m.event_id.clone(), request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn receive_event(&self, event: &AnyToDeviceEvent) -> Result<(), CryptoStoreError> {
|
||||||
trace!("Received a key verification event {:?}", event);
|
trace!("Received a key verification event {:?}", event);
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
|
|
|
@ -13,9 +13,11 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
mod machine;
|
mod machine;
|
||||||
|
mod requests;
|
||||||
mod sas;
|
mod sas;
|
||||||
|
|
||||||
pub use machine::VerificationMachine;
|
pub use machine::VerificationMachine;
|
||||||
|
pub use requests::VerificationRequest;
|
||||||
pub use sas::{Sas, VerificationResult};
|
pub use sas::{Sas, VerificationResult};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
262
matrix_sdk_crypto/src/verification/requests.rs
Normal file
262
matrix_sdk_crypto/src/verification/requests.rs
Normal file
|
@ -0,0 +1,262 @@
|
||||||
|
// 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::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use matrix_sdk_common::{
|
||||||
|
api::r0::message::send_message_event::Response as RoomMessageResponse,
|
||||||
|
events::{
|
||||||
|
key::verification::{ready::ReadyEventContent, Relation, VerificationMethod},
|
||||||
|
room::message::KeyVerificationRequestEventContent,
|
||||||
|
},
|
||||||
|
identifiers::{DeviceId, DeviceIdBox, EventId, RoomId, UserId},
|
||||||
|
};
|
||||||
|
|
||||||
|
const SUPPORTED_METHODS: &[VerificationMethod] = &[VerificationMethod::MSasV1];
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
/// TODO
|
||||||
|
pub struct VerificationRequest {
|
||||||
|
inner: Arc<Mutex<InnerRequest>>,
|
||||||
|
room_id: Arc<RoomId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VerificationRequest {
|
||||||
|
pub(crate) fn from_request_event(
|
||||||
|
room_id: &RoomId,
|
||||||
|
own_user_id: &UserId,
|
||||||
|
own_device_id: &DeviceId,
|
||||||
|
sender: &UserId,
|
||||||
|
event_id: &EventId,
|
||||||
|
content: &KeyVerificationRequestEventContent,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: Arc::new(Mutex::new(InnerRequest::Requested(
|
||||||
|
RequestState::from_request_event(
|
||||||
|
own_user_id,
|
||||||
|
own_device_id,
|
||||||
|
sender,
|
||||||
|
event_id,
|
||||||
|
content,
|
||||||
|
),
|
||||||
|
))),
|
||||||
|
room_id: room_id.clone().into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The room id where the verification is happening.
|
||||||
|
pub fn room_id(&self) -> &RoomId {
|
||||||
|
&self.room_id
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Accept the verification request.
|
||||||
|
pub fn accept(&self) -> Option<ReadyEventContent> {
|
||||||
|
self.inner.lock().unwrap().accept()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum InnerRequest {
|
||||||
|
Created(RequestState<Created>),
|
||||||
|
Sent(RequestState<Sent>),
|
||||||
|
Requested(RequestState<Requested>),
|
||||||
|
Ready(RequestState<Ready>),
|
||||||
|
Accepted(RequestState<Accepted>),
|
||||||
|
Passive(RequestState<Passive>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InnerRequest {
|
||||||
|
fn accept(&mut self) -> Option<ReadyEventContent> {
|
||||||
|
if let InnerRequest::Requested(s) = self {
|
||||||
|
let (state, content) = s.clone().accept();
|
||||||
|
*self = InnerRequest::Accepted(state);
|
||||||
|
|
||||||
|
Some(content)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct RequestState<S: Clone> {
|
||||||
|
/// Our own user id.
|
||||||
|
pub own_user_id: UserId,
|
||||||
|
|
||||||
|
/// Our own device id.
|
||||||
|
pub own_device_id: DeviceIdBox,
|
||||||
|
|
||||||
|
/// The id of the user which is participating in this verification request.
|
||||||
|
pub other_user_id: UserId,
|
||||||
|
|
||||||
|
/// The verification request state we are in.
|
||||||
|
state: S,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct Created {}
|
||||||
|
|
||||||
|
impl RequestState<Created> {
|
||||||
|
fn as_content(&self) -> KeyVerificationRequestEventContent {
|
||||||
|
KeyVerificationRequestEventContent {
|
||||||
|
body: format!(
|
||||||
|
"{} is requesting to verify your key, but your client does not \
|
||||||
|
support in-chat key verification. You will need to use legacy \
|
||||||
|
key verification to verify keys.",
|
||||||
|
self.own_user_id
|
||||||
|
),
|
||||||
|
methods: SUPPORTED_METHODS.to_vec(),
|
||||||
|
from_device: self.own_device_id.clone(),
|
||||||
|
to: self.other_user_id.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_sent(self, response: &RoomMessageResponse) -> RequestState<Sent> {
|
||||||
|
RequestState {
|
||||||
|
own_user_id: self.own_user_id,
|
||||||
|
own_device_id: self.own_device_id,
|
||||||
|
other_user_id: self.other_user_id,
|
||||||
|
state: Sent {
|
||||||
|
methods: SUPPORTED_METHODS.to_vec(),
|
||||||
|
flow_id: response.event_id.clone(),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct Sent {
|
||||||
|
/// The verification methods supported by the sender.
|
||||||
|
pub methods: Vec<VerificationMethod>,
|
||||||
|
|
||||||
|
/// The event id of our `m.key.verification.request` event which acts as an
|
||||||
|
/// unique id identifying this verification flow.
|
||||||
|
pub flow_id: EventId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RequestState<Sent> {
|
||||||
|
fn into_ready(self, _sender: &UserId, content: &ReadyEventContent) -> RequestState<Ready> {
|
||||||
|
// TODO check the flow id, and that the methods match what we suggested.
|
||||||
|
RequestState {
|
||||||
|
own_user_id: self.own_user_id,
|
||||||
|
own_device_id: self.own_device_id,
|
||||||
|
other_user_id: self.other_user_id,
|
||||||
|
state: Ready {
|
||||||
|
methods: content.methods.to_owned(),
|
||||||
|
other_device_id: content.from_device.clone(),
|
||||||
|
flow_id: self.state.flow_id.clone(),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct Requested {
|
||||||
|
/// The verification methods supported by the sender.
|
||||||
|
pub methods: Vec<VerificationMethod>,
|
||||||
|
|
||||||
|
/// The event id of the `m.key.verification.request` event which acts as an
|
||||||
|
/// unique id identifying this verification flow.
|
||||||
|
pub flow_id: EventId,
|
||||||
|
|
||||||
|
/// The device id of the device that responded to the verification request.
|
||||||
|
pub other_device_id: DeviceIdBox,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RequestState<Requested> {
|
||||||
|
fn from_request_event(
|
||||||
|
own_user_id: &UserId,
|
||||||
|
own_device_id: &DeviceId,
|
||||||
|
sender: &UserId,
|
||||||
|
event_id: &EventId,
|
||||||
|
content: &KeyVerificationRequestEventContent,
|
||||||
|
) -> RequestState<Requested> {
|
||||||
|
// TODO only create this if we suport the methods
|
||||||
|
RequestState {
|
||||||
|
own_user_id: own_user_id.clone(),
|
||||||
|
own_device_id: own_device_id.into(),
|
||||||
|
other_user_id: sender.clone(),
|
||||||
|
state: Requested {
|
||||||
|
methods: content.methods.clone(),
|
||||||
|
flow_id: event_id.clone(),
|
||||||
|
other_device_id: content.from_device.clone(),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accept(self) -> (RequestState<Accepted>, ReadyEventContent) {
|
||||||
|
// TODO let the user pick a method here.
|
||||||
|
let state = RequestState {
|
||||||
|
own_user_id: self.own_user_id,
|
||||||
|
own_device_id: self.own_device_id.clone(),
|
||||||
|
other_user_id: self.other_user_id,
|
||||||
|
state: Accepted {
|
||||||
|
methods: self.state.methods.clone(),
|
||||||
|
other_device_id: self.state.other_device_id.clone(),
|
||||||
|
flow_id: self.state.flow_id.clone(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let content = ReadyEventContent {
|
||||||
|
from_device: self.own_device_id,
|
||||||
|
methods: self.state.methods,
|
||||||
|
relation: Relation {
|
||||||
|
event_id: self.state.flow_id,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
(state, content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct Ready {
|
||||||
|
/// The verification methods supported by the sender.
|
||||||
|
pub methods: Vec<VerificationMethod>,
|
||||||
|
|
||||||
|
/// The device id of the device that responded to the verification request.
|
||||||
|
pub other_device_id: DeviceIdBox,
|
||||||
|
|
||||||
|
/// The event id of the `m.key.verification.request` event which acts as an
|
||||||
|
/// unique id identifying this verification flow.
|
||||||
|
pub flow_id: EventId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct Accepted {
|
||||||
|
/// The verification methods that were accepted
|
||||||
|
pub methods: Vec<VerificationMethod>,
|
||||||
|
|
||||||
|
/// The device id of the device that responded to the verification request.
|
||||||
|
pub other_device_id: DeviceIdBox,
|
||||||
|
|
||||||
|
/// The event id of the `m.key.verification.request` event which acts as an
|
||||||
|
/// unique id identifying this verification flow.
|
||||||
|
pub flow_id: EventId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct Passive {
|
||||||
|
/// The device id of the device that responded to the verification request.
|
||||||
|
pub other_device_id: DeviceIdBox,
|
||||||
|
|
||||||
|
/// The event id of the `m.key.verification.request` event which acts as an
|
||||||
|
/// unique id identifying this verification flow.
|
||||||
|
pub flow_id: EventId,
|
||||||
|
}
|
|
@ -514,7 +514,7 @@ impl Sas {
|
||||||
|
|
||||||
pub(crate) fn receive_event(
|
pub(crate) fn receive_event(
|
||||||
&self,
|
&self,
|
||||||
event: &mut AnyToDeviceEvent,
|
event: &AnyToDeviceEvent,
|
||||||
) -> Option<AnyToDeviceEventContent> {
|
) -> Option<AnyToDeviceEventContent> {
|
||||||
let mut guard = self.inner.lock().unwrap();
|
let mut guard = self.inner.lock().unwrap();
|
||||||
let sas: InnerSas = (*guard).clone();
|
let sas: InnerSas = (*guard).clone();
|
||||||
|
@ -628,7 +628,7 @@ impl InnerSas {
|
||||||
|
|
||||||
fn receive_event(
|
fn receive_event(
|
||||||
self,
|
self,
|
||||||
event: &mut AnyToDeviceEvent,
|
event: &AnyToDeviceEvent,
|
||||||
) -> (InnerSas, Option<AnyToDeviceEventContent>) {
|
) -> (InnerSas, Option<AnyToDeviceEventContent>) {
|
||||||
match event {
|
match event {
|
||||||
AnyToDeviceEvent::KeyVerificationAccept(e) => {
|
AnyToDeviceEvent::KeyVerificationAccept(e) => {
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
mem,
|
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
@ -498,14 +497,14 @@ impl SasState<Started> {
|
||||||
/// anymore.
|
/// anymore.
|
||||||
pub fn into_key_received(
|
pub fn into_key_received(
|
||||||
self,
|
self,
|
||||||
event: &mut ToDeviceEvent<KeyToDeviceEventContent>,
|
event: &ToDeviceEvent<KeyToDeviceEventContent>,
|
||||||
) -> Result<SasState<KeyReceived>, SasState<Canceled>> {
|
) -> Result<SasState<KeyReceived>, SasState<Canceled>> {
|
||||||
self.check_event(&event.sender, &event.content.transaction_id)
|
self.check_event(&event.sender, &event.content.transaction_id)
|
||||||
.map_err(|c| self.clone().cancel(c))?;
|
.map_err(|c| self.clone().cancel(c))?;
|
||||||
|
|
||||||
let accepted_protocols = AcceptedProtocols::default();
|
let accepted_protocols = AcceptedProtocols::default();
|
||||||
|
|
||||||
let their_pubkey = mem::take(&mut event.content.key);
|
let their_pubkey = event.content.key.clone();
|
||||||
|
|
||||||
self.inner
|
self.inner
|
||||||
.lock()
|
.lock()
|
||||||
|
@ -539,7 +538,7 @@ impl SasState<Accepted> {
|
||||||
/// anymore.
|
/// anymore.
|
||||||
pub fn into_key_received(
|
pub fn into_key_received(
|
||||||
self,
|
self,
|
||||||
event: &mut ToDeviceEvent<KeyToDeviceEventContent>,
|
event: &ToDeviceEvent<KeyToDeviceEventContent>,
|
||||||
) -> Result<SasState<KeyReceived>, SasState<Canceled>> {
|
) -> Result<SasState<KeyReceived>, SasState<Canceled>> {
|
||||||
self.check_event(&event.sender, &event.content.transaction_id)
|
self.check_event(&event.sender, &event.content.transaction_id)
|
||||||
.map_err(|c| self.clone().cancel(c))?;
|
.map_err(|c| self.clone().cancel(c))?;
|
||||||
|
@ -549,7 +548,7 @@ impl SasState<Accepted> {
|
||||||
if self.state.commitment != commitment {
|
if self.state.commitment != commitment {
|
||||||
Err(self.cancel(CancelCode::InvalidMessage))
|
Err(self.cancel(CancelCode::InvalidMessage))
|
||||||
} else {
|
} else {
|
||||||
let their_pubkey = mem::take(&mut event.content.key);
|
let their_pubkey = event.content.key.clone();
|
||||||
|
|
||||||
self.inner
|
self.inner
|
||||||
.lock()
|
.lock()
|
||||||
|
|
Loading…
Reference in a new issue