@@ -44,7 +44,10 @@ use ruma::{
4444} ;
4545use serde_json:: { value:: to_raw_value, Value } ;
4646use tracing:: { debug, error, info, trace, warn} ;
47- use vodozemac:: { megolm:: SessionOrdering , Curve25519PublicKey , Ed25519Signature } ;
47+ use vodozemac:: {
48+ megolm:: { DecryptionError , SessionOrdering } ,
49+ Curve25519PublicKey , Ed25519Signature ,
50+ } ;
4851
4952#[ cfg( feature = "backups_v1" ) ]
5053use crate :: backups:: BackupMachine ;
@@ -1143,8 +1146,6 @@ impl OlmMachine {
11431146
11441147 Ok ( TimelineEvent { encryption_info : Some ( encryption_info) , event : decrypted_event } )
11451148 } else {
1146- self . key_request_machine . create_outgoing_key_request ( room_id, event) . await ?;
1147-
11481149 Err ( MegolmError :: MissingRoomKey )
11491150 }
11501151 }
@@ -1179,29 +1180,36 @@ impl OlmMachine {
11791180 }
11801181 } ;
11811182
1182- self . decrypt_megolm_events ( room_id, & event, & content) . await . map_err ( |e| {
1183- if let MegolmError :: MissingRoomKey = e {
1184- // TODO log the withheld reason if we have one.
1185- debug ! (
1186- sender = event. sender. as_str( ) ,
1187- room_id = room_id. as_str( ) ,
1188- session_id = content. session_id( ) ,
1189- algorithm = %content. algorithm( ) ,
1190- "Failed to decrypt a room event, the room key is missing"
1191- ) ;
1192- } else {
1193- warn ! (
1194- sender = event. sender. as_str( ) ,
1195- room_id = room_id. as_str( ) ,
1196- session_id = content. session_id( ) ,
1197- algorithm = %content. algorithm( ) ,
1198- error = ?e,
1199- "Failed to decrypt a room event"
1200- ) ;
1183+ let result = self . decrypt_megolm_events ( room_id, & event, & content) . await ;
1184+
1185+ if let Err ( e) = & result {
1186+ match e {
1187+ MegolmError :: MissingRoomKey
1188+ | MegolmError :: Decryption ( DecryptionError :: UnknownMessageIndex ( _, _) ) => {
1189+ // TODO: log the withheld reason if we have one.
1190+ debug ! (
1191+ sender = event. sender. as_str( ) ,
1192+ room_id = room_id. as_str( ) ,
1193+ session_id = content. session_id( ) ,
1194+ algorithm = %content. algorithm( ) ,
1195+ "Failed to decrypt a room event, the room key is missing or has been ratcheted"
1196+ ) ;
1197+ self . key_request_machine . create_outgoing_key_request ( room_id, & event) . await ?;
1198+ }
1199+ _ => {
1200+ warn ! (
1201+ sender = event. sender. as_str( ) ,
1202+ room_id = room_id. as_str( ) ,
1203+ session_id = content. session_id( ) ,
1204+ algorithm = %content. algorithm( ) ,
1205+ error = ?e,
1206+ "Failed to decrypt a room event"
1207+ ) ;
1208+ }
12011209 }
1210+ }
12021211
1203- e
1204- } )
1212+ result
12051213 }
12061214
12071215 /// Update the tracked users.
@@ -1627,7 +1635,7 @@ pub(crate) mod tests {
16271635 } ,
16281636 utilities:: json_convert,
16291637 verification:: tests:: { outgoing_request_to_event, request_to_event} ,
1630- EncryptionSettings , OlmError , ReadOnlyDevice , ToDeviceRequest ,
1638+ EncryptionSettings , MegolmError , OlmError , ReadOnlyDevice , ToDeviceRequest ,
16311639 } ;
16321640
16331641 /// These keys need to be periodically uploaded to the server.
@@ -2080,6 +2088,75 @@ pub(crate) mod tests {
20802088 }
20812089 }
20822090
2091+ #[ async_test]
2092+ async fn test_query_ratcheted_key ( ) {
2093+ let ( alice, bob) = get_machine_pair_with_setup_sessions ( ) . await ;
2094+ let room_id = room_id ! ( "!test:example.org" ) ;
2095+
2096+ // Need a second bob session to check gossiping
2097+ let bob_id = user_id ( ) ;
2098+ let bob_other_device = device_id ! ( "OTHERBOB" ) ;
2099+ let bob_other_machine = OlmMachine :: new ( bob_id, bob_other_device) . await ;
2100+ let bob_other_device = ReadOnlyDevice :: from_machine ( & bob_other_machine) . await ;
2101+ bob. store . save_devices ( & [ bob_other_device] ) . await . unwrap ( ) ;
2102+ bob. get_device ( bob_id, device_id ! ( "OTHERBOB" ) , None )
2103+ . await
2104+ . unwrap ( )
2105+ . expect ( "should exist" )
2106+ . set_trust_state ( crate :: LocalTrust :: Verified ) ;
2107+
2108+ alice. create_outbound_group_session_with_defaults ( room_id) . await . unwrap ( ) ;
2109+
2110+ let plaintext = "It is a secret to everybody" ;
2111+
2112+ let content = RoomMessageEventContent :: text_plain ( plaintext) ;
2113+
2114+ let content = alice
2115+ . encrypt_room_event ( room_id, AnyMessageLikeEventContent :: RoomMessage ( content. clone ( ) ) )
2116+ . await
2117+ . unwrap ( ) ;
2118+
2119+ let room_event = OriginalSyncRoomEncryptedEvent {
2120+ event_id : event_id ! ( "$xxxxx:example.org" ) . to_owned ( ) ,
2121+ origin_server_ts : MilliSecondsSinceUnixEpoch :: now ( ) ,
2122+ sender : alice. user_id ( ) . to_owned ( ) ,
2123+ content : content. deserialize_as ( ) . unwrap ( ) ,
2124+ unsigned : MessageLikeUnsigned :: default ( ) ,
2125+ } ;
2126+
2127+ // should share at index 1
2128+ let to_device_requests = alice
2129+ . share_room_key ( room_id, iter:: once ( bob. user_id ( ) ) , EncryptionSettings :: default ( ) )
2130+ . await
2131+ . unwrap ( ) ;
2132+
2133+ let event = ToDeviceEvent :: new (
2134+ alice. user_id ( ) . to_owned ( ) ,
2135+ to_device_requests_to_content ( to_device_requests) ,
2136+ ) ;
2137+
2138+ let group_session =
2139+ bob. decrypt_to_device_event ( & event) . await . unwrap ( ) . inbound_group_session ;
2140+ bob. store . save_inbound_group_sessions ( & [ group_session. unwrap ( ) ] ) . await . unwrap ( ) ;
2141+
2142+ let room_event = json_convert ( & room_event) . unwrap ( ) ;
2143+
2144+ let decrypt_error = bob. decrypt_room_event ( & room_event, room_id) . await . unwrap_err ( ) ;
2145+
2146+ if let MegolmError :: Decryption ( vodo_error) = decrypt_error {
2147+ if let vodozemac:: megolm:: DecryptionError :: UnknownMessageIndex ( _, _) = vodo_error {
2148+ // check that key has been requested
2149+ let outgoing_to_devices =
2150+ bob. key_request_machine . outgoing_to_device_requests ( ) . await . unwrap ( ) ;
2151+ assert_eq ! ( 1 , outgoing_to_devices. len( ) ) ;
2152+ } else {
2153+ panic ! ( "Should be UnknownMessageIndex error " )
2154+ }
2155+ } else {
2156+ panic ! ( "Should have been unable to decrypt" )
2157+ }
2158+ }
2159+
20832160 #[ async_test]
20842161 async fn interactive_verification ( ) {
20852162 let ( alice, bob) = get_machine_pair_with_setup_sessions ( ) . await ;
0 commit comments