From ab28964db3ee2723b85487bb2e46fcef448f09af Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Thu, 10 Oct 2024 17:32:00 +0100 Subject: [PATCH] timeline: store UTDs in `decrypt_room_event` When `decrypt_room_event` fails to decrypt an event, return the UTD as a `TimelineEvent` instead of an Error. --- .../src/deserialized_responses.rs | 8 +++ .../matrix-sdk-ui/src/notification_client.rs | 54 +++++++++++-------- crates/matrix-sdk/src/room/mod.rs | 20 ++++--- 3 files changed, 48 insertions(+), 34 deletions(-) diff --git a/crates/matrix-sdk-common/src/deserialized_responses.rs b/crates/matrix-sdk-common/src/deserialized_responses.rs index 815fda90f2c..3a435f550bd 100644 --- a/crates/matrix-sdk-common/src/deserialized_responses.rs +++ b/crates/matrix-sdk-common/src/deserialized_responses.rs @@ -673,6 +673,14 @@ pub enum UnableToDecryptReason { SenderIdentityNotTrusted(VerificationLevel), } +impl UnableToDecryptReason { + /// Returns true if this UTD is due to a missing room key (and hence might + /// resolve itself if we wait a bit.) + pub fn is_missing_room_key(&self) -> bool { + matches!(self, Self::MissingMegolmSession | Self::UnknownMegolmMessageIndex) + } +} + /// Deserialization helper for [`SyncTimelineEvent`], for the modern format. /// /// This has the exact same fields as [`SyncTimelineEvent`] itself, but has a diff --git a/crates/matrix-sdk-ui/src/notification_client.rs b/crates/matrix-sdk-ui/src/notification_client.rs index cc306440f2d..f00bf09b550 100644 --- a/crates/matrix-sdk-ui/src/notification_client.rs +++ b/crates/matrix-sdk-ui/src/notification_client.rs @@ -20,10 +20,7 @@ use std::{ use futures_util::{pin_mut, StreamExt as _}; use matrix_sdk::{room::Room, Client, ClientBuildError, SlidingSyncList, SlidingSyncMode}; use matrix_sdk_base::{ - crypto::{vodozemac, MegolmError}, - deserialized_responses::TimelineEvent, - sliding_sync::http, - RoomState, StoreError, + deserialized_responses::TimelineEvent, sliding_sync::http, RoomState, StoreError, }; use ruma::{ assign, @@ -216,24 +213,24 @@ impl NotificationClient { tokio::time::sleep(Duration::from_millis(wait)).await; - match room.decrypt_event(raw_event.cast_ref()).await { - Ok(new_event) => { + let new_event = room.decrypt_event(raw_event.cast_ref()).await?; + + match new_event.kind { + matrix_sdk::deserialized_responses::TimelineEventKind::UnableToDecrypt ( + utd_event) => { + if utd_event.utd_info.reason.is_missing_room_key() { + // Decryption error that could be caused by a missing room + // key; retry in a few. + wait *= 2; + } else { + trace!("Event could not be decrypted, but waiting longer is unlikely to help: {:?}", utd_event.utd_info.reason); + return Ok(None); + } + } + _ => { trace!("Waiting succeeded and event could be decrypted!"); return Ok(Some(new_event)); } - Err(matrix_sdk::Error::MegolmError( - MegolmError::MissingRoomKey(_) - | MegolmError::Decryption( - vodozemac::megolm::DecryptionError::UnknownMessageIndex(_, _), - ), - )) => { - // Decryption error that could be caused by a missing room key; - // retry in a few. - wait *= 2; - } - Err(err) => { - return Err(err.into()); - } } } @@ -259,10 +256,21 @@ impl NotificationClient { match encryption_sync { Ok(sync) => match sync.run_fixed_iterations(2, sync_permit_guard).await { Ok(()) => match room.decrypt_event(raw_event.cast_ref()).await { - Ok(new_event) => { - trace!("Encryption sync managed to decrypt the event."); - Ok(Some(new_event)) - } + Ok(new_event) => match new_event.kind { + matrix_sdk::deserialized_responses::TimelineEventKind::UnableToDecrypt( + utd_event, + ) => { + trace!( + "Encryption sync failed to decrypt the event: {:?}", + utd_event.utd_info.reason + ); + Ok(None) + } + _ => { + trace!("Encryption sync managed to decrypt the event."); + Ok(Some(new_event)) + } + }, Err(err) => { trace!("Encryption sync failed to decrypt the event: {err}"); Ok(None) diff --git a/crates/matrix-sdk/src/room/mod.rs b/crates/matrix-sdk/src/room/mod.rs index 1a5287abd98..a36fce9ef6e 100644 --- a/crates/matrix-sdk/src/room/mod.rs +++ b/crates/matrix-sdk/src/room/mod.rs @@ -19,7 +19,7 @@ use futures_util::{ #[cfg(all(feature = "e2e-encryption", not(target_arch = "wasm32")))] pub use identity_status_changes::IdentityStatusChanges; #[cfg(feature = "e2e-encryption")] -use matrix_sdk_base::crypto::DecryptionSettings; +use matrix_sdk_base::crypto::{DecryptionSettings, RoomEventDecryptionResult}; #[cfg(all(feature = "e2e-encryption", not(target_arch = "wasm32")))] use matrix_sdk_base::crypto::{IdentityStatusChange, RoomIdentityProvider, UserIdentity}; use matrix_sdk_base::{ @@ -1210,7 +1210,8 @@ impl Room { /// # Arguments /// * `event` - The room event to be decrypted. /// - /// Returns the decrypted event. + /// Returns the decrypted event. In the case of a decryption error, returns + /// a `TimelineEvent` representing the decryption error. #[cfg(feature = "e2e-encryption")] pub async fn decrypt_event( &self, @@ -1222,24 +1223,21 @@ impl Room { let decryption_settings = DecryptionSettings { sender_device_trust_requirement: self.client.base_client().decryption_trust_requirement, }; - let decrypted = match machine - .decrypt_room_event(event.cast_ref(), self.inner.room_id(), &decryption_settings) - .await + let mut event: TimelineEvent = match machine + .try_decrypt_room_event(event.cast_ref(), self.inner.room_id(), &decryption_settings) + .await? { - Ok(event) => event, - Err(e) => { + RoomEventDecryptionResult::Decrypted(decrypted) => decrypted.into(), + RoomEventDecryptionResult::UnableToDecrypt(utd_info) => { self.client .encryption() .backups() .maybe_download_room_key(self.room_id().to_owned(), event.clone()); - - return Err(e.into()); + TimelineEvent::new_utd_event(event.clone().cast(), utd_info) } }; - let mut event: TimelineEvent = decrypted.into(); event.push_actions = self.event_push_actions(event.raw()).await?; - Ok(event) }