diff --git a/matrix_sdk/src/client.rs b/matrix_sdk/src/client.rs index a0c3e9d2..1b63d4ac 100644 --- a/matrix_sdk/src/client.rs +++ b/matrix_sdk/src/client.rs @@ -2172,8 +2172,8 @@ impl Client { let encrypt = move || -> Result<()> { let export: String = encrypt_key_export(&keys, &passphrase, 500_000)?; - let mut file = std::fs::File::create(path).unwrap(); - file.write_all(&export.into_bytes()).unwrap(); + let mut file = std::fs::File::create(path)?; + file.write_all(&export.into_bytes())?; Ok(()) }; @@ -2237,6 +2237,7 @@ impl Client { }; let task = tokio::task::spawn_blocking(decrypt); + // TODO remove this unwrap. let import = task.await.expect("Task join error").unwrap(); Ok(olm.import_keys(import).await?) diff --git a/matrix_sdk_crypto/src/verification/machine.rs b/matrix_sdk_crypto/src/verification/machine.rs index b59fd64a..2b7e03cb 100644 --- a/matrix_sdk_crypto/src/verification/machine.rs +++ b/matrix_sdk_crypto/src/verification/machine.rs @@ -224,6 +224,10 @@ impl VerificationMachine { // 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. + } return Ok(()); } @@ -250,6 +254,14 @@ impl VerificationMachine { } } } + AnySyncMessageEvent::KeyVerificationReady(e) => { + if let Some(request) = self.requests.get(&e.content.relation.event_id) { + if &e.sender == request.other_user() { + // TODO remove this unwrap. + request.receive_ready(&e.sender, &e.content).unwrap(); + } + } + } AnySyncMessageEvent::KeyVerificationStart(e) => { info!( "Received a new verification start event from {} {}", diff --git a/matrix_sdk_crypto/src/verification/requests.rs b/matrix_sdk_crypto/src/verification/requests.rs index ae96cf90..e11e244c 100644 --- a/matrix_sdk_crypto/src/verification/requests.rs +++ b/matrix_sdk_crypto/src/verification/requests.rs @@ -43,12 +43,63 @@ const SUPPORTED_METHODS: &[VerificationMethod] = &[VerificationMethod::MSasV1]; pub struct VerificationRequest { inner: Arc>, account: ReadOnlyAccount, + other_user_id: Arc, private_cross_signing_identity: PrivateCrossSigningIdentity, store: Arc>, room_id: Arc, } impl VerificationRequest { + /// TODO + pub fn new( + account: ReadOnlyAccount, + private_cross_signing_identity: PrivateCrossSigningIdentity, + store: Arc>, + room_id: Arc, + other_user: &UserId, + ) -> Self { + let inner = Mutex::new(InnerRequest::Created(RequestState::new( + account.user_id(), + account.device_id(), + other_user, + ))) + .into(); + Self { + inner, + account, + private_cross_signing_identity, + store, + other_user_id: other_user.clone().into(), + room_id, + } + } + + /// TODO + pub fn request(&self) -> Option { + match &*self.inner.lock().unwrap() { + InnerRequest::Created(c) => Some(c.as_content()), + _ => None, + } + } + + /// The id of the other user that is participating in this verification + /// request. + pub fn other_user(&self) -> &UserId { + &self.other_user_id + } + + /// Mark the request as sent. + pub fn mark_as_sent(&self, response: &RoomMessageResponse) { + let mut inner = self.inner.lock().unwrap(); + + match &*inner { + InnerRequest::Created(c) => { + *inner = InnerRequest::Sent(c.clone().into_sent(response)); + } + _ => (), + } + } + pub(crate) fn from_request_event( account: ReadOnlyAccount, private_cross_signing_identity: PrivateCrossSigningIdentity, @@ -69,6 +120,7 @@ impl VerificationRequest { ), ))), account, + other_user_id: sender.clone().into(), private_cross_signing_identity, store, room_id: room_id.clone().into(), @@ -85,6 +137,28 @@ impl VerificationRequest { self.inner.lock().unwrap().accept() } + pub(crate) fn receive_ready( + &self, + sender: &UserId, + content: &ReadyEventContent, + ) -> Result<(), ()> { + let mut inner = self.inner.lock().unwrap(); + + match &*inner { + InnerRequest::Sent(s) => { + *inner = InnerRequest::Ready(s.clone().into_ready(sender, content)); + } + _ => (), + } + + Ok(()) + } + + /// Is the verification request ready to start a verification flow. + pub fn is_ready(&self) -> bool { + matches!(&*self.inner.lock().unwrap(), InnerRequest::Ready(_)) + } + pub(crate) fn into_started_sas( self, event: &SyncMessageEvent, @@ -171,6 +245,15 @@ struct RequestState { struct Created {} impl RequestState { + fn new(own_user_id: &UserId, own_device_id: &DeviceId, other_user: &UserId) -> Self { + Self { + own_user_id: own_user_id.clone(), + own_device_id: own_device_id.into(), + other_user_id: other_user.clone(), + state: Created {}, + } + } + fn as_content(&self) -> KeyVerificationRequestEventContent { KeyVerificationRequestEventContent { body: format!( @@ -343,3 +426,81 @@ struct Passive { /// unique id identifying this verification flow. pub flow_id: EventId, } + +#[cfg(test)] +mod test { + use std::convert::TryFrom; + + use matrix_sdk_common::{ + api::r0::message::send_message_event::Response as RoomMessageResponse, + identifiers::{event_id, room_id, DeviceIdBox, UserId}, + }; + use matrix_sdk_test::async_test; + + use crate::{ + olm::{PrivateCrossSigningIdentity, ReadOnlyAccount}, + store::{CryptoStore, MemoryStore}, + }; + + use super::VerificationRequest; + + fn alice_id() -> UserId { + UserId::try_from("@alice:example.org").unwrap() + } + + fn alice_device_id() -> DeviceIdBox { + "JLAFKJWSCS".into() + } + + fn bob_id() -> UserId { + UserId::try_from("@bob:example.org").unwrap() + } + + fn bob_device_id() -> DeviceIdBox { + "BOBDEVCIE".into() + } + + #[async_test] + async fn test_request_accepting() { + let event_id = event_id!("$1234localhost"); + let room_id = room_id!("!test:localhost"); + + let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id()); + let alice_store: Box = Box::new(MemoryStore::new()); + let alice_identity = PrivateCrossSigningIdentity::empty(alice_id()); + + let bob = ReadOnlyAccount::new(&bob_id(), &bob_device_id()); + let bob_store: Box = Box::new(MemoryStore::new()); + let bob_identity = PrivateCrossSigningIdentity::empty(alice_id()); + + let bob_request = VerificationRequest::new( + bob, + bob_identity, + bob_store.into(), + room_id.clone().into(), + &alice_id(), + ); + + let content = bob_request.request().unwrap(); + + let alice_request = VerificationRequest::from_request_event( + alice, + alice_identity, + alice_store.into(), + &room_id, + &bob_id(), + &event_id, + &content, + ); + + let content = alice_request.accept().unwrap(); + + let response = RoomMessageResponse::new(event_id); + bob_request.mark_as_sent(&response); + + bob_request.receive_ready(&alice_id(), &content).unwrap(); + + assert!(bob_request.is_ready()); + assert!(alice_request.is_ready()); + } +}