diff --git a/crates/matrix-sdk/src/encryption/mod.rs b/crates/matrix-sdk/src/encryption/mod.rs index 6b50c2a49..16cbfddd6 100644 --- a/crates/matrix-sdk/src/encryption/mod.rs +++ b/crates/matrix-sdk/src/encryption/mod.rs @@ -26,19 +26,15 @@ use std::{ }; use futures_util::stream::{self, StreamExt}; -pub use matrix_sdk_base::crypto::{LocalTrust, MediaEncryptionInfo, RoomKeyImportResult}; -use matrix_sdk_base::{ - crypto::{ - store::CryptoStoreError, CrossSigningStatus, OutgoingRequest, RoomMessageRequest, - ToDeviceRequest, - }, - deserialized_responses::RoomEvent, +use matrix_sdk_base::crypto::{ + store::CryptoStoreError, CrossSigningStatus, OutgoingRequest, RoomMessageRequest, + ToDeviceRequest, }; +pub use matrix_sdk_base::crypto::{LocalTrust, MediaEncryptionInfo, RoomKeyImportResult}; use matrix_sdk_common::instant::Duration; #[cfg(feature = "e2e-encryption")] use ruma::{ - api::client::config::set_global_account_data, - events::{GlobalAccountDataEventContent, MessageLikeEvent}, + api::client::config::set_global_account_data, events::GlobalAccountDataEventContent, OwnedDeviceId, }; use ruma::{ @@ -54,8 +50,7 @@ use ruma::{ uiaa::AuthData, }, assign, - events::{AnyMessageLikeEvent, AnyRoomEvent, GlobalAccountDataEventType}, - serde::Raw, + events::GlobalAccountDataEventType, DeviceId, OwnedUserId, TransactionId, UserId, }; use tracing::{debug, instrument, trace, warn}; @@ -71,33 +66,6 @@ use crate::{ }; impl Client { - /// Tries to decrypt a `AnyRoomEvent`. Returns undecrypted room event when - /// decryption fails. - #[cfg(feature = "e2e-encryption")] - pub(crate) async fn decrypt_room_event(&self, event: Raw) -> RoomEvent { - if let Some(machine) = self.olm_machine().await { - if let Ok(AnyRoomEvent::MessageLike(event)) = event.deserialize() { - if let AnyMessageLikeEvent::RoomEncrypted(_) = event { - let room_id = event.room_id(); - - if let AnyMessageLikeEvent::RoomEncrypted(MessageLikeEvent::Original(ev)) = - &event - { - // Turn the OriginalMessageLikeEvent into a OriginalSyncMessageLikeEvent - let ev = ev.clone().into(); - if let Ok(decrypted) = machine.decrypt_room_event(&ev, room_id).await { - return decrypted; - } - } - } - } - } - - // Fallback to still-encrypted room event - - RoomEvent { event, encryption_info: None } - } - /// Query the server for users device keys. /// /// # Panics diff --git a/crates/matrix-sdk/src/error.rs b/crates/matrix-sdk/src/error.rs index 5c533aea8..5e1b678b9 100644 --- a/crates/matrix-sdk/src/error.rs +++ b/crates/matrix-sdk/src/error.rs @@ -122,6 +122,11 @@ pub enum Error { #[error("The olm machine has already been initialized")] BadCryptoStoreState, + /// Attempting to access the olm-machine but it is not yet available. + #[cfg(feature = "e2e-encryption")] + #[error("The olm machine isn't yet available")] + NoOlmMachine, + /// An error de/serializing type for the `StateStore` #[error(transparent)] SerdeJson(#[from] JsonError), diff --git a/crates/matrix-sdk/src/room/common.rs b/crates/matrix-sdk/src/room/common.rs index b6ea52a4c..a08c138ad 100644 --- a/crates/matrix-sdk/src/room/common.rs +++ b/crates/matrix-sdk/src/room/common.rs @@ -4,13 +4,15 @@ use std::{collections::BTreeMap, ops::Deref, sync::Arc}; use futures_core::stream::Stream; use matrix_sdk_base::deserialized_responses::{MembersResponse, RoomEvent}; #[cfg(feature = "experimental-timeline")] -use matrix_sdk_base::{ - deserialized_responses::{SyncRoomEvent, TimelineSlice}, - TimelineStreamError, -}; +use matrix_sdk_base::{deserialized_responses::TimelineSlice, TimelineStreamError}; use matrix_sdk_common::locks::Mutex; #[cfg(feature = "experimental-timeline")] use ruma::api::client::filter::LazyLoadOptions; +#[cfg(feature = "e2e-encryption")] +use ruma::events::{ + room::encrypted::OriginalSyncRoomEncryptedEvent, AnySyncMessageLikeEvent, AnySyncRoomEvent, + SyncMessageLikeEvent, +}; use ruma::{ api::client::{ config::set_global_account_data, @@ -178,24 +180,47 @@ impl Common { /// # }); /// ``` pub async fn messages(&self, options: MessagesOptions<'_>) -> Result { - let request = options.into_request(self.inner.room_id()); + let room_id = self.inner.room_id(); + let request = options.into_request(room_id); let http_response = self.client.send(request, None).await?; + #[allow(unused_mut)] let mut response = Messages { start: http_response.start, end: http_response.end, + #[cfg(not(feature = "e2e-encryption"))] + chunk: http_response + .chunk + .into_iter() + .map(|event| RoomEvent { event, encryption_info: None }) + .collect(), + #[cfg(feature = "e2e-encryption")] chunk: Vec::with_capacity(http_response.chunk.len()), state: http_response.state, }; - for event in http_response.chunk { - #[cfg(feature = "e2e-encryption")] - let event = self.client.decrypt_room_event(event).await; + #[cfg(feature = "e2e-encryption")] + if let Some(machine) = self.client.olm_machine().await { + for event in http_response.chunk { + let decrypted_event = + if let AnySyncRoomEvent::MessageLike(AnySyncMessageLikeEvent::RoomEncrypted( + SyncMessageLikeEvent::Original(encrypted_event), + )) = event.deserialize_as::()? + { + machine.decrypt_room_event(&encrypted_event, room_id).await? + } else { + RoomEvent { event, encryption_info: None } + }; - #[cfg(not(feature = "e2e-encryption"))] - let event = RoomEvent { event, encryption_info: None }; - - response.chunk.push(event); + response.chunk.push(decrypted_event); + } + } else { + response.chunk.extend( + http_response + .chunk + .into_iter() + .map(|event| RoomEvent { event, encryption_info: None }), + ); } Ok(response) @@ -450,10 +475,17 @@ impl Common { let event = self.client.send(request, None).await?.event; #[cfg(feature = "e2e-encryption")] - return Ok(self.client.decrypt_room_event(event).await); + if let AnySyncRoomEvent::MessageLike(AnySyncMessageLikeEvent::RoomEncrypted( + SyncMessageLikeEvent::Original(encrypted_event), + )) = event.deserialize_as::()? + { + Ok(self.decrypt_event(&encrypted_event).await?) + } else { + Ok(RoomEvent { event, encryption_info: None }) + } #[cfg(not(feature = "e2e-encryption"))] - return Ok(RoomEvent { event, encryption_info: None }); + Ok(RoomEvent { event, encryption_info: None }) } pub(crate) async fn request_members(&self) -> Result> { @@ -876,6 +908,21 @@ impl Common { self.client.send(request, None).await?; Ok(()) } + + /// Tries to decrypt a room event. + /// + /// # Arguments + /// * `event` - The room event to be decrypted. + /// + /// Returns the decrypted event. + #[cfg(feature = "e2e-encryption")] + pub async fn decrypt_event(&self, event: &OriginalSyncRoomEncryptedEvent) -> Result { + if let Some(machine) = self.client.olm_machine().await { + Ok(machine.decrypt_room_event(event, self.inner.room_id()).await?) + } else { + Err(Error::NoOlmMachine) + } + } } /// Options for [`messages`][Common::messages].