matrix-sdk: Add encryption info to our sync events.

master
Damir Jelić 2021-04-28 11:48:20 +02:00
parent 5ed0c7a7b3
commit cff90b1480
6 changed files with 329 additions and 260 deletions

View File

@ -81,7 +81,12 @@ async fn login(
let client = &client_ref; let client = &client_ref;
let initial = &initial_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 { match event {
AnyToDeviceEvent::KeyVerificationStart(e) => { AnyToDeviceEvent::KeyVerificationStart(e) => {
let sas = client let sas = client
@ -124,7 +129,12 @@ async fn login(
if !initial.load(Ordering::SeqCst) { if !initial.load(Ordering::SeqCst) {
for (_room_id, room_info) in response.rooms.join { 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 { if let AnySyncRoomEvent::Message(event) = event {
match event { match event {
AnySyncMessageEvent::RoomMessage(m) => { AnySyncMessageEvent::RoomMessage(m) => {

View File

@ -75,50 +75,95 @@ impl Handler {
pub(crate) async fn handle_sync(&self, response: &SyncResponse) { pub(crate) async fn handle_sync(&self, response: &SyncResponse) {
for (room_id, room_info) in &response.rooms.join { for (room_id, room_info) in &response.rooms.join {
if let Some(room) = self.get_room(room_id) { if let Some(room) = self.get_room(room_id) {
for event in &room_info.ephemeral.events { for event in room_info
self.handle_ephemeral_event(room.clone(), event).await; .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 { for event in room_info
self.handle_account_data_event(room.clone(), event).await; .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 { for event in room_info
self.handle_state_event(room.clone(), event).await; .state
.events
.iter()
.filter_map(|e| e.deserialize().ok())
{
self.handle_state_event(room.clone(), &event).await;
} }
for event in &room_info.timeline.events { for event in room_info
self.handle_timeline_event(room.clone(), event).await; .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 { for (room_id, room_info) in &response.rooms.leave {
if let Some(room) = self.get_room(room_id) { if let Some(room) = self.get_room(room_id) {
for event in &room_info.account_data.events { for event in room_info
self.handle_account_data_event(room.clone(), event).await; .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 { for event in room_info
self.handle_state_event(room.clone(), event).await; .state
.events
.iter()
.filter_map(|e| e.deserialize().ok())
{
self.handle_state_event(room.clone(), &event).await;
} }
for event in &room_info.timeline.events { for event in room_info
self.handle_timeline_event(room.clone(), event).await; .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 { for (room_id, room_info) in &response.rooms.invite {
if let Some(room) = self.get_room(room_id) { if let Some(room) = self.get_room(room_id) {
for event in &room_info.invite_state.events { for event in room_info
self.handle_stripped_state_event(room.clone(), event).await; .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 { for event in response
self.on_presence_event(event).await; .presence
.events
.iter()
.filter_map(|e| e.deserialize().ok())
{
self.on_presence_event(&event).await;
} }
for (room_id, notifications) in &response.notifications { for (room_id, notifications) in &response.notifications {

View File

@ -37,15 +37,13 @@ use matrix_sdk_common::{
use matrix_sdk_common::{ use matrix_sdk_common::{
api::r0::{self as api, push::get_notifications::Notification}, api::r0::{self as api, push::get_notifications::Notification},
deserialized_responses::{ deserialized_responses::{
AccountData, AmbiguityChanges, Ephemeral, InviteState, InvitedRoom, JoinedRoom, LeftRoom, AmbiguityChanges, JoinedRoom, LeftRoom, MemberEvent, MembersResponse, Rooms,
MemberEvent, MembersResponse, Presence, Rooms, State, StrippedMemberEvent, SyncResponse, StrippedMemberEvent, SyncResponse, SyncRoomEvent, Timeline,
Timeline,
}, },
events::{ events::{
presence::PresenceEvent,
room::member::{MemberEventContent, MembershipState}, room::member::{MemberEventContent, MembershipState},
AnyBasicEvent, AnyStrippedStateEvent, AnySyncRoomEvent, AnySyncStateEvent, AnyBasicEvent, AnyStrippedStateEvent, AnySyncRoomEvent, AnySyncStateEvent, EventContent,
AnyToDeviceEvent, EventContent, EventType, StateEvent, EventType, StateEvent,
}, },
identifiers::{RoomId, UserId}, identifiers::{RoomId, UserId},
instant::Instant, instant::Instant,
@ -432,15 +430,12 @@ impl BaseClient {
let mut push_context = self.get_push_room_context(room, room_info, changes).await?; let mut push_context = self.get_push_room_context(room, room_info, changes).await?;
for event in ruma_timeline.events { for event in ruma_timeline.events {
match hoist_room_event_prev_content(&event) { let mut event: SyncRoomEvent = event.into();
Ok(mut e) => {
#[cfg(not(feature = "encryption"))]
let raw_event = event;
#[cfg(feature = "encryption")]
let mut raw_event = event;
match hoist_room_event_prev_content(&event.event) {
Ok(e) => {
#[allow(clippy::single_match)] #[allow(clippy::single_match)]
match &mut e { match &e {
AnySyncRoomEvent::State(s) => match s { AnySyncRoomEvent::State(s) => match s {
AnySyncStateEvent::RoomMember(member) => { AnySyncStateEvent::RoomMember(member) => {
if let Ok(member) = MemberEvent::try_from(member.clone()) { if let Ok(member) = MemberEvent::try_from(member.clone()) {
@ -487,18 +482,10 @@ impl BaseClient {
encrypted, encrypted,
)) => { )) => {
if let Some(olm) = self.olm_machine().await { 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 olm.decrypt_room_event(encrypted, room_id).await
{ {
match raw_decrypted.deserialize() { event = decrypted;
Ok(decrypted) => {
e = decrypted;
raw_event = raw_decrypted;
}
Err(e) => {
warn!("Error deserializing a decrypted event {:?} ", e)
}
}
} }
} }
} }
@ -517,14 +504,14 @@ impl BaseClient {
} }
if let Some(context) = &push_context { 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)) { if actions.iter().any(|a| matches!(a, Action::Notify)) {
changes.add_notification( changes.add_notification(
room_id, room_id,
Notification::new( Notification::new(
actions, actions,
raw_event, event.event.clone(),
false, false,
room_id.clone(), room_id.clone(),
SystemTime::now(), SystemTime::now(),
@ -537,13 +524,13 @@ impl BaseClient {
// Requires the possibility to associate custom data with events and to // Requires the possibility to associate custom data with events and to
// store them. // store them.
} }
timeline.events.push(e);
} }
Err(e) => { Err(e) => {
warn!("Error deserializing event {:?}", e); warn!("Error deserializing event {:?}", e);
} }
} }
timeline.events.push(event);
} }
Ok(timeline) Ok(timeline)
@ -552,19 +539,17 @@ impl BaseClient {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
fn handle_invited_state( fn handle_invited_state(
&self, &self,
events: Vec<Raw<AnyStrippedStateEvent>>, events: &[Raw<AnyStrippedStateEvent>],
room_info: &mut RoomInfo, room_info: &mut RoomInfo,
) -> ( ) -> (
InviteState,
BTreeMap<UserId, StrippedMemberEvent>, BTreeMap<UserId, StrippedMemberEvent>,
BTreeMap<String, BTreeMap<String, AnyStrippedStateEvent>>, BTreeMap<String, BTreeMap<String, AnyStrippedStateEvent>>,
) { ) {
events.into_iter().fold( events.iter().fold(
(InviteState::default(), BTreeMap::new(), BTreeMap::new()), (BTreeMap::new(), BTreeMap::new()),
|(mut state, mut members, mut state_events), e| { |(mut members, mut state_events), e| {
match e.deserialize() { match e.deserialize() {
Ok(e) => { Ok(e) => {
state.events.push(e.clone());
if let AnyStrippedStateEvent::RoomMember(member) = e { if let AnyStrippedStateEvent::RoomMember(member) = e {
match StrippedMemberEvent::try_from(member) { match StrippedMemberEvent::try_from(member) {
@ -591,7 +576,7 @@ impl BaseClient {
); );
} }
} }
(state, members, state_events) (members, state_events)
}, },
) )
} }
@ -600,10 +585,9 @@ impl BaseClient {
&self, &self,
changes: &mut StateChanges, changes: &mut StateChanges,
ambiguity_cache: &mut AmbiguityCache, ambiguity_cache: &mut AmbiguityCache,
events: Vec<Raw<AnySyncStateEvent>>, events: &[Raw<AnySyncStateEvent>],
room_info: &mut RoomInfo, room_info: &mut RoomInfo,
) -> StoreResult<(State, BTreeSet<UserId>)> { ) -> StoreResult<BTreeSet<UserId>> {
let mut state = State::default();
let mut members = BTreeMap::new(); let mut members = BTreeMap::new();
let mut state_events = BTreeMap::new(); let mut state_events = BTreeMap::new();
let mut user_ids = BTreeSet::new(); let mut user_ids = BTreeSet::new();
@ -611,21 +595,19 @@ impl BaseClient {
let room_id = room_info.room_id.clone(); let room_id = room_info.room_id.clone();
for event in for event in events
events .iter()
.into_iter() .filter_map(|e| match hoist_and_deserialize_state_event(&e) {
.filter_map(|e| match hoist_and_deserialize_state_event(&e) { Ok(e) => Some(e),
Ok(e) => Some(e), Err(err) => {
Err(err) => { warn!(
warn!( "Couldn't deserialize state event for room {}: {:?} {:#?}",
"Couldn't deserialize state event for room {}: {:?} {:#?}", room_id, err, e
room_id, err, e );
); None
None }
} })
})
{ {
state.events.push(event.clone());
room_info.handle_state_event(&event.content()); room_info.handle_state_event(&event.content());
if let AnySyncStateEvent::RoomMember(member) = event { if let AnySyncStateEvent::RoomMember(member) = event {
@ -667,7 +649,7 @@ impl BaseClient {
changes.profiles.insert(room_id.as_ref().clone(), profiles); changes.profiles.insert(room_id.as_ref().clone(), profiles);
changes.state.insert(room_id.as_ref().clone(), state_events); changes.state.insert(room_id.as_ref().clone(), state_events);
Ok((state, user_ids)) Ok(user_ids)
} }
async fn handle_room_account_data( async fn handle_room_account_data(
@ -675,22 +657,16 @@ impl BaseClient {
room_id: &RoomId, room_id: &RoomId,
events: &[Raw<AnyBasicEvent>], events: &[Raw<AnyBasicEvent>],
changes: &mut StateChanges, changes: &mut StateChanges,
) -> AccountData { ) {
let events: Vec<AnyBasicEvent> = let events: Vec<AnyBasicEvent> =
events.iter().filter_map(|e| e.deserialize().ok()).collect(); events.iter().filter_map(|e| e.deserialize().ok()).collect();
for event in &events { for event in &events {
changes.add_room_account_data(room_id, event.clone()); changes.add_room_account_data(room_id, event.clone());
} }
AccountData { events }
} }
async fn handle_account_data( async fn handle_account_data(&self, events: &[Raw<AnyBasicEvent>], changes: &mut StateChanges) {
&self,
events: Vec<Raw<AnyBasicEvent>>,
changes: &mut StateChanges,
) {
let events: Vec<AnyBasicEvent> = let events: Vec<AnyBasicEvent> =
events.iter().filter_map(|e| e.deserialize().ok()).collect(); events.iter().filter_map(|e| e.deserialize().ok()).collect();
@ -769,29 +745,17 @@ impl BaseClient {
// decryptes to-device events, but leaves room events alone. // decryptes to-device events, but leaves room events alone.
// This makes sure that we have the deryption keys for the room // This makes sure that we have the deryption keys for the room
// events at hand. // 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? .await?
} else { } else {
to_device to_device
.events
.into_iter()
.filter_map(|e| e.deserialize().ok())
.collect::<Vec<AnyToDeviceEvent>>()
.into()
} }
}; };
#[cfg(not(feature = "encryption"))]
let to_device = to_device
.events
.into_iter()
.filter_map(|e| e.deserialize().ok())
.collect::<Vec<AnyToDeviceEvent>>()
.into();
let mut changes = StateChanges::new(next_batch.clone()); let mut changes = StateChanges::new(next_batch.clone());
let mut ambiguity_cache = AmbiguityCache::new(self.store.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; .await;
let push_rules = self.get_push_rules(&changes).await?; let push_rules = self.get_push_rules(&changes).await?;
@ -809,11 +773,11 @@ impl BaseClient {
room_info.update_summary(&new_info.summary); room_info.update_summary(&new_info.summary);
room_info.set_prev_batch(new_info.timeline.prev_batch.as_deref()); 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( .handle_state(
&mut changes, &mut changes,
&mut ambiguity_cache, &mut ambiguity_cache,
new_info.state.events, &new_info.state.events,
&mut room_info, &mut room_info,
) )
.await?; .await?;
@ -834,8 +798,7 @@ impl BaseClient {
) )
.await?; .await?;
let account_data = self self.handle_room_account_data(&room_id, &new_info.account_data.events, &mut changes)
.handle_room_account_data(&room_id, &new_info.account_data.events, &mut changes)
.await; .await;
#[cfg(feature = "encryption")] #[cfg(feature = "encryption")]
@ -859,18 +822,15 @@ impl BaseClient {
let notification_count = new_info.unread_notifications.into(); let notification_count = new_info.unread_notifications.into();
room_info.update_notification_count(notification_count); 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( new_rooms.join.insert(
room_id, 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); changes.add_room(room_info);
@ -884,11 +844,11 @@ impl BaseClient {
let mut room_info = room.clone_info(); let mut room_info = room.clone_info();
room_info.mark_as_left(); room_info.mark_as_left();
let (state, mut user_ids) = self let mut user_ids = self
.handle_state( .handle_state(
&mut changes, &mut changes,
&mut ambiguity_cache, &mut ambiguity_cache,
new_info.state.events, &new_info.state.events,
&mut room_info, &mut room_info,
) )
.await?; .await?;
@ -905,14 +865,14 @@ impl BaseClient {
) )
.await?; .await?;
let account_data = self self.handle_room_account_data(&room_id, &new_info.account_data.events, &mut changes)
.handle_room_account_data(&room_id, &new_info.account_data.events, &mut changes)
.await; .await;
changes.add_room(room_info); changes.add_room(room_info);
new_rooms new_rooms.leave.insert(
.leave room_id,
.insert(room_id, LeftRoom::new(timeline, state, account_data)); LeftRoom::new(timeline, new_info.state, new_info.account_data),
);
} }
for (room_id, new_info) in rooms.invite { for (room_id, new_info) in rooms.invite {
@ -929,31 +889,25 @@ impl BaseClient {
let room = self.store.get_or_create_stripped_room(&room_id).await; let room = self.store.get_or_create_stripped_room(&room_id).await;
let mut room_info = room.clone_info(); let mut room_info = room.clone_info();
let (state, members, state_events) = let (members, state_events) =
self.handle_invited_state(new_info.invite_state.events, &mut room_info); self.handle_invited_state(&new_info.invite_state.events, &mut room_info);
changes.stripped_members.insert(room_id.clone(), members); changes.stripped_members.insert(room_id.clone(), members);
changes.stripped_state.insert(room_id.clone(), state_events); changes.stripped_state.insert(room_id.clone(), state_events);
changes.add_stripped_room(room_info); changes.add_stripped_room(room_info);
let room = InvitedRoom { new_rooms.invite.insert(room_id, new_info);
invite_state: state,
};
new_rooms.invite.insert(room_id, room);
} }
let presence: BTreeMap<UserId, PresenceEvent> = presence changes.presence = presence
.events .events
.into_iter() .iter()
.filter_map(|e| { .filter_map(|e| {
let event = e.deserialize().ok()?; let event = e.deserialize().ok()?;
Some((event.sender.clone(), event)) Some((event.sender.clone(), event))
}) })
.collect(); .collect();
changes.presence = presence;
changes.ambiguity_maps = ambiguity_cache.cache; changes.ambiguity_maps = ambiguity_cache.cache;
self.store.save_changes(&changes).await?; self.store.save_changes(&changes).await?;
@ -965,12 +919,8 @@ impl BaseClient {
let response = SyncResponse { let response = SyncResponse {
next_batch, next_batch,
rooms: new_rooms, rooms: new_rooms,
presence: Presence { presence,
events: changes.presence.into_iter().map(|(_, v)| v).collect(), account_data,
},
account_data: AccountData {
events: changes.account_data.into_iter().map(|(_, e)| e).collect(),
},
to_device, to_device,
device_lists, device_lists,
device_one_time_keys_count: device_one_time_keys_count device_one_time_keys_count: device_one_time_keys_count

View File

@ -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 serde::{Deserialize, Serialize};
use std::{collections::BTreeMap, convert::TryFrom, time::SystemTime}; use std::{collections::BTreeMap, convert::TryFrom, time::SystemTime};
@ -9,9 +16,8 @@ use super::{
}, },
}, },
events::{ events::{
presence::PresenceEvent, room::member::MemberEventContent, AnyBasicEvent, room::member::MemberEventContent, AnySyncRoomEvent, StateEvent, StrippedStateEvent,
AnyStrippedStateEvent, AnySyncEphemeralRoomEvent, AnySyncRoomEvent, AnySyncStateEvent, SyncStateEvent, Unsigned,
AnyToDeviceEvent, StateEvent, StrippedStateEvent, SyncStateEvent, Unsigned,
}, },
identifiers::{DeviceKeyAlgorithm, EventId, RoomId, UserId}, identifiers::{DeviceKeyAlgorithm, EventId, RoomId, UserId},
}; };
@ -37,6 +43,72 @@ pub struct AmbiguityChanges {
pub changes: BTreeMap<RoomId, BTreeMap<EventId, AmbiguityChange>>, pub changes: BTreeMap<RoomId, BTreeMap<EventId, AmbiguityChange>>,
} }
/// 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<DeviceKeyAlgorithm, String>,
/// Chain of curve25519 keys through which this session was forwarded,
/// via m.forwarded_room_key events.
forwarding_curve25519_key_chain: Vec<String>,
},
}
/// 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 comming from a sync that holds optional
/// decryption info.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SyncRoomEvent {
/// The actual event.
pub event: Raw<AnySyncRoomEvent>,
/// The encryption info about the event. Will be `None` if the event was not
/// encrypted.
pub encryption_info: Option<EncryptionInfo>,
}
impl From<Raw<AnySyncRoomEvent>> for SyncRoomEvent {
fn from(inner: Raw<AnySyncRoomEvent>) -> Self {
Self {
encryption_info: None,
event: inner,
}
}
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct SyncResponse { pub struct SyncResponse {
/// The batch token to supply in the `since` param of the next `/sync` request. /// 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<PresenceEvent>,
}
/// 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<AnyBasicEvent>,
}
/// Messages sent dirrectly between devices.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct ToDevice {
/// A list of events.
pub events: Vec<AnyToDeviceEvent>,
}
impl From<Vec<AnyToDeviceEvent>> for ToDevice {
fn from(events: Vec<AnyToDeviceEvent>) -> Self {
Self { events }
}
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Rooms { pub struct Rooms {
/// The rooms that the user has left or been banned from. /// 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<AnyStrippedStateEvent>,
}
/// Counts of unread notifications for a room. /// Counts of unread notifications for a room.
#[derive(Copy, Clone, Debug, Default, Deserialize, Serialize)] #[derive(Copy, Clone, Debug, Default, Deserialize, Serialize)]
pub struct UnreadNotificationsCount { pub struct UnreadNotificationsCount {
@ -179,13 +210,6 @@ impl From<RumaUnreadNotificationsCount> 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<AnySyncEphemeralRoomEvent>,
}
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct LeftRoom { pub struct LeftRoom {
/// The timeline of messages and state changes in the room up to the point /// 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<String>, pub prev_batch: Option<String>,
/// A list of events. /// A list of events.
pub events: Vec<AnySyncRoomEvent>, pub events: Vec<SyncRoomEvent>,
} }
impl Timeline { 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<AnySyncStateEvent>,
}
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
#[serde( #[serde(
try_from = "SyncStateEvent<MemberEventContent>", try_from = "SyncStateEvent<MemberEventContent>",

View File

@ -27,14 +27,13 @@ use matrix_sdk_common::{
upload_keys, upload_keys,
upload_signatures::Request as UploadSignaturesRequest, upload_signatures::Request as UploadSignaturesRequest,
}, },
sync::sync_events::{DeviceLists, ToDevice as RumaToDevice}, sync::sync_events::{DeviceLists, ToDevice},
}, },
assign, assign,
deserialized_responses::ToDevice, deserialized_responses::{AlgorithmInfo, EncryptionInfo, SyncRoomEvent, VerificationState},
events::{ events::{
room::encrypted::EncryptedEventContent, room_key::RoomKeyEventContent, room::encrypted::EncryptedEventContent, room_key::RoomKeyEventContent,
AnyMessageEventContent, AnySyncRoomEvent, AnyToDeviceEvent, SyncMessageEvent, AnyMessageEventContent, AnyToDeviceEvent, SyncMessageEvent, ToDeviceEvent,
ToDeviceEvent,
}, },
identifiers::{ identifiers::{
DeviceId, DeviceIdBox, DeviceKeyAlgorithm, EventEncryptionAlgorithm, EventId, RoomId, DeviceId, DeviceIdBox, DeviceKeyAlgorithm, EventEncryptionAlgorithm, EventId, RoomId,
@ -42,7 +41,7 @@ use matrix_sdk_common::{
}, },
locks::Mutex, locks::Mutex,
uuid::Uuid, uuid::Uuid,
Raw, UInt, UInt,
}; };
#[cfg(feature = "sled_cryptostore")] #[cfg(feature = "sled_cryptostore")]
@ -802,7 +801,7 @@ impl OlmMachine {
/// [`decrypt_room_event`]: #method.decrypt_room_event /// [`decrypt_room_event`]: #method.decrypt_room_event
pub async fn receive_sync_changes( pub async fn receive_sync_changes(
&self, &self,
to_device_events: &RumaToDevice, to_device_events: ToDevice,
changed_devices: &DeviceLists, changed_devices: &DeviceLists,
one_time_keys_counts: &BTreeMap<DeviceKeyAlgorithm, UInt>, one_time_keys_counts: &BTreeMap<DeviceKeyAlgorithm, UInt>,
) -> OlmResult<ToDevice> { ) -> OlmResult<ToDevice> {
@ -826,14 +825,14 @@ impl OlmMachine {
let mut events = Vec::new(); let mut events = Vec::new();
for event_result in &to_device_events.events { for mut raw_event in to_device_events.events {
let mut event = match event_result.deserialize() { let event = match raw_event.deserialize() {
Ok(e) => e, Ok(e) => e,
Err(e) => { Err(e) => {
// Skip invalid events. // Skip invalid events.
warn!( warn!(
"Received an invalid to-device event {:?} {:?}", "Received an invalid to-device event {:?} {:?}",
e, event_result e, raw_event
); );
continue; continue;
} }
@ -841,9 +840,9 @@ impl OlmMachine {
info!("Received a to-device event {:?}", event); info!("Received a to-device event {:?}", event);
match &mut event { match event {
AnyToDeviceEvent::RoomEncrypted(e) => { 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, Ok(e) => e,
Err(err) => { Err(err) => {
warn!( warn!(
@ -885,12 +884,10 @@ impl OlmMachine {
changes.inbound_group_sessions.push(group_session); changes.inbound_group_sessions.push(group_session);
} }
if let Some(e) = decrypted.deserialized_event { raw_event = decrypted.event;
event = e;
}
} }
AnyToDeviceEvent::RoomKeyRequest(e) => { AnyToDeviceEvent::RoomKeyRequest(e) => {
self.key_request_machine.receive_incoming_key_request(e) self.key_request_machine.receive_incoming_key_request(&e)
} }
AnyToDeviceEvent::KeyVerificationAccept(..) AnyToDeviceEvent::KeyVerificationAccept(..)
| AnyToDeviceEvent::KeyVerificationCancel(..) | AnyToDeviceEvent::KeyVerificationCancel(..)
@ -903,7 +900,7 @@ impl OlmMachine {
_ => continue, _ => continue,
} }
events.push(event); events.push(raw_event);
} }
let changed_sessions = self let changed_sessions = self
@ -915,7 +912,10 @@ impl OlmMachine {
self.store.save_changes(changes).await?; 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. /// Request a room key from our devices.
@ -950,6 +950,44 @@ impl OlmMachine {
.await?) .await?)
} }
async fn get_encryption_info(
&self,
session: &InboundGroupSession,
sender: &UserId,
device_id: &DeviceId,
) -> StoreResult<EncryptionInfo> {
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. /// Decrypt an event from a room timeline.
/// ///
/// # Arguments /// # Arguments
@ -961,7 +999,7 @@ impl OlmMachine {
&self, &self,
event: &SyncMessageEvent<EncryptedEventContent>, event: &SyncMessageEvent<EncryptedEventContent>,
room_id: &RoomId, room_id: &RoomId,
) -> MegolmResult<Raw<AnySyncRoomEvent>> { ) -> MegolmResult<SyncRoomEvent> {
let content = match &event.content { let content = match &event.content {
EncryptedEventContent::MegolmV1AesSha2(c) => c, EncryptedEventContent::MegolmV1AesSha2(c) => c,
_ => return Err(EventError::UnsupportedAlgorithm.into()), _ => return Err(EventError::UnsupportedAlgorithm.into()),
@ -989,8 +1027,6 @@ impl OlmMachine {
"Successfully decrypted a Megolm event {:?}", "Successfully decrypted a Megolm event {:?}",
decrypted_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() { if let Ok(e) = decrypted_event.deserialize() {
self.verification_machine self.verification_machine
@ -998,7 +1034,14 @@ impl OlmMachine {
.await?; .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. /// Update the tracked users.
@ -1815,23 +1858,24 @@ pub(crate) mod test {
.decrypt_room_event(&event, &room_id) .decrypt_room_event(&event, &room_id)
.await .await
.unwrap() .unwrap()
.event
.deserialize() .deserialize()
.unwrap(); .unwrap();
match decrypted_event { if let AnySyncRoomEvent::Message(AnySyncMessageEvent::RoomMessage(SyncMessageEvent {
AnySyncRoomEvent::Message(AnySyncMessageEvent::RoomMessage(SyncMessageEvent { sender,
sender, content,
content, ..
.. })) = decrypted_event
})) => { {
assert_eq!(&sender, alice.user_id()); assert_eq!(&sender, alice.user_id());
if let MessageType::Text(c) = &content.msgtype { if let MessageType::Text(c) = &content.msgtype {
assert_eq!(&c.body, plaintext); assert_eq!(&c.body, plaintext);
} else { } else {
panic!("Decrypted event has a missmatched content"); panic!("Decrypted event has a missmatched content");
}
} }
_ => panic!("Decrypted room event has the wrong type"), } else {
panic!("Decrypted room event has the wrong type")
} }
} }

View File

@ -61,9 +61,9 @@ pub struct InboundGroupSession {
session_id: Arc<str>, session_id: Arc<str>,
first_known_index: u32, first_known_index: u32,
pub(crate) sender_key: Arc<str>, pub(crate) sender_key: Arc<str>,
pub(crate) signing_key: Arc<BTreeMap<DeviceKeyAlgorithm, String>>, pub(crate) signing_keys: Arc<BTreeMap<DeviceKeyAlgorithm, String>>,
pub(crate) room_id: Arc<RoomId>, pub(crate) room_id: Arc<RoomId>,
forwarding_chains: Arc<Mutex<Option<Vec<String>>>>, forwarding_chains: Arc<Vec<String>>,
imported: Arc<bool>, imported: Arc<bool>,
} }
@ -104,10 +104,10 @@ impl InboundGroupSession {
history_visibility: history_visibility.into(), history_visibility: history_visibility.into(),
sender_key: sender_key.to_owned().into(), sender_key: sender_key.to_owned().into(),
first_known_index, first_known_index,
signing_key: Arc::new(keys), signing_keys: keys.into(),
room_id: Arc::new(room_id.clone()), room_id: room_id.clone().into(),
forwarding_chains: Arc::new(Mutex::new(None)), forwarding_chains: Vec::new().into(),
imported: Arc::new(false), imported: false.into(),
}) })
} }
@ -152,15 +152,15 @@ impl InboundGroupSession {
); );
Ok(InboundGroupSession { Ok(InboundGroupSession {
inner: Arc::new(Mutex::new(session)), inner: Mutex::new(session).into(),
session_id: content.session_id.as_str().into(), session_id: content.session_id.as_str().into(),
sender_key: content.sender_key.as_str().into(), sender_key: content.sender_key.as_str().into(),
first_known_index, first_known_index,
history_visibility: None.into(), history_visibility: None.into(),
signing_key: Arc::new(sender_claimed_key), signing_keys: sender_claimed_key.into(),
room_id: Arc::new(content.room_id.clone()), room_id: content.room_id.clone().into(),
forwarding_chains: Arc::new(Mutex::new(Some(forwarding_chains))), forwarding_chains: forwarding_chains.into(),
imported: Arc::new(true), imported: true.into(),
}) })
} }
@ -176,9 +176,9 @@ impl InboundGroupSession {
PickledInboundGroupSession { PickledInboundGroupSession {
pickle: InboundGroupSessionPickle::from(pickle), pickle: InboundGroupSessionPickle::from(pickle),
sender_key: self.sender_key.to_string(), 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(), 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, imported: *self.imported,
history_visibility: self.history_visibility.as_ref().clone(), history_visibility: self.history_visibility.as_ref().clone(),
} }
@ -197,6 +197,20 @@ impl InboundGroupSession {
&self.sender_key &self.sender_key
} }
/// Get the map of signing keys this session was received from.
pub fn signing_keys(&self) -> &BTreeMap<DeviceKeyAlgorithm, String> {
&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. /// Export this session at the given message index.
pub async fn export_at_index(&self, message_index: u32) -> ExportedRoomKey { pub async fn export_at_index(&self, message_index: u32) -> ExportedRoomKey {
let message_index = std::cmp::max(self.first_known_index(), message_index); let message_index = std::cmp::max(self.first_known_index(), message_index);
@ -214,14 +228,8 @@ impl InboundGroupSession {
room_id: (&*self.room_id).clone(), room_id: (&*self.room_id).clone(),
sender_key: (&*self.sender_key).to_owned(), sender_key: (&*self.sender_key).to_owned(),
session_id: self.session_id().to_owned(), session_id: self.session_id().to_owned(),
forwarding_curve25519_key_chain: self forwarding_curve25519_key_chain: self.forwading_key_chain().to_vec(),
.forwarding_chains sender_claimed_keys: (&*self.signing_keys).clone(),
.lock()
.await
.as_ref()
.cloned()
.unwrap_or_default(),
sender_claimed_keys: (&*self.signing_key).clone(),
session_key, session_key,
} }
} }
@ -246,15 +254,15 @@ impl InboundGroupSession {
let session_id = session.session_id(); let session_id = session.session_id();
Ok(InboundGroupSession { Ok(InboundGroupSession {
inner: Arc::new(Mutex::new(session)), inner: Mutex::new(session).into(),
session_id: session_id.into(), session_id: session_id.into(),
sender_key: pickle.sender_key.into(), sender_key: pickle.sender_key.into(),
history_visibility: pickle.history_visibility.into(), history_visibility: pickle.history_visibility.into(),
first_known_index, first_known_index,
signing_key: Arc::new(pickle.signing_key), signing_keys: pickle.signing_key.into(),
room_id: Arc::new(pickle.room_id), room_id: pickle.room_id.into(),
forwarding_chains: Arc::new(Mutex::new(pickle.forwarding_chains)), forwarding_chains: pickle.forwarding_chains.into(),
imported: Arc::new(pickle.imported), imported: pickle.imported.into(),
}) })
} }
@ -379,7 +387,8 @@ pub struct PickledInboundGroupSession {
pub room_id: RoomId, pub room_id: RoomId,
/// The list of claimed ed25519 that forwarded us this key. Will be None if /// The list of claimed ed25519 that forwarded us this key. Will be None if
/// we dirrectly received this session. /// we dirrectly received this session.
pub forwarding_chains: Option<Vec<String>>, #[serde(default)]
pub forwarding_chains: Vec<String>,
/// Flag remembering if the session was dirrectly sent to us by the sender /// Flag remembering if the session was dirrectly sent to us by the sender
/// or if it was imported. /// or if it was imported.
pub imported: bool, pub imported: bool,
@ -411,21 +420,15 @@ impl TryFrom<ExportedRoomKey> for InboundGroupSession {
let session = OlmInboundGroupSession::import(&key.session_key.0)?; let session = OlmInboundGroupSession::import(&key.session_key.0)?;
let first_known_index = session.first_known_index(); 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 { Ok(InboundGroupSession {
inner: Arc::new(Mutex::new(session)), inner: Arc::new(Mutex::new(session)),
session_id: key.session_id.into(), session_id: key.session_id.into(),
sender_key: key.sender_key.into(), sender_key: key.sender_key.into(),
history_visibility: None.into(), history_visibility: None.into(),
first_known_index, 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), 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), imported: Arc::new(true),
}) })
} }