diff --git a/matrix_sdk/src/error.rs b/matrix_sdk/src/error.rs index c293797a..a060c217 100644 --- a/matrix_sdk/src/error.rs +++ b/matrix_sdk/src/error.rs @@ -18,6 +18,8 @@ use reqwest::Error as ReqwestError; use serde_json::Error as JsonError; use thiserror::Error; +#[cfg(feature = "encryption")] +use matrix_sdk_base::CryptoStoreError; use matrix_sdk_base::Error as MatrixError; use crate::api::r0::uiaa::UiaaResponse as UiaaError; @@ -55,6 +57,10 @@ pub enum Error { #[error(transparent)] MatrixError(#[from] MatrixError), + /// An error occurred in the crypto store. + #[error(transparent)] + CryptoStoreError(#[from] CryptoStoreError), + /// An error occurred while authenticating. /// /// When registering or authenticating the Matrix server can send a `UiaaResponse` diff --git a/matrix_sdk/src/sas.rs b/matrix_sdk/src/sas.rs index 224b1c36..d9f700d8 100644 --- a/matrix_sdk/src/sas.rs +++ b/matrix_sdk/src/sas.rs @@ -42,9 +42,10 @@ impl Sas { /// Confirm that the short auth strings match on both sides. pub async fn confirm(&self) -> Result<()> { - if let Some(request) = self.inner.confirm() { + if let Some(request) = self.inner.confirm().await? { self.http_client.send(request, self.session.clone()).await?; } + Ok(()) } diff --git a/matrix_sdk_base/src/lib.rs b/matrix_sdk_base/src/lib.rs index 7e6b7fd5..cac16e53 100644 --- a/matrix_sdk_base/src/lib.rs +++ b/matrix_sdk_base/src/lib.rs @@ -51,7 +51,7 @@ pub use models::Room; pub use state::{AllRooms, ClientState}; #[cfg(feature = "encryption")] -pub use matrix_sdk_crypto::{Device, Sas, TrustState}; +pub use matrix_sdk_crypto::{CryptoStoreError, Device, Sas, TrustState}; #[cfg(feature = "messages")] #[cfg_attr(docsrs, doc(cfg(feature = "messages")))] diff --git a/matrix_sdk_crypto/src/store/mod.rs b/matrix_sdk_crypto/src/store/mod.rs index a848136d..95a1f040 100644 --- a/matrix_sdk_crypto/src/store/mod.rs +++ b/matrix_sdk_crypto/src/store/mod.rs @@ -23,7 +23,7 @@ use matrix_sdk_common::locks::Mutex; use serde_json::Error as SerdeError; use thiserror::Error; -use super::device::{Device, TrustState}; +use super::device::Device; use super::memory_stores::UserDevices; use super::olm::{Account, InboundGroupSession, Session}; use matrix_sdk_common::identifiers::{DeviceId, RoomId, UserId}; @@ -188,19 +188,4 @@ pub trait CryptoStore: Debug { /// /// * `user_id` - The user for which we should get all the devices. async fn get_user_devices(&self, user_id: &UserId) -> Result; - - /// Set the trust state of the given device. - /// - /// # Arguments - /// - /// * `device` - The device that should have its trust state changed. - /// - /// * `state` - The new state that should be set on the device. - async fn set_device_verification(&self, device: Device, state: TrustState) -> Result<()> - where - Self: Sized, - { - device.set_trust_state(state); - self.save_devices(&[device]).await - } } diff --git a/matrix_sdk_crypto/src/verification/machine.rs b/matrix_sdk_crypto/src/verification/machine.rs index 6d7d0263..c9573980 100644 --- a/matrix_sdk_crypto/src/verification/machine.rs +++ b/matrix_sdk_crypto/src/verification/machine.rs @@ -92,7 +92,7 @@ impl VerificationMachine { .get_device(&e.sender, &e.content.from_device) .await? { - match Sas::from_start_event(self.account.clone(), d, e) { + match Sas::from_start_event(self.account.clone(), d, self.store.clone(), e) { Ok(s) => { self.verifications .insert(e.content.transaction_id.clone(), s); @@ -161,6 +161,8 @@ mod test { let alice = Account::new(&alice_id(), &alice_device_id()); let bob = Account::new(&bob_id(), &bob_device_id()); let store = MemoryStore::new(); + let bob_store: Arc>> = + Arc::new(RwLock::new(Box::new(MemoryStore::new()))); let bob_device = Device::from_account(&bob).await; let alice_device = Device::from_account(&alice).await; @@ -168,7 +170,7 @@ mod test { store.save_devices(&[bob_device]).await.unwrap(); let machine = VerificationMachine::new(alice, Arc::new(RwLock::new(Box::new(store)))); - let (bob_sas, start_content) = Sas::start(bob, alice_device); + let (bob_sas, start_content) = Sas::start(bob, alice_device, bob_store); machine .receive_event(&mut wrap_any_to_device_content( bob_sas.user_id(), @@ -229,13 +231,13 @@ mod test { let mut event = wrap_any_to_device_content( alice.user_id(), - get_content_from_request(&alice.confirm().unwrap()), + get_content_from_request(&alice.confirm().await.unwrap().unwrap()), ); bob.receive_event(&mut event); let mut event = wrap_any_to_device_content( bob.user_id(), - get_content_from_request(&bob.confirm().unwrap()), + get_content_from_request(&bob.confirm().await.unwrap().unwrap()), ); alice.receive_event(&mut event); diff --git a/matrix_sdk_crypto/src/verification/sas/mod.rs b/matrix_sdk_crypto/src/verification/sas/mod.rs index 1e0c5ac6..7c9b793e 100644 --- a/matrix_sdk_crypto/src/verification/sas/mod.rs +++ b/matrix_sdk_crypto/src/verification/sas/mod.rs @@ -27,9 +27,10 @@ use matrix_sdk_common::{ AnyToDeviceEvent, AnyToDeviceEventContent, ToDeviceEvent, }, identifiers::{DeviceId, UserId}, + locks::RwLock, }; -use crate::{Account, Device}; +use crate::{Account, CryptoStore, CryptoStoreError, Device, TrustState}; pub use helpers::content_to_request; use sas_state::{ Accepted, Canceled, Confirmed, Created, Done, KeyReceived, MacReceived, SasState, Started, @@ -39,6 +40,7 @@ use sas_state::{ /// Short authentication string object. pub struct Sas { inner: Arc>, + store: Arc>>, account: Account, other_device: Device, flow_id: Arc, @@ -80,13 +82,18 @@ impl Sas { /// /// Returns the new `Sas` object and a `StartEventContent` that needs to be /// sent out through the server to the other device. - pub(crate) fn start(account: Account, other_device: Device) -> (Sas, StartEventContent) { + pub(crate) fn start( + account: Account, + other_device: Device, + store: Arc>>, + ) -> (Sas, StartEventContent) { let (inner, content) = InnerSas::start(account.clone(), other_device.clone()); let flow_id = inner.verification_flow_id(); let sas = Sas { inner: Arc::new(Mutex::new(inner)), account, + store, other_device, flow_id, }; @@ -107,6 +114,7 @@ impl Sas { pub(crate) fn from_start_event( account: Account, other_device: Device, + store: Arc>>, event: &ToDeviceEvent, ) -> Result { let inner = InnerSas::from_start_event(account.clone(), other_device.clone(), event)?; @@ -115,6 +123,7 @@ impl Sas { inner: Arc::new(Mutex::new(inner)), account, other_device, + store, flow_id, }) } @@ -137,16 +146,41 @@ impl Sas { /// Does nothing if we're not in a state where we can confirm the short auth /// string, otherwise returns a `MacEventContent` that needs to be sent to /// the server. - pub fn confirm(&self) -> Option { + pub async fn confirm(&self) -> Result, CryptoStoreError> { let mut guard = self.inner.lock().unwrap(); let sas: InnerSas = (*guard).clone(); let (sas, content) = sas.confirm(); *guard = sas; - content.map(|c| { + if guard.is_done() { + self.mark_device_as_verified().await?; + } + + Ok(content.map(|c| { let content = AnyToDeviceEventContent::KeyVerificationMac(c); self.content_to_request(content) - }) + })) + } + + async fn mark_device_as_verified(&self) -> Result { + let device = self + .store + .read() + .await + .get_device(self.other_user_id(), self.other_device_id()) + .await?; + + if let Some(device) = device { + if device.keys() == self.other_device.keys() { + device.set_trust_state(TrustState::Verified); + self.store.read().await.save_devices(&[device]).await?; + Ok(true) + } else { + Ok(false) + } + } else { + Ok(false) + } } /// Cancel the verification. @@ -414,13 +448,16 @@ impl InnerSas { #[cfg(test)] mod test { use std::convert::TryFrom; + use std::sync::Arc; use matrix_sdk_common::events::{EventContent, ToDeviceEvent}; use matrix_sdk_common::identifiers::{DeviceId, UserId}; + use matrix_sdk_common::locks::RwLock; use crate::{ + store::memorystore::MemoryStore, verification::test::{get_content_from_request, wrap_any_to_device_content}, - Account, Device, + Account, CryptoStore, Device, }; use super::{Accepted, Created, Sas, SasState, Started}; @@ -539,10 +576,15 @@ mod test { let bob = Account::new(&bob_id(), &bob_device_id()); let bob_device = Device::from_account(&bob).await; - let (alice, content) = Sas::start(alice, bob_device); + let alice_store: Arc>> = + Arc::new(RwLock::new(Box::new(MemoryStore::new()))); + let bob_store: Arc>> = + Arc::new(RwLock::new(Box::new(MemoryStore::new()))); + + let (alice, content) = Sas::start(alice, bob_device, alice_store); let event = wrap_to_device_event(alice.user_id(), content); - let bob = Sas::from_start_event(bob, alice_device, &event).unwrap(); + let bob = Sas::from_start_event(bob, alice_device, bob_store, &event).unwrap(); let mut event = wrap_any_to_device_content( bob.user_id(), get_content_from_request(&bob.accept().unwrap()), @@ -567,13 +609,13 @@ mod test { let mut event = wrap_any_to_device_content( alice.user_id(), - get_content_from_request(&alice.confirm().unwrap()), + get_content_from_request(&alice.confirm().await.unwrap().unwrap()), ); bob.receive_event(&mut event); let mut event = wrap_any_to_device_content( bob.user_id(), - get_content_from_request(&bob.confirm().unwrap()), + get_content_from_request(&bob.confirm().await.unwrap().unwrap()), ); alice.receive_event(&mut event);