refactor(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.
This commit is contained in:
Richard van der Hoff
2024-10-10 17:32:00 +01:00
committed by Richard van der Hoff
parent 543152d914
commit b69575d5ff
3 changed files with 48 additions and 34 deletions

View File

@@ -708,6 +708,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

View File

@@ -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_info, ..} => {
if 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 {
debug!("Event could not be decrypted, but waiting longer is unlikely to help: {:?}", 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_info, ..
} => {
trace!(
"Encryption sync failed to decrypt the 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)

View File

@@ -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::{
@@ -1215,7 +1215,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,
@@ -1227,24 +1228,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)
}