@@ -281,11 +281,16 @@ pub enum AlgorithmInfo {
281281 /// decrypt this session. This map will usually contain a single ed25519
282282 /// key.
283283 sender_claimed_keys : BTreeMap < DeviceKeyAlgorithm , String > ,
284+
285+ /// The Megolm session ID that was used to encrypt this event, or None
286+ /// if this info was stored before we collected this data.
287+ #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
288+ session_id : Option < String > ,
284289 } ,
285290}
286291
287292/// Struct containing information on how an event was decrypted.
288- #[ derive( Clone , Debug , Deserialize , Serialize ) ]
293+ #[ derive( Clone , Debug , Serialize ) ]
289294pub struct EncryptionInfo {
290295 /// The user ID of the event sender, note this is untrusted data unless the
291296 /// `verification_state` is `Verified` as well.
@@ -302,9 +307,54 @@ pub struct EncryptionInfo {
302307 /// Callers that persist this should mark the state as dirty when a device
303308 /// change is received down the sync.
304309 pub verification_state : VerificationState ,
305- /// The Megolm session ID that was used to encrypt this event, or None if
306- /// this info was stored before we collected this data.
307- pub session_id : Option < String > ,
310+ }
311+
312+ impl EncryptionInfo {
313+ /// Helper to get the megolm session id used to encrypt.
314+ pub fn session_id ( & self ) -> Option < & str > {
315+ let AlgorithmInfo :: MegolmV1AesSha2 { session_id, .. } = & self . algorithm_info ;
316+ session_id. as_deref ( )
317+ }
318+ }
319+
320+ impl < ' de > Deserialize < ' de > for EncryptionInfo {
321+ fn deserialize < D > ( deserializer : D ) -> Result < Self , D :: Error >
322+ where
323+ D : serde:: Deserializer < ' de > ,
324+ {
325+ // Backwards compatibility: Capture session_id at root if exists. In legacy
326+ // EncryptionInfo the session_id was not in AlgorithmInfo
327+ #[ derive( Deserialize ) ]
328+ struct Helper {
329+ pub sender : OwnedUserId ,
330+ pub sender_device : Option < OwnedDeviceId > ,
331+ pub algorithm_info : AlgorithmInfo ,
332+ pub verification_state : VerificationState ,
333+ #[ serde( rename = "session_id" ) ]
334+ pub old_session_id : Option < String > ,
335+ }
336+
337+ let Helper {
338+ sender,
339+ sender_device,
340+ algorithm_info :
341+ AlgorithmInfo :: MegolmV1AesSha2 { curve25519_key, sender_claimed_keys, session_id } ,
342+ verification_state,
343+ old_session_id,
344+ } = Helper :: deserialize ( deserializer) ?;
345+
346+ Ok ( EncryptionInfo {
347+ sender,
348+ sender_device,
349+ algorithm_info : AlgorithmInfo :: MegolmV1AesSha2 {
350+ // Migration, merge the old_session_id in algorithm_info
351+ session_id : session_id. or ( old_session_id) ,
352+ curve25519_key,
353+ sender_claimed_keys,
354+ } ,
355+ verification_state,
356+ } )
357+ }
308358}
309359
310360/// Represents a matrix room event that has been returned from `/sync`,
@@ -549,12 +599,11 @@ impl TimelineEventKind {
549599 pub fn session_id ( & self ) -> Option < & str > {
550600 match self {
551601 TimelineEventKind :: Decrypted ( decrypted_room_event) => {
552- decrypted_room_event. encryption_info . session_id . as_ref ( )
602+ decrypted_room_event. encryption_info . session_id ( )
553603 }
554- TimelineEventKind :: UnableToDecrypt { utd_info, .. } => utd_info. session_id . as_ref ( ) ,
604+ TimelineEventKind :: UnableToDecrypt { utd_info, .. } => utd_info. session_id . as_deref ( ) ,
555605 TimelineEventKind :: PlainText { .. } => None ,
556606 }
557- . map ( String :: as_str)
558607 }
559608}
560609
@@ -1056,9 +1105,9 @@ mod tests {
10561105 algorithm_info : AlgorithmInfo :: MegolmV1AesSha2 {
10571106 curve25519_key : "xxx" . to_owned ( ) ,
10581107 sender_claimed_keys : Default :: default ( ) ,
1108+ session_id : Some ( "xyz" . to_owned ( ) ) ,
10591109 } ,
10601110 verification_state : VerificationState :: Verified ,
1061- session_id : Some ( "xyz" . to_owned ( ) ) ,
10621111 } ,
10631112 unsigned_encryption_info : Some ( BTreeMap :: from ( [ (
10641113 UnsignedEventLocation :: RelationsReplace ,
@@ -1093,11 +1142,11 @@ mod tests {
10931142 "algorithm_info" : {
10941143 "MegolmV1AesSha2" : {
10951144 "curve25519_key" : "xxx" ,
1096- "sender_claimed_keys" : { }
1145+ "sender_claimed_keys" : { } ,
1146+ "session_id" : "xyz" ,
10971147 }
10981148 } ,
10991149 "verification_state" : "Verified" ,
1100- "session_id" : "xyz" ,
11011150 } ,
11021151 "unsigned_encryption_info" : {
11031152 "RelationsReplace" : { "UnableToDecrypt" : {
@@ -1144,9 +1193,8 @@ mod tests {
11441193 assert_eq ! ( event. event_id( ) , Some ( event_id!( "$xxxxx:example.org" ) . to_owned( ) ) ) ;
11451194 assert_matches ! (
11461195 event. encryption_info( ) . unwrap( ) . algorithm_info,
1147- AlgorithmInfo :: MegolmV1AesSha2 { .. }
1196+ AlgorithmInfo :: MegolmV1AesSha2 { session_id : None , .. }
11481197 ) ;
1149- assert_eq ! ( event. encryption_info( ) . unwrap( ) . session_id, None ) ;
11501198
11511199 // Test that the previous format, with an undecryptable unsigned event, can also
11521200 // be deserialized.
@@ -1366,13 +1414,40 @@ mod tests {
13661414 ( DeviceKeyAlgorithm :: Curve25519 , "claimedclaimedcurve25519" . to_owned ( ) ) ,
13671415 ( DeviceKeyAlgorithm :: Ed25519 , "claimedclaimeded25519" . to_owned ( ) ) ,
13681416 ] ) ,
1417+ session_id : None ,
13691418 } ;
13701419
13711420 with_settings ! ( { prepend_module_to_snapshot => false } , {
13721421 assert_json_snapshot!( info)
13731422 } ) ;
13741423 }
13751424
1425+ #[ test]
1426+ fn test_encryption_info_migration ( ) {
1427+ // In the old format the session_id was in the EncryptionInfo, now
1428+ // it is moved to the `algorithm_info` struct.
1429+ let old_format = json ! ( {
1430+ "sender" : "@alice:localhost" ,
1431+ "sender_device" : "ABCDEFGH" ,
1432+ "algorithm_info" : {
1433+ "MegolmV1AesSha2" : {
1434+ "curve25519_key" : "curvecurvecurve" ,
1435+ "sender_claimed_keys" : { }
1436+ }
1437+ } ,
1438+ "verification_state" : "Verified" ,
1439+ "session_id" : "mysessionid76"
1440+ } ) ;
1441+
1442+ let deserialized = serde_json:: from_value :: < EncryptionInfo > ( old_format) . unwrap ( ) ;
1443+ let expected_session_id = Some ( "mysessionid76" . to_owned ( ) ) ;
1444+
1445+ let AlgorithmInfo :: MegolmV1AesSha2 { session_id, .. } = deserialized. algorithm_info . clone ( ) ;
1446+ assert_eq ! ( session_id, expected_session_id) ;
1447+
1448+ assert_json_snapshot ! ( deserialized) ;
1449+ }
1450+
13761451 #[ test]
13771452 fn snapshot_test_encryption_info ( ) {
13781453 let info = EncryptionInfo {
@@ -1381,9 +1456,9 @@ mod tests {
13811456 algorithm_info : AlgorithmInfo :: MegolmV1AesSha2 {
13821457 curve25519_key : "curvecurvecurve" . into ( ) ,
13831458 sender_claimed_keys : Default :: default ( ) ,
1459+ session_id : Some ( "mysessionid76" . to_owned ( ) ) ,
13841460 } ,
13851461 verification_state : VerificationState :: Verified ,
1386- session_id : Some ( "mysessionid76" . to_owned ( ) ) ,
13871462 } ;
13881463
13891464 with_settings ! ( { sort_maps => true , prepend_module_to_snapshot => false } , {
@@ -1411,9 +1486,9 @@ mod tests {
14111486 "qzdW3F5IMPFl0HQgz5w/L5Oi/npKUFn8Um84acIHfPY" . to_owned ( ) ,
14121487 ) ,
14131488 ] ) ,
1489+ session_id : Some ( "mysessionid112" . to_owned ( ) ) ,
14141490 } ,
14151491 verification_state : VerificationState :: Verified ,
1416- session_id : Some ( "mysessionid112" . to_owned ( ) ) ,
14171492 } ,
14181493 unsigned_encryption_info : Some ( BTreeMap :: from ( [ (
14191494 UnsignedEventLocation :: RelationsThreadLatestEvent ,
0 commit comments