Skip to content

Commit a2235d5

Browse files
zecakehpoljar
authored andcommitted
crypto: Decrypt events bundled in unsigned object of another event
Signed-off-by: Kévin Commaille <[email protected]>
1 parent 0cd93a2 commit a2235d5

File tree

8 files changed

+538
-46
lines changed

8 files changed

+538
-46
lines changed

crates/matrix-sdk-base/src/read_receipts.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,7 @@ mod tests {
772772
}),
773773
encryption_info: None,
774774
push_actions,
775+
unsigned_encryption_info: None,
775776
}
776777
}
777778

@@ -857,6 +858,7 @@ mod tests {
857858
}),
858859
encryption_info: None,
859860
push_actions: Vec::new(),
861+
unsigned_encryption_info: None,
860862
}
861863
}
862864

crates/matrix-sdk-common/src/deserialized_responses.rs

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use std::{collections::BTreeMap, fmt};
1717
use ruma::{
1818
events::{AnySyncTimelineEvent, AnyTimelineEvent},
1919
push::Action,
20-
serde::Raw,
20+
serde::{JsonObject, Raw},
2121
DeviceKeyAlgorithm, OwnedDeviceId, OwnedEventId, OwnedUserId,
2222
};
2323
use serde::{Deserialize, Serialize};
@@ -235,6 +235,11 @@ pub struct SyncTimelineEvent {
235235
/// The push actions associated with this event.
236236
#[serde(default, skip_serializing_if = "Vec::is_empty")]
237237
pub push_actions: Vec<Action>,
238+
/// The encryption info about the events bundled in the `unsigned` object.
239+
///
240+
/// Will be `None` if no bundled event was encrypted.
241+
#[serde(skip_serializing_if = "Option::is_none")]
242+
pub unsigned_encryption_info: Option<BTreeMap<UnsignedEventLocation, UnsignedDecryptionResult>>,
238243
}
239244

240245
impl SyncTimelineEvent {
@@ -243,7 +248,7 @@ impl SyncTimelineEvent {
243248
/// This is a convenience constructor for when you don't need to set
244249
/// `encryption_info` or `push_action`, for example inside a test.
245250
pub fn new(event: Raw<AnySyncTimelineEvent>) -> Self {
246-
Self { event, encryption_info: None, push_actions: vec![] }
251+
Self { event, encryption_info: None, push_actions: vec![], unsigned_encryption_info: None }
247252
}
248253

249254
/// Get the event id of this `SyncTimelineEvent` if the event has any valid
@@ -256,20 +261,22 @@ impl SyncTimelineEvent {
256261
#[cfg(not(tarpaulin_include))]
257262
impl fmt::Debug for SyncTimelineEvent {
258263
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
259-
let SyncTimelineEvent { event, encryption_info, push_actions } = self;
264+
let SyncTimelineEvent { event, encryption_info, push_actions, unsigned_encryption_info } =
265+
self;
260266
let mut s = f.debug_struct("SyncTimelineEvent");
261267
s.field("event", &DebugRawEvent(event));
262268
s.maybe_field("encryption_info", encryption_info);
263269
if !push_actions.is_empty() {
264270
s.field("push_actions", push_actions);
265271
}
272+
s.maybe_field("unsigned_encryption_info", unsigned_encryption_info);
266273
s.finish()
267274
}
268275
}
269276

270277
impl From<Raw<AnySyncTimelineEvent>> for SyncTimelineEvent {
271278
fn from(inner: Raw<AnySyncTimelineEvent>) -> Self {
272-
Self { encryption_info: None, event: inner, push_actions: Vec::default() }
279+
Self::new(inner)
273280
}
274281
}
275282

@@ -283,6 +290,7 @@ impl From<TimelineEvent> for SyncTimelineEvent {
283290
event: o.event.cast(),
284291
encryption_info: o.encryption_info,
285292
push_actions: o.push_actions.unwrap_or_default(),
293+
unsigned_encryption_info: o.unsigned_encryption_info,
286294
}
287295
}
288296
}
@@ -297,6 +305,10 @@ pub struct TimelineEvent {
297305
/// The push actions associated with this event, if we had sufficient
298306
/// context to compute them.
299307
pub push_actions: Option<Vec<Action>>,
308+
/// The encryption info about the events bundled in the `unsigned` object.
309+
///
310+
/// Will be `None` if no bundled event was encrypted.
311+
pub unsigned_encryption_info: Option<BTreeMap<UnsignedEventLocation, UnsignedDecryptionResult>>,
300312
}
301313

302314
impl TimelineEvent {
@@ -305,14 +317,14 @@ impl TimelineEvent {
305317
/// This is a convenience constructor for when you don't need to set
306318
/// `encryption_info` or `push_action`, for example inside a test.
307319
pub fn new(event: Raw<AnyTimelineEvent>) -> Self {
308-
Self { event, encryption_info: None, push_actions: None }
320+
Self { event, encryption_info: None, push_actions: None, unsigned_encryption_info: None }
309321
}
310322
}
311323

312324
#[cfg(not(tarpaulin_include))]
313325
impl fmt::Debug for TimelineEvent {
314326
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
315-
let TimelineEvent { event, encryption_info, push_actions } = self;
327+
let TimelineEvent { event, encryption_info, push_actions, unsigned_encryption_info } = self;
316328
let mut s = f.debug_struct("TimelineEvent");
317329
s.field("event", &DebugRawEvent(event));
318330
s.maybe_field("encryption_info", encryption_info);
@@ -321,10 +333,59 @@ impl fmt::Debug for TimelineEvent {
321333
s.field("push_actions", push_actions);
322334
}
323335
}
336+
s.maybe_field("unsigned_encryption_info", unsigned_encryption_info);
324337
s.finish()
325338
}
326339
}
327340

341+
/// The location of an event bundled in an `unsigned` object.
342+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
343+
pub enum UnsignedEventLocation {
344+
/// An event at the `m.replace` key of the `m.relations` object, that is a
345+
/// bundled replacement.
346+
RelationsReplace,
347+
/// An event at the `latest_event` key of the `m.thread` object of the
348+
/// `m.relations` object, that is the latest event of a thread.
349+
RelationsThreadLatestEvent,
350+
}
351+
352+
impl UnsignedEventLocation {
353+
/// Find the mutable JSON value at this location in the given unsigned
354+
/// object.
355+
///
356+
/// # Arguments
357+
///
358+
/// * `unsigned` - The `unsigned` property of an event as a JSON object.
359+
pub fn find_mut<'a>(&self, unsigned: &'a mut JsonObject) -> Option<&'a mut serde_json::Value> {
360+
let relations = unsigned.get_mut("m.relations")?.as_object_mut()?;
361+
362+
match self {
363+
Self::RelationsReplace => relations.get_mut("m.replace"),
364+
Self::RelationsThreadLatestEvent => {
365+
relations.get_mut("m.thread")?.as_object_mut()?.get_mut("latest_event")
366+
}
367+
}
368+
}
369+
}
370+
371+
/// The result of the decryption of an event bundled in an `unsigned` object.
372+
#[derive(Debug, Clone, Serialize, Deserialize)]
373+
pub enum UnsignedDecryptionResult {
374+
/// The event was successfully decrypted.
375+
Decrypted(EncryptionInfo),
376+
/// The event failed to be decrypted.
377+
UnableToDecrypt(UnableToDecryptInfo),
378+
}
379+
380+
/// Metadata about an event that could not be decrypted.
381+
#[derive(Debug, Clone, Serialize, Deserialize)]
382+
pub struct UnableToDecryptInfo {
383+
/// The ID of the session used to encrypt the message, if it used the
384+
/// `m.megolm.v1.aes-sha2` algorithm.
385+
#[serde(skip_serializing_if = "Option::is_none")]
386+
pub session_id: Option<String>,
387+
}
388+
328389
#[cfg(test)]
329390
mod tests {
330391
use ruma::{

crates/matrix-sdk-common/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
#![doc = include_str!("../README.md")]
1616
#![warn(missing_debug_implementations)]
1717

18+
use std::pin::Pin;
19+
20+
use futures_core::Future;
1821
#[doc(no_inline)]
1922
pub use instant;
2023
#[doc(no_inline)]
@@ -88,3 +91,9 @@ macro_rules! boxed_into_future {
8891
>>;
8992
};
9093
}
94+
95+
/// A `Box::pin` future that is `Send` on non-wasm, and without `Send` on wasm.
96+
#[cfg(target_arch = "wasm32")]
97+
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
98+
#[cfg(not(target_arch = "wasm32"))]
99+
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;

0 commit comments

Comments
 (0)