diff --git a/crates/matrix-sdk/src/room/timeline/mod.rs b/crates/matrix-sdk/src/room/timeline/mod.rs index 89d263515..a3d417f13 100644 --- a/crates/matrix-sdk/src/room/timeline/mod.rs +++ b/crates/matrix-sdk/src/room/timeline/mod.rs @@ -54,7 +54,10 @@ pub use self::{ }, virtual_item::VirtualTimelineItem, }; -use self::{inner::TimelineInner, to_device::handle_room_key_event}; +use self::{ + inner::TimelineInner, + to_device::{handle_forwarded_room_key_event, handle_room_key_event}, +}; /// A high-level view into a regular¹ room's contents. /// @@ -71,6 +74,7 @@ pub struct Timeline { _fully_read_handler_guard: Option, #[cfg(feature = "e2e-encryption")] _room_key_handler_guard: EventHandlerDropGuard, + _forwarded_room_key_handler_guard: EventHandlerDropGuard, } /// Non-signalling parts of `TimelineInner`. @@ -118,6 +122,14 @@ impl Timeline { #[cfg(feature = "e2e-encryption")] let _room_key_handler_guard = room.client.event_handler_drop_guard(room_key_handle); + #[cfg(feature = "e2e-encryption")] + let forwarded_room_key_handle = room.client.add_event_handler( + handle_forwarded_room_key_event(inner.clone(), room.room_id().to_owned()), + ); + #[cfg(feature = "e2e-encryption")] + let _forwarded_room_key_handler_guard = + room.client.event_handler_drop_guard(forwarded_room_key_handle); + Timeline { inner, room: room.clone(), @@ -127,6 +139,8 @@ impl Timeline { _fully_read_handler_guard: None, #[cfg(feature = "e2e-encryption")] _room_key_handler_guard, + #[cfg(feature = "e2e-encryption")] + _forwarded_room_key_handler_guard, } } diff --git a/crates/matrix-sdk/src/room/timeline/to_device.rs b/crates/matrix-sdk/src/room/timeline/to_device.rs index fbcf3858d..16db67576 100644 --- a/crates/matrix-sdk/src/room/timeline/to_device.rs +++ b/crates/matrix-sdk/src/room/timeline/to_device.rs @@ -1,6 +1,9 @@ use std::{iter, sync::Arc}; -use ruma::{events::room_key::ToDeviceRoomKeyEvent, OwnedRoomId}; +use ruma::{ + events::{forwarded_room_key::ToDeviceForwardedRoomKeyEvent, room_key::ToDeviceRoomKeyEvent}, + OwnedRoomId, +}; use tracing::{debug_span, error, trace, Instrument}; use super::inner::TimelineInner; @@ -14,36 +17,61 @@ pub(super) fn handle_room_key_event( let inner = inner.clone(); let room_id = room_id.clone(); async move { - if event.content.room_id != room_id { - let event_room_id = &event.content.room_id; - let session_id = &event.content.session_id; - trace!( - %event_room_id, timeline_room_id = %room_id, %session_id, - "Received to-device room key event for a different room, ignoring" - ); - return; - } - - let Some(olm_machine) = client.olm_machine() else { - error!("The olm machine isn't yet available"); - return; - }; - + let event_room_id = event.content.room_id; let session_id = event.content.session_id; - let Some(own_user_id) = client.user_id() else { - error!("The user's own ID isn't available"); - return; - }; - - inner - .retry_event_decryption( - &room_id, - olm_machine, - iter::once(session_id.as_str()).collect(), - own_user_id, - ) - .await; + retry_decryption(client, inner, room_id, event_room_id, session_id).await; } .instrument(debug_span!("handle_room_key_event")) } } + +pub(super) fn handle_forwarded_room_key_event( + inner: Arc, + room_id: OwnedRoomId, +) -> impl EventHandler { + move |event: ToDeviceForwardedRoomKeyEvent, client: Client| { + let inner = inner.clone(); + let room_id = room_id.clone(); + async move { + let event_room_id = event.content.room_id; + let session_id = event.content.session_id; + retry_decryption(client, inner, room_id, event_room_id, session_id).await; + } + .instrument(debug_span!("handle_forwarded_room_key_event")) + } +} + +async fn retry_decryption( + client: Client, + inner: Arc, + room_id: OwnedRoomId, + event_room_id: OwnedRoomId, + session_id: String, +) { + if event_room_id != room_id { + trace!( + %event_room_id, timeline_room_id = %room_id, %session_id, + "Received to-device room key event for a different room, ignoring" + ); + return; + } + + let Some(olm_machine) = client.olm_machine() else { + error!("The olm machine isn't yet available"); + return; + }; + + let Some(own_user_id) = client.user_id() else { + error!("The user's own ID isn't available"); + return; + }; + + inner + .retry_event_decryption( + &room_id, + olm_machine, + iter::once(session_id.as_str()).collect(), + own_user_id, + ) + .await; +}