diff --git a/matrix_sdk/examples/emoji_verification.rs b/matrix_sdk/examples/emoji_verification.rs index 5b153bfd..e3f25136 100644 --- a/matrix_sdk/examples/emoji_verification.rs +++ b/matrix_sdk/examples/emoji_verification.rs @@ -81,7 +81,12 @@ async fn login( let client = &client_ref; let initial = &initial_ref; - for event in &response.to_device.events { + for event in response + .to_device + .events + .iter() + .filter_map(|e| e.deserialize().ok()) + { match event { AnyToDeviceEvent::KeyVerificationStart(e) => { let sas = client @@ -124,7 +129,12 @@ async fn login( if !initial.load(Ordering::SeqCst) { for (_room_id, room_info) in response.rooms.join { - for event in room_info.timeline.events { + for event in room_info + .timeline + .events + .iter() + .filter_map(|e| e.event.deserialize().ok()) + { if let AnySyncRoomEvent::Message(event) = event { match event { AnySyncMessageEvent::RoomMessage(m) => { diff --git a/matrix_sdk/examples/wasm_command_bot/src/lib.rs b/matrix_sdk/examples/wasm_command_bot/src/lib.rs index e7e8c0e5..7f4abbb4 100644 --- a/matrix_sdk/examples/wasm_command_bot/src/lib.rs +++ b/matrix_sdk/examples/wasm_command_bot/src/lib.rs @@ -58,7 +58,7 @@ impl WasmBot { for (room_id, room) in response.rooms.join { for event in room.timeline.events { - if let AnySyncRoomEvent::Message(AnySyncMessageEvent::RoomMessage(ev)) = event { + if let Ok(AnySyncRoomEvent::Message(AnySyncMessageEvent::RoomMessage(ev))) = event.event.deserialize() { self.on_room_message(&room_id, &ev).await } } diff --git a/matrix_sdk/src/event_handler/mod.rs b/matrix_sdk/src/event_handler/mod.rs index 17d706b3..370fa2fc 100644 --- a/matrix_sdk/src/event_handler/mod.rs +++ b/matrix_sdk/src/event_handler/mod.rs @@ -75,50 +75,95 @@ impl Handler { pub(crate) async fn handle_sync(&self, response: &SyncResponse) { for (room_id, room_info) in &response.rooms.join { if let Some(room) = self.get_room(room_id) { - for event in &room_info.ephemeral.events { - self.handle_ephemeral_event(room.clone(), event).await; + for event in room_info + .ephemeral + .events + .iter() + .filter_map(|e| e.deserialize().ok()) + { + self.handle_ephemeral_event(room.clone(), &event).await; } - for event in &room_info.account_data.events { - self.handle_account_data_event(room.clone(), event).await; + for event in room_info + .account_data + .events + .iter() + .filter_map(|e| e.deserialize().ok()) + { + self.handle_account_data_event(room.clone(), &event).await; } - for event in &room_info.state.events { - self.handle_state_event(room.clone(), event).await; + for event in room_info + .state + .events + .iter() + .filter_map(|e| e.deserialize().ok()) + { + self.handle_state_event(room.clone(), &event).await; } - for event in &room_info.timeline.events { - self.handle_timeline_event(room.clone(), event).await; + for event in room_info + .timeline + .events + .iter() + .filter_map(|e| e.event.deserialize().ok()) + { + self.handle_timeline_event(room.clone(), &event).await; } } } for (room_id, room_info) in &response.rooms.leave { if let Some(room) = self.get_room(room_id) { - for event in &room_info.account_data.events { - self.handle_account_data_event(room.clone(), event).await; + for event in room_info + .account_data + .events + .iter() + .filter_map(|e| e.deserialize().ok()) + { + self.handle_account_data_event(room.clone(), &event).await; } - for event in &room_info.state.events { - self.handle_state_event(room.clone(), event).await; + for event in room_info + .state + .events + .iter() + .filter_map(|e| e.deserialize().ok()) + { + self.handle_state_event(room.clone(), &event).await; } - for event in &room_info.timeline.events { - self.handle_timeline_event(room.clone(), event).await; + for event in room_info + .timeline + .events + .iter() + .filter_map(|e| e.event.deserialize().ok()) + { + self.handle_timeline_event(room.clone(), &event).await; } } } for (room_id, room_info) in &response.rooms.invite { if let Some(room) = self.get_room(room_id) { - for event in &room_info.invite_state.events { - self.handle_stripped_state_event(room.clone(), event).await; + for event in room_info + .invite_state + .events + .iter() + .filter_map(|e| e.deserialize().ok()) + { + self.handle_stripped_state_event(room.clone(), &event).await; } } } - for event in &response.presence.events { - self.on_presence_event(event).await; + for event in response + .presence + .events + .iter() + .filter_map(|e| e.deserialize().ok()) + { + self.on_presence_event(&event).await; } for (room_id, notifications) in &response.notifications { diff --git a/matrix_sdk_base/src/client.rs b/matrix_sdk_base/src/client.rs index d1e8fe38..732909e7 100644 --- a/matrix_sdk_base/src/client.rs +++ b/matrix_sdk_base/src/client.rs @@ -37,15 +37,13 @@ use matrix_sdk_common::{ use matrix_sdk_common::{ api::r0::{self as api, push::get_notifications::Notification}, deserialized_responses::{ - AccountData, AmbiguityChanges, Ephemeral, InviteState, InvitedRoom, JoinedRoom, LeftRoom, - MemberEvent, MembersResponse, Presence, Rooms, State, StrippedMemberEvent, SyncResponse, - Timeline, + AmbiguityChanges, JoinedRoom, LeftRoom, MemberEvent, MembersResponse, Rooms, + StrippedMemberEvent, SyncResponse, SyncRoomEvent, Timeline, }, events::{ - presence::PresenceEvent, room::member::{MemberEventContent, MembershipState}, - AnyBasicEvent, AnyStrippedStateEvent, AnySyncRoomEvent, AnySyncStateEvent, - AnyToDeviceEvent, EventContent, EventType, StateEvent, + AnyBasicEvent, AnyStrippedStateEvent, AnySyncRoomEvent, AnySyncStateEvent, EventContent, + EventType, StateEvent, }, identifiers::{RoomId, UserId}, instant::Instant, @@ -432,15 +430,13 @@ impl BaseClient { let mut push_context = self.get_push_room_context(room, room_info, changes).await?; for event in ruma_timeline.events { - match hoist_room_event_prev_content(&event) { - Ok(mut e) => { - #[cfg(not(feature = "encryption"))] - let raw_event = event; - #[cfg(feature = "encryption")] - let mut raw_event = event; + #[allow(unused_mut)] + let mut event: SyncRoomEvent = event.into(); + match hoist_room_event_prev_content(&event.event) { + Ok(e) => { #[allow(clippy::single_match)] - match &mut e { + match &e { AnySyncRoomEvent::State(s) => match s { AnySyncStateEvent::RoomMember(member) => { if let Ok(member) = MemberEvent::try_from(member.clone()) { @@ -478,7 +474,9 @@ impl BaseClient { } _ => { room_info.handle_state_event(&s.content()); - changes.add_state_event(room_id, s.clone()); + let raw_event: Raw = + Raw::from_json(event.event.clone().into_json()); + changes.add_state_event(room_id, s.clone(), raw_event); } }, @@ -487,18 +485,10 @@ impl BaseClient { encrypted, )) => { if let Some(olm) = self.olm_machine().await { - if let Ok(raw_decrypted) = + if let Ok(decrypted) = olm.decrypt_room_event(encrypted, room_id).await { - match raw_decrypted.deserialize() { - Ok(decrypted) => { - e = decrypted; - raw_event = raw_decrypted; - } - Err(e) => { - warn!("Error deserializing a decrypted event {:?} ", e) - } - } + event = decrypted; } } } @@ -517,14 +507,14 @@ impl BaseClient { } if let Some(context) = &push_context { - let actions = push_rules.get_actions(&raw_event, &context).to_vec(); + let actions = push_rules.get_actions(&event.event, &context).to_vec(); if actions.iter().any(|a| matches!(a, Action::Notify)) { changes.add_notification( room_id, Notification::new( actions, - raw_event, + event.event.clone(), false, room_id.clone(), SystemTime::now(), @@ -537,13 +527,13 @@ impl BaseClient { // Requires the possibility to associate custom data with events and to // store them. } - - timeline.events.push(e); } Err(e) => { warn!("Error deserializing event {:?}", e); } } + + timeline.events.push(event); } Ok(timeline) @@ -552,19 +542,17 @@ impl BaseClient { #[allow(clippy::type_complexity)] fn handle_invited_state( &self, - events: Vec>, + events: &[Raw], room_info: &mut RoomInfo, ) -> ( - InviteState, BTreeMap, - BTreeMap>, + BTreeMap>>, ) { - events.into_iter().fold( - (InviteState::default(), BTreeMap::new(), BTreeMap::new()), - |(mut state, mut members, mut state_events), e| { - match e.deserialize() { + events.iter().fold( + (BTreeMap::new(), BTreeMap::new()), + |(mut members, mut state_events), raw_event| { + match raw_event.deserialize() { Ok(e) => { - state.events.push(e.clone()); if let AnyStrippedStateEvent::RoomMember(member) = e { match StrippedMemberEvent::try_from(member) { @@ -581,7 +569,7 @@ impl BaseClient { state_events .entry(e.content().event_type().to_owned()) .or_insert_with(BTreeMap::new) - .insert(e.state_key().to_owned(), e); + .insert(e.state_key().to_owned(), raw_event.clone()); } } Err(err) => { @@ -591,7 +579,7 @@ impl BaseClient { ); } } - (state, members, state_events) + (members, state_events) }, ) } @@ -600,10 +588,9 @@ impl BaseClient { &self, changes: &mut StateChanges, ambiguity_cache: &mut AmbiguityCache, - events: Vec>, + events: &[Raw], room_info: &mut RoomInfo, - ) -> StoreResult<(State, BTreeSet)> { - let mut state = State::default(); + ) -> StoreResult> { let mut members = BTreeMap::new(); let mut state_events = BTreeMap::new(); let mut user_ids = BTreeSet::new(); @@ -611,21 +598,18 @@ impl BaseClient { let room_id = room_info.room_id.clone(); - for event in - events - .into_iter() - .filter_map(|e| match hoist_and_deserialize_state_event(&e) { - Ok(e) => Some(e), - Err(err) => { - warn!( - "Couldn't deserialize state event for room {}: {:?} {:#?}", - room_id, err, e - ); - None - } - }) - { - state.events.push(event.clone()); + for raw_event in events { + let event = match hoist_and_deserialize_state_event(raw_event) { + Ok(e) => e, + Err(e) => { + warn!( + "Couldn't deserialize state event for room {}: {:?} {:#?}", + room_id, e, raw_event + ); + continue; + } + }; + room_info.handle_state_event(&event.content()); if let AnySyncStateEvent::RoomMember(member) = event { @@ -659,7 +643,7 @@ impl BaseClient { state_events .entry(event.content().event_type().to_owned()) .or_insert_with(BTreeMap::new) - .insert(event.state_key().to_owned(), event); + .insert(event.state_key().to_owned(), raw_event.clone()); } } @@ -667,7 +651,7 @@ impl BaseClient { changes.profiles.insert(room_id.as_ref().clone(), profiles); changes.state.insert(room_id.as_ref().clone(), state_events); - Ok((state, user_ids)) + Ok(user_ids) } async fn handle_room_account_data( @@ -675,27 +659,25 @@ impl BaseClient { room_id: &RoomId, events: &[Raw], changes: &mut StateChanges, - ) -> AccountData { - let events: Vec = - events.iter().filter_map(|e| e.deserialize().ok()).collect(); - - for event in &events { - changes.add_room_account_data(room_id, event.clone()); + ) { + for raw_event in events { + if let Ok(event) = raw_event.deserialize() { + changes.add_room_account_data(room_id, event, raw_event.clone()); + } } - - AccountData { events } } - async fn handle_account_data( - &self, - events: Vec>, - changes: &mut StateChanges, - ) { - let events: Vec = - events.iter().filter_map(|e| e.deserialize().ok()).collect(); + async fn handle_account_data(&self, events: &[Raw], changes: &mut StateChanges) { + let mut account_data = BTreeMap::new(); - for event in &events { - if let AnyBasicEvent::Direct(e) = event { + for raw_event in events { + let event = if let Ok(e) = raw_event.deserialize() { + e + } else { + continue; + }; + + if let AnyBasicEvent::Direct(e) = &event { for (user_id, rooms) in e.content.iter() { for room_id in rooms { if let Some(room) = changes.room_infos.get_mut(room_id) { @@ -708,12 +690,9 @@ impl BaseClient { } } } - } - let account_data: BTreeMap = events - .into_iter() - .map(|e| (e.content().event_type().to_owned(), e)) - .collect(); + account_data.insert(event.content().event_type().to_owned(), raw_event.clone()); + } changes.account_data = account_data; } @@ -769,29 +748,17 @@ impl BaseClient { // decryptes to-device events, but leaves room events alone. // This makes sure that we have the deryption keys for the room // events at hand. - o.receive_sync_changes(&to_device, &device_lists, &device_one_time_keys_count) + o.receive_sync_changes(to_device, &device_lists, &device_one_time_keys_count) .await? } else { to_device - .events - .into_iter() - .filter_map(|e| e.deserialize().ok()) - .collect::>() - .into() } }; - #[cfg(not(feature = "encryption"))] - let to_device = to_device - .events - .into_iter() - .filter_map(|e| e.deserialize().ok()) - .collect::>() - .into(); let mut changes = StateChanges::new(next_batch.clone()); let mut ambiguity_cache = AmbiguityCache::new(self.store.clone()); - self.handle_account_data(account_data.events, &mut changes) + self.handle_account_data(&account_data.events, &mut changes) .await; let push_rules = self.get_push_rules(&changes).await?; @@ -809,11 +776,11 @@ impl BaseClient { room_info.update_summary(&new_info.summary); room_info.set_prev_batch(new_info.timeline.prev_batch.as_deref()); - let (state, mut user_ids) = self + let mut user_ids = self .handle_state( &mut changes, &mut ambiguity_cache, - new_info.state.events, + &new_info.state.events, &mut room_info, ) .await?; @@ -834,8 +801,7 @@ impl BaseClient { ) .await?; - let account_data = self - .handle_room_account_data(&room_id, &new_info.account_data.events, &mut changes) + self.handle_room_account_data(&room_id, &new_info.account_data.events, &mut changes) .await; #[cfg(feature = "encryption")] @@ -859,18 +825,15 @@ impl BaseClient { let notification_count = new_info.unread_notifications.into(); room_info.update_notification_count(notification_count); - let ephemeral = Ephemeral { - events: new_info - .ephemeral - .events - .into_iter() - .filter_map(|e| e.deserialize().ok()) - .collect(), - }; - new_rooms.join.insert( room_id, - JoinedRoom::new(timeline, state, account_data, ephemeral, notification_count), + JoinedRoom::new( + timeline, + new_info.state, + new_info.account_data, + new_info.ephemeral, + notification_count, + ), ); changes.add_room(room_info); @@ -884,11 +847,11 @@ impl BaseClient { let mut room_info = room.clone_info(); room_info.mark_as_left(); - let (state, mut user_ids) = self + let mut user_ids = self .handle_state( &mut changes, &mut ambiguity_cache, - new_info.state.events, + &new_info.state.events, &mut room_info, ) .await?; @@ -905,14 +868,14 @@ impl BaseClient { ) .await?; - let account_data = self - .handle_room_account_data(&room_id, &new_info.account_data.events, &mut changes) + self.handle_room_account_data(&room_id, &new_info.account_data.events, &mut changes) .await; changes.add_room(room_info); - new_rooms - .leave - .insert(room_id, LeftRoom::new(timeline, state, account_data)); + new_rooms.leave.insert( + room_id, + LeftRoom::new(timeline, new_info.state, new_info.account_data), + ); } for (room_id, new_info) in rooms.invite { @@ -929,31 +892,25 @@ impl BaseClient { let room = self.store.get_or_create_stripped_room(&room_id).await; let mut room_info = room.clone_info(); - let (state, members, state_events) = - self.handle_invited_state(new_info.invite_state.events, &mut room_info); + let (members, state_events) = + self.handle_invited_state(&new_info.invite_state.events, &mut room_info); changes.stripped_members.insert(room_id.clone(), members); changes.stripped_state.insert(room_id.clone(), state_events); changes.add_stripped_room(room_info); - let room = InvitedRoom { - invite_state: state, - }; - - new_rooms.invite.insert(room_id, room); + new_rooms.invite.insert(room_id, new_info); } - let presence: BTreeMap = presence + changes.presence = presence .events - .into_iter() + .iter() .filter_map(|e| { let event = e.deserialize().ok()?; - Some((event.sender.clone(), event)) + Some((event.sender, e.clone())) }) .collect(); - changes.presence = presence; - changes.ambiguity_maps = ambiguity_cache.cache; self.store.save_changes(&changes).await?; @@ -965,12 +922,8 @@ impl BaseClient { let response = SyncResponse { next_batch, rooms: new_rooms, - presence: Presence { - events: changes.presence.into_iter().map(|(_, v)| v).collect(), - }, - account_data: AccountData { - events: changes.account_data.into_iter().map(|(_, e)| e).collect(), - }, + presence, + account_data, to_device, device_lists, device_one_time_keys_count: device_one_time_keys_count @@ -1395,14 +1348,17 @@ impl BaseClient { /// Gets the push rules from `changes` if they have been updated, otherwise get them from the /// store. As a fallback, uses `Ruleset::server_default` if the user is logged in. pub async fn get_push_rules(&self, changes: &StateChanges) -> Result { - if let Some(AnyBasicEvent::PushRules(event)) = - changes.account_data.get(&EventType::PushRules.to_string()) + if let Some(AnyBasicEvent::PushRules(event)) = changes + .account_data + .get(EventType::PushRules.as_str()) + .and_then(|e| e.deserialize().ok()) { - Ok(event.content.global.clone()) + Ok(event.content.global) } else if let Some(AnyBasicEvent::PushRules(event)) = self .store .get_account_data_event(EventType::PushRules) .await? + .and_then(|e| e.deserialize().ok()) { Ok(event.content.global) } else if let Some(session) = self.get_session().await { @@ -1451,12 +1407,14 @@ impl BaseClient { .get(room_id) .and_then(|types| types.get(EventType::RoomPowerLevels.as_str())) .and_then(|events| events.get("")) + .and_then(|e| e.deserialize().ok()) { - event.content.clone() + event.content } else if let Some(AnySyncStateEvent::RoomPowerLevels(event)) = self .store .get_state_event(room_id, EventType::RoomPowerLevels, "") .await? + .and_then(|e| e.deserialize().ok()) { event.content } else { @@ -1504,8 +1462,9 @@ impl BaseClient { .get(room_id) .and_then(|types| types.get(EventType::RoomPowerLevels.as_str())) .and_then(|events| events.get("")) + .and_then(|e| e.deserialize().ok()) { - let room_power_levels = event.content.clone(); + let room_power_levels = event.content; push_rules.users_power_levels = room_power_levels.users; push_rules.default_power_level = room_power_levels.users_default; diff --git a/matrix_sdk_base/src/rooms/normal.rs b/matrix_sdk_base/src/rooms/normal.rs index 82e9429e..d9dc8862 100644 --- a/matrix_sdk_base/src/rooms/normal.rs +++ b/matrix_sdk_base/src/rooms/normal.rs @@ -393,7 +393,11 @@ impl Room { return Ok(None); }; - let presence = self.store.get_presence_event(user_id).await?; + let presence = self + .store + .get_presence_event(user_id) + .await? + .and_then(|e| e.deserialize().ok()); let profile = self.store.get_profile(self.room_id(), user_id).await?; let max_power_level = self.max_power_level(); let is_room_creator = self @@ -410,6 +414,7 @@ impl Room { .store .get_state_event(self.room_id(), EventType::RoomPowerLevels, "") .await? + .and_then(|e| e.deserialize().ok()) .and_then(|e| { if let AnySyncStateEvent::RoomPowerLevels(e) = e { Some(e) diff --git a/matrix_sdk_base/src/store/memory_store.rs b/matrix_sdk_base/src/store/memory_store.rs index 33ffd1a5..b8182cc1 100644 --- a/matrix_sdk_base/src/store/memory_store.rs +++ b/matrix_sdk_base/src/store/memory_store.rs @@ -23,10 +23,11 @@ use matrix_sdk_common::{ events::{ presence::PresenceEvent, room::member::{MemberEventContent, MembershipState}, - AnyBasicEvent, AnyStrippedStateEvent, AnySyncStateEvent, EventContent, EventType, + AnyBasicEvent, AnyStrippedStateEvent, AnySyncStateEvent, EventType, }, identifiers::{RoomId, UserId}, instant::Instant, + Raw, }; use tracing::info; @@ -39,7 +40,7 @@ use super::{Result, RoomInfo, StateChanges, StateStore}; pub struct MemoryStore { sync_token: Arc>>, filters: Arc>, - account_data: Arc>, + account_data: Arc>>, members: Arc>>, profiles: Arc>>, display_names: Arc>>>, @@ -47,14 +48,14 @@ pub struct MemoryStore { invited_user_ids: Arc>>, room_info: Arc>, #[allow(clippy::type_complexity)] - room_state: Arc>>>, - room_account_data: Arc>>, + room_state: Arc>>>>, + room_account_data: Arc>>>, stripped_room_info: Arc>, #[allow(clippy::type_complexity)] stripped_room_state: - Arc>>>, + Arc>>>>, stripped_members: Arc>>, - presence: Arc>, + presence: Arc>>, } impl MemoryStore { @@ -176,14 +177,14 @@ impl MemoryStore { } for (room, event_types) in &changes.state { - for events in event_types.values() { - for event in events.values() { + for (event_type, events) in event_types { + for (state_key, event) in events { self.room_state .entry(room.clone()) .or_insert_with(DashMap::new) - .entry(event.content().event_type().to_string()) + .entry(event_type.to_owned()) .or_insert_with(DashMap::new) - .insert(event.state_key().to_string(), event.clone()); + .insert(state_key.to_owned(), event.clone()); } } } @@ -211,14 +212,14 @@ impl MemoryStore { } for (room, event_types) in &changes.stripped_state { - for events in event_types.values() { - for event in events.values() { + for (event_type, events) in event_types { + for (state_key, event) in events { self.stripped_room_state .entry(room.clone()) .or_insert_with(DashMap::new) - .entry(event.content().event_type().to_string()) + .entry(event_type.to_owned()) .or_insert_with(DashMap::new) - .insert(event.state_key().to_string(), event.clone()); + .insert(state_key.to_owned(), event.clone()); } } } @@ -228,7 +229,7 @@ impl MemoryStore { Ok(()) } - async fn get_presence_event(&self, user_id: &UserId) -> Result> { + async fn get_presence_event(&self, user_id: &UserId) -> Result>> { #[allow(clippy::map_clone)] Ok(self.presence.get(user_id).map(|p| p.clone())) } @@ -238,7 +239,7 @@ impl MemoryStore { room_id: &RoomId, event_type: EventType, state_key: &str, - ) -> Result> { + ) -> Result>> { #[allow(clippy::map_clone)] Ok(self.room_state.get(room_id).and_then(|e| { e.get(event_type.as_ref()) @@ -304,7 +305,10 @@ impl MemoryStore { self.stripped_room_info.iter().map(|r| r.clone()).collect() } - async fn get_account_data_event(&self, event_type: EventType) -> Result> { + async fn get_account_data_event( + &self, + event_type: EventType, + ) -> Result>> { Ok(self .account_data .get(event_type.as_ref()) @@ -331,7 +335,7 @@ impl StateStore for MemoryStore { self.get_sync_token().await } - async fn get_presence_event(&self, user_id: &UserId) -> Result> { + async fn get_presence_event(&self, user_id: &UserId) -> Result>> { self.get_presence_event(user_id).await } @@ -340,7 +344,7 @@ impl StateStore for MemoryStore { room_id: &RoomId, event_type: EventType, state_key: &str, - ) -> Result> { + ) -> Result>> { self.get_state_event(room_id, event_type, state_key).await } @@ -393,7 +397,10 @@ impl StateStore for MemoryStore { .unwrap_or_default()) } - async fn get_account_data_event(&self, event_type: EventType) -> Result> { + async fn get_account_data_event( + &self, + event_type: EventType, + ) -> Result>> { self.get_account_data_event(event_type).await } } diff --git a/matrix_sdk_base/src/store/mod.rs b/matrix_sdk_base/src/store/mod.rs index d9e33336..2e017d22 100644 --- a/matrix_sdk_base/src/store/mod.rs +++ b/matrix_sdk_base/src/store/mod.rs @@ -31,7 +31,7 @@ use matrix_sdk_common::{ }, identifiers::{RoomId, UserId}, locks::RwLock, - AsyncTraitDeps, + AsyncTraitDeps, Raw, }; #[cfg(feature = "sled_state_store")] use sled::Db; @@ -114,7 +114,7 @@ pub trait StateStore: AsyncTraitDeps { /// /// * `user_id` - The id of the user for which we wish to fetch the presence /// event for. - async fn get_presence_event(&self, user_id: &UserId) -> Result>; + async fn get_presence_event(&self, user_id: &UserId) -> Result>>; /// Get a state event out of the state store. /// @@ -128,7 +128,7 @@ pub trait StateStore: AsyncTraitDeps { room_id: &RoomId, event_type: EventType, state_key: &str, - ) -> Result>; + ) -> Result>>; /// Get the current profile for the given user in the given room. /// @@ -192,7 +192,10 @@ pub trait StateStore: AsyncTraitDeps { /// # Arguments /// /// * `event_type` - The event type of the account data event. - async fn get_account_data_event(&self, event_type: EventType) -> Result>; + async fn get_account_data_event( + &self, + event_type: EventType, + ) -> Result>>; } /// A state store wrapper for the SDK. @@ -345,30 +348,33 @@ pub struct StateChanges { /// A user session, containing an access token and information about the associated user account. pub session: Option, /// A mapping of event type string to `AnyBasicEvent`. - pub account_data: BTreeMap, + pub account_data: BTreeMap>, /// A mapping of `UserId` to `PresenceEvent`. - pub presence: BTreeMap, + pub presence: BTreeMap>, /// A mapping of `RoomId` to a map of users and their `MemberEvent`. pub members: BTreeMap>, /// A mapping of `RoomId` to a map of users and their `MemberEventContent`. pub profiles: BTreeMap>, - pub(crate) ambiguity_maps: BTreeMap>>, /// A mapping of `RoomId` to a map of event type string to a state key and `AnySyncStateEvent`. - pub state: BTreeMap>>, + pub state: BTreeMap>>>, /// A mapping of `RoomId` to a map of event type string to `AnyBasicEvent`. - pub room_account_data: BTreeMap>, + pub room_account_data: BTreeMap>>, /// A map of `RoomId` to `RoomInfo`. pub room_infos: BTreeMap, /// A mapping of `RoomId` to a map of event type to a map of state key to `AnyStrippedStateEvent`. - pub stripped_state: BTreeMap>>, + pub stripped_state: + BTreeMap>>>, /// A mapping of `RoomId` to a map of users and their `StrippedMemberEvent`. pub stripped_members: BTreeMap>, /// A map of `RoomId` to `RoomInfo`. pub invited_room_info: BTreeMap, + /// A map from room id to a map of a display name and a set of user ids that + /// share that display name in the given room. + pub ambiguity_maps: BTreeMap>>, /// A map of `RoomId` to a vector of `Notification`s pub notifications: BTreeMap>, } @@ -383,8 +389,8 @@ impl StateChanges { } /// Update the `StateChanges` struct with the given `PresenceEvent`. - pub fn add_presence_event(&mut self, event: PresenceEvent) { - self.presence.insert(event.sender.clone(), event); + pub fn add_presence_event(&mut self, event: PresenceEvent, raw_event: Raw) { + self.presence.insert(event.sender, raw_event); } /// Update the `StateChanges` struct with the given `RoomInfo`. @@ -400,27 +406,22 @@ impl StateChanges { } /// Update the `StateChanges` struct with the given `AnyBasicEvent`. - pub fn add_account_data(&mut self, event: AnyBasicEvent) { + pub fn add_account_data(&mut self, event: AnyBasicEvent, raw_event: Raw) { self.account_data - .insert(event.content().event_type().to_owned(), event); + .insert(event.content().event_type().to_owned(), raw_event); } /// Update the `StateChanges` struct with the given room with a new `AnyBasicEvent`. - pub fn add_room_account_data(&mut self, room_id: &RoomId, event: AnyBasicEvent) { + pub fn add_room_account_data( + &mut self, + room_id: &RoomId, + event: AnyBasicEvent, + raw_event: Raw, + ) { self.room_account_data .entry(room_id.to_owned()) .or_insert_with(BTreeMap::new) - .insert(event.content().event_type().to_owned(), event); - } - - /// Update the `StateChanges` struct with the given room with a new `AnyStrippedStateEvent`. - pub fn add_stripped_state_event(&mut self, room_id: &RoomId, event: AnyStrippedStateEvent) { - self.stripped_state - .entry(room_id.to_owned()) - .or_insert_with(BTreeMap::new) - .entry(event.content().event_type().to_string()) - .or_insert_with(BTreeMap::new) - .insert(event.state_key().to_string(), event); + .insert(event.content().event_type().to_owned(), raw_event); } /// Update the `StateChanges` struct with the given room with a new `StrippedMemberEvent`. @@ -434,13 +435,18 @@ impl StateChanges { } /// Update the `StateChanges` struct with the given room with a new `AnySyncStateEvent`. - pub fn add_state_event(&mut self, room_id: &RoomId, event: AnySyncStateEvent) { + pub fn add_state_event( + &mut self, + room_id: &RoomId, + event: AnySyncStateEvent, + raw_event: Raw, + ) { self.state .entry(room_id.to_owned()) .or_insert_with(BTreeMap::new) .entry(event.content().event_type().to_string()) .or_insert_with(BTreeMap::new) - .insert(event.state_key().to_string(), event); + .insert(event.state_key().to_string(), raw_event); } /// Update the `StateChanges` struct with the given room with a new `Notification`. diff --git a/matrix_sdk_base/src/store/sled_store/mod.rs b/matrix_sdk_base/src/store/sled_store/mod.rs index ac815683..e14c0a0b 100644 --- a/matrix_sdk_base/src/store/sled_store/mod.rs +++ b/matrix_sdk_base/src/store/sled_store/mod.rs @@ -31,9 +31,10 @@ use matrix_sdk_common::{ events::{ presence::PresenceEvent, room::member::{MemberEventContent, MembershipState}, - AnyBasicEvent, AnySyncStateEvent, EventContent, EventType, + AnyBasicEvent, AnySyncStateEvent, EventType, }, identifiers::{RoomId, UserId}, + Raw, }; use serde::{Deserialize, Serialize}; @@ -405,14 +406,10 @@ impl SledStore { } for (room, event_types) in &changes.state { - for events in event_types.values() { - for event in events.values() { + for (event_type, events) in event_types { + for (state_key, event) in events { state.insert( - ( - room.as_str(), - event.content().event_type(), - event.state_key(), - ) + (room.as_str(), event_type.as_str(), state_key.as_str()) .encode(), self.serialize_event(&event) .map_err(ConflictableTransactionError::Abort)?, @@ -456,14 +453,10 @@ impl SledStore { } for (room, event_types) in &changes.stripped_state { - for events in event_types.values() { - for event in events.values() { + for (event_type, events) in event_types { + for (state_key, event) in events { stripped_state.insert( - ( - room.as_str(), - event.content().event_type(), - event.state_key(), - ) + (room.as_str(), event_type.as_str(), state_key.as_str()) .encode(), self.serialize_event(&event) .map_err(ConflictableTransactionError::Abort)?, @@ -485,7 +478,7 @@ impl SledStore { Ok(()) } - pub async fn get_presence_event(&self, user_id: &UserId) -> Result> { + pub async fn get_presence_event(&self, user_id: &UserId) -> Result>> { Ok(self .presence .get(user_id.encode())? @@ -498,7 +491,7 @@ impl SledStore { room_id: &RoomId, event_type: EventType, state_key: &str, - ) -> Result> { + ) -> Result>> { Ok(self .room_state .get((room_id.as_str(), event_type.as_str(), state_key).encode())? @@ -597,7 +590,7 @@ impl SledStore { pub async fn get_account_data_event( &self, event_type: EventType, - ) -> Result> { + ) -> Result>> { Ok(self .account_data .get(event_type.encode())? @@ -624,7 +617,7 @@ impl StateStore for SledStore { self.get_sync_token().await } - async fn get_presence_event(&self, user_id: &UserId) -> Result> { + async fn get_presence_event(&self, user_id: &UserId) -> Result>> { self.get_presence_event(user_id).await } @@ -633,7 +626,7 @@ impl StateStore for SledStore { room_id: &RoomId, event_type: EventType, state_key: &str, - ) -> Result> { + ) -> Result>> { self.get_state_event(room_id, event_type, state_key).await } @@ -682,7 +675,10 @@ impl StateStore for SledStore { .await } - async fn get_account_data_event(&self, event_type: EventType) -> Result> { + async fn get_account_data_event( + &self, + event_type: EventType, + ) -> Result>> { self.get_account_data_event(event_type).await } } @@ -693,12 +689,17 @@ mod test { use matrix_sdk_common::{ events::{ - room::member::{MemberEventContent, MembershipState}, - Unsigned, + room::{ + member::{MemberEventContent, MembershipState}, + power_levels::PowerLevelsEventContent, + }, + AnySyncStateEvent, EventType, Unsigned, }, identifiers::{room_id, user_id, EventId, UserId}, + Raw, }; use matrix_sdk_test::async_test; + use serde_json::json; use super::{SledStore, StateChanges}; use crate::deserialized_responses::MemberEvent; @@ -707,6 +708,22 @@ mod test { user_id!("@example:localhost") } + fn power_level_event() -> Raw { + let content = PowerLevelsEventContent::default(); + + let event = json!({ + "event_id": EventId::try_from("$h29iv0s8:example.com").unwrap(), + "content": content, + "sender": user_id(), + "type": "m.room.power_levels", + "origin_server_ts": 0u64, + "state_key": "", + "unsigned": Unsigned::default(), + }); + + serde_json::from_value(event).unwrap() + } + fn membership_event() -> MemberEvent { let content = MemberEventContent { avatar_url: None, @@ -752,4 +769,28 @@ mod test { .unwrap() .is_some()); } + + #[async_test] + async fn test_power_level_saving() { + let store = SledStore::open().unwrap(); + let room_id = room_id!("!test:localhost"); + + let raw_event = power_level_event(); + let event = raw_event.deserialize().unwrap(); + + assert!(store + .get_state_event(&room_id, EventType::RoomPowerLevels, "") + .await + .unwrap() + .is_none()); + let mut changes = StateChanges::default(); + changes.add_state_event(&room_id, event, raw_event); + + store.save_changes(&changes).await.unwrap(); + assert!(store + .get_state_event(&room_id, EventType::RoomPowerLevels, "") + .await + .unwrap() + .is_some()); + } } diff --git a/matrix_sdk_common/src/deserialized_responses.rs b/matrix_sdk_common/src/deserialized_responses.rs index 45a50380..052717b0 100644 --- a/matrix_sdk_common/src/deserialized_responses.rs +++ b/matrix_sdk_common/src/deserialized_responses.rs @@ -1,3 +1,10 @@ +use ruma::{ + api::client::r0::sync::sync_events::{ + AccountData, Ephemeral, InvitedRoom, Presence, State, ToDevice, + }, + serde::Raw, + DeviceIdBox, +}; use serde::{Deserialize, Serialize}; use std::{collections::BTreeMap, convert::TryFrom, time::SystemTime}; @@ -9,9 +16,8 @@ use super::{ }, }, events::{ - presence::PresenceEvent, room::member::MemberEventContent, AnyBasicEvent, - AnyStrippedStateEvent, AnySyncEphemeralRoomEvent, AnySyncRoomEvent, AnySyncStateEvent, - AnyToDeviceEvent, StateEvent, StrippedStateEvent, SyncStateEvent, Unsigned, + room::member::MemberEventContent, AnySyncRoomEvent, StateEvent, StrippedStateEvent, + SyncStateEvent, Unsigned, }, identifiers::{DeviceKeyAlgorithm, EventId, RoomId, UserId}, }; @@ -37,6 +43,72 @@ pub struct AmbiguityChanges { pub changes: BTreeMap>, } +/// The verification state of the device that sent an event to us. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum VerificationState { + /// The device is trusted. + Trusted, + /// The device is not trusted. + Untrusted, + /// The device is not known to us. + UnknownDevice, +} + +/// The algorithm specific information of a decrypted event. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum AlgorithmInfo { + /// The info if the event was encrypted using m.megolm.v1.aes-sha2 + MegolmV1AesSha2 { + /// The curve25519 key of the device that created the megolm decryption + /// key originally. + curve25519_key: String, + /// The signing keys that have created the megolm key that was used to + /// decrypt this session. This map will usually contain a signle ed25519 + /// key. + sender_claimed_keys: BTreeMap, + /// Chain of curve25519 keys through which this session was forwarded, + /// via m.forwarded_room_key events. + forwarding_curve25519_key_chain: Vec, + }, +} + +/// Struct containing information on how an event was decrypted. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct EncryptionInfo { + /// The user ID of the event sender, note this is untrusted data unless the + /// `verification_state` is as well trusted. + pub sender: UserId, + /// The device ID of the device that sent us the event, note this is + /// untrusted data unless `verification_state` is as well trusted. + pub sender_device: DeviceIdBox, + /// Information about the algorithm that was used to encrypt the event. + pub algorithm_info: AlgorithmInfo, + /// The verification state of the device that sent us the event, note this + /// is the state of the device at the time of decryption. It may change in + /// the future if a device gets verified or deleted. + pub verification_state: VerificationState, +} + +/// A customized version of a room event coming from a sync that holds optional +/// encryption info. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct SyncRoomEvent { + /// The actual event. + pub event: Raw, + /// The encryption info about the event. Will be `None` if the event was not + /// encrypted. + pub encryption_info: Option, +} + +impl From> for SyncRoomEvent { + fn from(inner: Raw) -> Self { + Self { + encryption_info: None, + event: inner, + } + } +} + #[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct SyncResponse { /// The batch token to supply in the `since` param of the next `/sync` request. @@ -71,33 +143,6 @@ impl SyncResponse { } } -/// Updates to the presence status of other users. -#[derive(Clone, Debug, Default, Deserialize, Serialize)] -pub struct Presence { - /// A list of events. - pub events: Vec, -} - -/// Data that the user has attached to either the account or a specific room. -#[derive(Clone, Debug, Default, Deserialize, Serialize)] -pub struct AccountData { - /// The list of account data events. - pub events: Vec, -} - -/// Messages sent dirrectly between devices. -#[derive(Clone, Debug, Default, Deserialize, Serialize)] -pub struct ToDevice { - /// A list of events. - pub events: Vec, -} - -impl From> for ToDevice { - fn from(events: Vec) -> Self { - Self { events } - } -} - #[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct Rooms { /// The rooms that the user has left or been banned from. @@ -144,20 +189,6 @@ impl JoinedRoom { } } -/// Updates to the rooms that the user has been invited to. -#[derive(Clone, Debug, Default, Deserialize, Serialize)] -pub struct InvitedRoom { - /// The state of a room that the user has been invited to. - pub invite_state: InviteState, -} - -/// The state of a room that the user has been invited to. -#[derive(Clone, Debug, Default, Deserialize, Serialize)] -pub struct InviteState { - /// A list of state events. - pub events: Vec, -} - /// Counts of unread notifications for a room. #[derive(Copy, Clone, Debug, Default, Deserialize, Serialize)] pub struct UnreadNotificationsCount { @@ -179,13 +210,6 @@ impl From for UnreadNotificationsCount { } } -/// The ephemeral events in the room that aren't recorded in the timeline or -/// state of the room. e.g. typing. -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct Ephemeral { - pub events: Vec, -} - #[derive(Clone, Debug, Deserialize, Serialize)] pub struct LeftRoom { /// The timeline of messages and state changes in the room up to the point @@ -220,7 +244,7 @@ pub struct Timeline { pub prev_batch: Option, /// A list of events. - pub events: Vec, + pub events: Vec, } impl Timeline { @@ -233,13 +257,6 @@ impl Timeline { } } -/// State events in the room. -#[derive(Clone, Debug, Default, Deserialize, Serialize)] -pub struct State { - /// A list of state events. - pub events: Vec, -} - #[derive(Clone, Debug, Deserialize, Serialize)] #[serde( try_from = "SyncStateEvent", diff --git a/matrix_sdk_crypto/src/machine.rs b/matrix_sdk_crypto/src/machine.rs index 447d7a12..a144a3cd 100644 --- a/matrix_sdk_crypto/src/machine.rs +++ b/matrix_sdk_crypto/src/machine.rs @@ -27,14 +27,13 @@ use matrix_sdk_common::{ upload_keys, upload_signatures::Request as UploadSignaturesRequest, }, - sync::sync_events::{DeviceLists, ToDevice as RumaToDevice}, + sync::sync_events::{DeviceLists, ToDevice}, }, assign, - deserialized_responses::ToDevice, + deserialized_responses::{AlgorithmInfo, EncryptionInfo, SyncRoomEvent, VerificationState}, events::{ room::encrypted::EncryptedEventContent, room_key::RoomKeyEventContent, - AnyMessageEventContent, AnySyncRoomEvent, AnyToDeviceEvent, SyncMessageEvent, - ToDeviceEvent, + AnyMessageEventContent, AnyToDeviceEvent, SyncMessageEvent, ToDeviceEvent, }, identifiers::{ DeviceId, DeviceIdBox, DeviceKeyAlgorithm, EventEncryptionAlgorithm, EventId, RoomId, @@ -42,7 +41,7 @@ use matrix_sdk_common::{ }, locks::Mutex, uuid::Uuid, - Raw, UInt, + UInt, }; #[cfg(feature = "sled_cryptostore")] @@ -802,7 +801,7 @@ impl OlmMachine { /// [`decrypt_room_event`]: #method.decrypt_room_event pub async fn receive_sync_changes( &self, - to_device_events: &RumaToDevice, + to_device_events: ToDevice, changed_devices: &DeviceLists, one_time_keys_counts: &BTreeMap, ) -> OlmResult { @@ -826,14 +825,14 @@ impl OlmMachine { let mut events = Vec::new(); - for event_result in &to_device_events.events { - let mut event = match event_result.deserialize() { + for mut raw_event in to_device_events.events { + let event = match raw_event.deserialize() { Ok(e) => e, Err(e) => { // Skip invalid events. warn!( "Received an invalid to-device event {:?} {:?}", - e, event_result + e, raw_event ); continue; } @@ -841,9 +840,9 @@ impl OlmMachine { info!("Received a to-device event {:?}", event); - match &mut event { + match event { AnyToDeviceEvent::RoomEncrypted(e) => { - let decrypted = match self.decrypt_to_device_event(e).await { + let decrypted = match self.decrypt_to_device_event(&e).await { Ok(e) => e, Err(err) => { warn!( @@ -885,12 +884,10 @@ impl OlmMachine { changes.inbound_group_sessions.push(group_session); } - if let Some(e) = decrypted.deserialized_event { - event = e; - } + raw_event = decrypted.event; } AnyToDeviceEvent::RoomKeyRequest(e) => { - self.key_request_machine.receive_incoming_key_request(e) + self.key_request_machine.receive_incoming_key_request(&e) } AnyToDeviceEvent::KeyVerificationAccept(..) | AnyToDeviceEvent::KeyVerificationCancel(..) @@ -903,7 +900,7 @@ impl OlmMachine { _ => continue, } - events.push(event); + events.push(raw_event); } let changed_sessions = self @@ -915,7 +912,10 @@ impl OlmMachine { self.store.save_changes(changes).await?; - Ok(ToDevice { events }) + let mut to_device = ToDevice::new(); + to_device.events = events; + + Ok(to_device) } /// Request a room key from our devices. @@ -950,6 +950,44 @@ impl OlmMachine { .await?) } + async fn get_encryption_info( + &self, + session: &InboundGroupSession, + sender: &UserId, + device_id: &DeviceId, + ) -> StoreResult { + let verification_state = if let Some(device) = + self.get_device(sender, device_id).await?.filter(|d| { + d.get_key(DeviceKeyAlgorithm::Curve25519) + .map(|k| k == session.sender_key()) + .unwrap_or(false) + }) { + if (self.user_id() == device.user_id() && self.device_id() == device.device_id()) + || device.is_trusted() + { + VerificationState::Trusted + } else { + VerificationState::Untrusted + } + } else { + VerificationState::UnknownDevice + }; + + let sender = sender.clone(); + let device_id = device_id.to_owned(); + + Ok(EncryptionInfo { + sender, + sender_device: device_id, + algorithm_info: AlgorithmInfo::MegolmV1AesSha2 { + curve25519_key: session.sender_key().to_owned(), + sender_claimed_keys: session.signing_keys().to_owned(), + forwarding_curve25519_key_chain: session.forwading_key_chain().to_vec(), + }, + verification_state, + }) + } + /// Decrypt an event from a room timeline. /// /// # Arguments @@ -961,7 +999,7 @@ impl OlmMachine { &self, event: &SyncMessageEvent, room_id: &RoomId, - ) -> MegolmResult> { + ) -> MegolmResult { let content = match &event.content { EncryptedEventContent::MegolmV1AesSha2(c) => c, _ => return Err(EventError::UnsupportedAlgorithm.into()), @@ -989,8 +1027,6 @@ impl OlmMachine { "Successfully decrypted a Megolm event {:?}", decrypted_event ); - // TODO set the encryption info on the event (is it verified, was it - // decrypted, sender key...) if let Ok(e) = decrypted_event.deserialize() { self.verification_machine @@ -998,7 +1034,14 @@ impl OlmMachine { .await?; } - Ok(decrypted_event) + let encryption_info = self + .get_encryption_info(&session, &event.sender, &content.device_id) + .await?; + + Ok(SyncRoomEvent { + encryption_info: Some(encryption_info), + event: decrypted_event, + }) } /// Update the tracked users. @@ -1815,23 +1858,24 @@ pub(crate) mod test { .decrypt_room_event(&event, &room_id) .await .unwrap() + .event .deserialize() .unwrap(); - match decrypted_event { - AnySyncRoomEvent::Message(AnySyncMessageEvent::RoomMessage(SyncMessageEvent { - sender, - content, - .. - })) => { - assert_eq!(&sender, alice.user_id()); - if let MessageType::Text(c) = &content.msgtype { - assert_eq!(&c.body, plaintext); - } else { - panic!("Decrypted event has a missmatched content"); - } + if let AnySyncRoomEvent::Message(AnySyncMessageEvent::RoomMessage(SyncMessageEvent { + sender, + content, + .. + })) = decrypted_event + { + assert_eq!(&sender, alice.user_id()); + if let MessageType::Text(c) = &content.msgtype { + assert_eq!(&c.body, plaintext); + } else { + panic!("Decrypted event has a mismatched content"); } - _ => panic!("Decrypted room event has the wrong type"), + } else { + panic!("Decrypted room event has the wrong type") } } diff --git a/matrix_sdk_crypto/src/olm/group_sessions/inbound.rs b/matrix_sdk_crypto/src/olm/group_sessions/inbound.rs index db373133..a23e4ef5 100644 --- a/matrix_sdk_crypto/src/olm/group_sessions/inbound.rs +++ b/matrix_sdk_crypto/src/olm/group_sessions/inbound.rs @@ -61,9 +61,9 @@ pub struct InboundGroupSession { session_id: Arc, first_known_index: u32, pub(crate) sender_key: Arc, - pub(crate) signing_key: Arc>, + pub(crate) signing_keys: Arc>, pub(crate) room_id: Arc, - forwarding_chains: Arc>>>, + forwarding_chains: Arc>, imported: Arc, } @@ -104,10 +104,10 @@ impl InboundGroupSession { history_visibility: history_visibility.into(), sender_key: sender_key.to_owned().into(), first_known_index, - signing_key: Arc::new(keys), - room_id: Arc::new(room_id.clone()), - forwarding_chains: Arc::new(Mutex::new(None)), - imported: Arc::new(false), + signing_keys: keys.into(), + room_id: room_id.clone().into(), + forwarding_chains: Vec::new().into(), + imported: false.into(), }) } @@ -152,15 +152,15 @@ impl InboundGroupSession { ); Ok(InboundGroupSession { - inner: Arc::new(Mutex::new(session)), + inner: Mutex::new(session).into(), session_id: content.session_id.as_str().into(), sender_key: content.sender_key.as_str().into(), first_known_index, history_visibility: None.into(), - signing_key: Arc::new(sender_claimed_key), - room_id: Arc::new(content.room_id.clone()), - forwarding_chains: Arc::new(Mutex::new(Some(forwarding_chains))), - imported: Arc::new(true), + signing_keys: sender_claimed_key.into(), + room_id: content.room_id.clone().into(), + forwarding_chains: forwarding_chains.into(), + imported: true.into(), }) } @@ -176,9 +176,9 @@ impl InboundGroupSession { PickledInboundGroupSession { pickle: InboundGroupSessionPickle::from(pickle), sender_key: self.sender_key.to_string(), - signing_key: (&*self.signing_key).clone(), + signing_key: (&*self.signing_keys).clone(), room_id: (&*self.room_id).clone(), - forwarding_chains: self.forwarding_chains.lock().await.clone(), + forwarding_chains: self.forwading_key_chain().to_vec(), imported: *self.imported, history_visibility: self.history_visibility.as_ref().clone(), } @@ -197,6 +197,20 @@ impl InboundGroupSession { &self.sender_key } + /// Get the map of signing keys this session was received from. + pub fn signing_keys(&self) -> &BTreeMap { + &self.signing_keys + } + + /// Get the list of ed25519 keys that this session was forwarded through. + /// + /// Each ed25519 key represents a single device. If device A forwards the + /// session to device B and device B to C this list will contain the ed25519 + /// keys of A and B. + pub fn forwading_key_chain(&self) -> &[String] { + &self.forwarding_chains + } + /// Export this session at the given message index. pub async fn export_at_index(&self, message_index: u32) -> ExportedRoomKey { let message_index = std::cmp::max(self.first_known_index(), message_index); @@ -214,14 +228,8 @@ impl InboundGroupSession { room_id: (&*self.room_id).clone(), sender_key: (&*self.sender_key).to_owned(), session_id: self.session_id().to_owned(), - forwarding_curve25519_key_chain: self - .forwarding_chains - .lock() - .await - .as_ref() - .cloned() - .unwrap_or_default(), - sender_claimed_keys: (&*self.signing_key).clone(), + forwarding_curve25519_key_chain: self.forwading_key_chain().to_vec(), + sender_claimed_keys: (&*self.signing_keys).clone(), session_key, } } @@ -246,15 +254,15 @@ impl InboundGroupSession { let session_id = session.session_id(); Ok(InboundGroupSession { - inner: Arc::new(Mutex::new(session)), + inner: Mutex::new(session).into(), session_id: session_id.into(), sender_key: pickle.sender_key.into(), history_visibility: pickle.history_visibility.into(), first_known_index, - signing_key: Arc::new(pickle.signing_key), - room_id: Arc::new(pickle.room_id), - forwarding_chains: Arc::new(Mutex::new(pickle.forwarding_chains)), - imported: Arc::new(pickle.imported), + signing_keys: pickle.signing_key.into(), + room_id: pickle.room_id.into(), + forwarding_chains: pickle.forwarding_chains.into(), + imported: pickle.imported.into(), }) } @@ -379,7 +387,8 @@ pub struct PickledInboundGroupSession { pub room_id: RoomId, /// The list of claimed ed25519 that forwarded us this key. Will be None if /// we dirrectly received this session. - pub forwarding_chains: Option>, + #[serde(default)] + pub forwarding_chains: Vec, /// Flag remembering if the session was dirrectly sent to us by the sender /// or if it was imported. pub imported: bool, @@ -411,21 +420,15 @@ impl TryFrom for InboundGroupSession { let session = OlmInboundGroupSession::import(&key.session_key.0)?; let first_known_index = session.first_known_index(); - let forwarding_chains = if key.forwarding_curve25519_key_chain.is_empty() { - None - } else { - Some(key.forwarding_curve25519_key_chain) - }; - Ok(InboundGroupSession { inner: Arc::new(Mutex::new(session)), session_id: key.session_id.into(), sender_key: key.sender_key.into(), history_visibility: None.into(), first_known_index, - signing_key: Arc::new(key.sender_claimed_keys), + signing_keys: Arc::new(key.sender_claimed_keys), room_id: Arc::new(key.room_id), - forwarding_chains: Arc::new(Mutex::new(forwarding_chains)), + forwarding_chains: Arc::new(key.forwarding_curve25519_key_chain), imported: Arc::new(true), }) }