@@ -17,7 +17,7 @@ use std::{collections::BTreeMap, fmt};
1717use ruma:: {
1818 events:: { AnySyncTimelineEvent , AnyTimelineEvent } ,
1919 push:: Action ,
20- serde:: Raw ,
20+ serde:: { JsonObject , Raw } ,
2121 DeviceKeyAlgorithm , OwnedDeviceId , OwnedEventId , OwnedUserId ,
2222} ;
2323use 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
240245impl 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) ) ]
257262impl 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
270277impl 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
302314impl 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) ) ]
313325impl 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) ]
329390mod tests {
330391 use ruma:: {
0 commit comments