17
17
18
18
use std:: collections:: BTreeMap ;
19
19
20
- use matrix_sdk_base:: deserialized_responses:: RawAnySyncOrStrippedState ;
20
+ use futures_util:: future:: join_all;
21
+ use matrix_sdk_base:: deserialized_responses:: { EncryptionInfo , RawAnySyncOrStrippedState } ;
22
+ use matrix_sdk_common:: executor:: spawn;
21
23
use ruma:: {
22
24
api:: client:: {
23
25
account:: request_openid_token:: v3:: { Request as OpenIdRequest , Response as OpenIdResponse } ,
24
26
delayed_events:: { self , update_delayed_event:: unstable:: UpdateAction } ,
25
27
filter:: RoomEventFilter ,
28
+ to_device:: send_event_to_device:: { self , v3:: Request as RumaToDeviceRequest } ,
26
29
} ,
27
30
assign,
28
31
events:: {
29
32
AnyMessageLikeEventContent , AnyStateEventContent , AnySyncMessageLikeEvent ,
30
- AnySyncStateEvent , AnySyncTimelineEvent , AnyTimelineEvent , MessageLikeEventType ,
31
- StateEventType , TimelineEventType ,
33
+ AnySyncStateEvent , AnySyncTimelineEvent , AnyTimelineEvent , AnyToDeviceEvent ,
34
+ AnyToDeviceEventContent , MessageLikeEventType , StateEventType , TimelineEventType ,
35
+ ToDeviceEventType ,
32
36
} ,
33
37
serde:: { from_raw_json_value, Raw } ,
34
- EventId , RoomId , TransactionId ,
38
+ to_device:: DeviceIdOrAllDevices ,
39
+ EventId , OwnedUserId , RoomId , TransactionId , UserId ,
35
40
} ;
36
41
use serde_json:: { value:: RawValue as RawJsonValue , Value } ;
37
42
use tokio:: sync:: mpsc:: { unbounded_channel, UnboundedReceiver } ;
38
- use tracing:: error;
43
+ use tracing:: { error, info , warn } ;
39
44
40
45
use super :: { machine:: SendEventResponse , StateKeySelector } ;
41
- use crate :: { event_handler:: EventHandlerDropGuard , room:: MessagesOptions , Error , Result , Room } ;
46
+ use crate :: {
47
+ encryption:: identities:: Device , event_handler:: EventHandlerDropGuard , room:: MessagesOptions ,
48
+ Client , Error , Result , Room ,
49
+ } ;
42
50
43
51
/// Thin wrapper around a [`Room`] that provides functionality relevant for
44
52
/// widgets.
@@ -86,7 +94,11 @@ impl MatrixDriver {
86
94
) -> Result < Vec < Raw < AnyTimelineEvent > > > {
87
95
let room_id = self . room . room_id ( ) ;
88
96
let convert = |sync_or_stripped_state| match sync_or_stripped_state {
89
- RawAnySyncOrStrippedState :: Sync ( ev) => Some ( attach_room_id ( ev. cast_ref ( ) , room_id) ) ,
97
+ RawAnySyncOrStrippedState :: Sync ( ev) => with_attached_room_id ( ev. cast_ref ( ) , room_id)
98
+ . map_err ( |e| {
99
+ error ! ( "failed to convert event from `get_state_event` response:{}" , e)
100
+ } )
101
+ . ok ( ) ,
90
102
RawAnySyncOrStrippedState :: Stripped ( _) => {
91
103
error ! ( "MatrixDriver can't operate in invited rooms" ) ;
92
104
None
@@ -181,7 +193,7 @@ impl MatrixDriver {
181
193
182
194
/// Starts forwarding new room events. Once the returned `EventReceiver`
183
195
/// is dropped, forwarding will be stopped.
184
- pub ( crate ) fn events ( & self ) -> EventReceiver {
196
+ pub ( crate ) fn events ( & self ) -> EventReceiver < Raw < AnyTimelineEvent > > {
185
197
let ( tx, rx) = unbounded_channel ( ) ;
186
198
let room_id = self . room . room_id ( ) . to_owned ( ) ;
187
199
@@ -190,14 +202,29 @@ impl MatrixDriver {
190
202
let _room_id = room_id. clone ( ) ;
191
203
let handle_msg_like =
192
204
self . room . add_event_handler ( move |raw : Raw < AnySyncMessageLikeEvent > | {
193
- let _ = _tx. send ( attach_room_id ( raw. cast_ref ( ) , & _room_id) ) ;
205
+ match with_attached_room_id ( raw. cast_ref ( ) , & _room_id) {
206
+ Ok ( event_with_room_id) => {
207
+ let _ = _tx. send ( event_with_room_id) ;
208
+ }
209
+ Err ( e) => {
210
+ error ! ( "Failed to attach room id to message like event: {}" , e) ;
211
+ }
212
+ }
194
213
async { }
195
214
} ) ;
196
215
let drop_guard_msg_like = self . room . client ( ) . event_handler_drop_guard ( handle_msg_like) ;
197
-
216
+ let _room_id = room_id;
217
+ let _tx = tx;
198
218
// Get only all state events from the state section of the sync.
199
219
let handle_state = self . room . add_event_handler ( move |raw : Raw < AnySyncStateEvent > | {
200
- let _ = tx. send ( attach_room_id ( raw. cast_ref ( ) , & room_id) ) ;
220
+ match with_attached_room_id ( raw. cast_ref ( ) , & _room_id) {
221
+ Ok ( event_with_room_id) => {
222
+ let _ = _tx. send ( event_with_room_id) ;
223
+ }
224
+ Err ( e) => {
225
+ error ! ( "Failed to attach room id to state event: {}" , e) ;
226
+ }
227
+ }
201
228
async { }
202
229
} ) ;
203
230
let drop_guard_state = self . room . client ( ) . event_handler_drop_guard ( handle_state) ;
@@ -208,25 +235,213 @@ impl MatrixDriver {
208
235
// section of the sync will not be forwarded to the widget.
209
236
// TODO annotate the events and send both timeline and state section state
210
237
// events.
211
- EventReceiver { rx, _drop_guards : [ drop_guard_msg_like, drop_guard_state] }
238
+ EventReceiver { rx, _drop_guards : vec ! [ drop_guard_msg_like, drop_guard_state] }
239
+ }
240
+
241
+ /// Starts forwarding new room events. Once the returned `EventReceiver`
242
+ /// is dropped, forwarding will be stopped.
243
+ pub ( crate ) fn to_device_events ( & self ) -> EventReceiver < Raw < AnyToDeviceEvent > > {
244
+ let ( tx, rx) = unbounded_channel ( ) ;
245
+
246
+ let to_device_handle =
247
+ self . room . client ( ) . add_event_handler ( move |raw : Raw < AnyToDeviceEvent > | {
248
+ match with_attached_encryption_flag ( raw, & encryption_info) {
249
+ Ok ( ev) => {
250
+ let _ = tx. send ( ev) ;
251
+ }
252
+ Err ( e) => {
253
+ error ! ( "Failed to attach encryption flag to to_device event: {}" , e) ;
254
+ }
255
+ }
256
+ async { }
257
+ } ) ;
258
+
259
+ let drop_guard = self . room . client ( ) . event_handler_drop_guard ( to_device_handle) ;
260
+ EventReceiver { rx, _drop_guards : vec ! [ drop_guard] }
261
+ }
262
+
263
+ /// It will ignore all devices where errors occurred or where the device is
264
+ /// not verified or where th user has a has_verification_violation.
265
+ pub ( crate ) async fn send_to_device (
266
+ & self ,
267
+ event_type : ToDeviceEventType ,
268
+ encrypted : bool ,
269
+ messages : BTreeMap <
270
+ OwnedUserId ,
271
+ BTreeMap < DeviceIdOrAllDevices , Raw < AnyToDeviceEventContent > > ,
272
+ > ,
273
+ ) -> Result < send_event_to_device:: v3:: Response > {
274
+ let client = self . room . client ( ) ;
275
+ /// This encrypts to device content for a collection of devices.
276
+ /// It will ignore all devices where errors occurred or where the device
277
+ /// is not verified or where th user has a has_verification_violation.
278
+ async fn encrypted_content_for_devices (
279
+ unencrypted_content : & Raw < AnyToDeviceEventContent > ,
280
+ devices : Vec < Device > ,
281
+ event_type : & ToDeviceEventType ,
282
+ ) -> Result < impl Iterator < Item = ( DeviceIdOrAllDevices , Raw < AnyToDeviceEventContent > ) > >
283
+ {
284
+ let content: Value =
285
+ unencrypted_content. deserialize_as ( ) . map_err ( Into :: < Error > :: into) ?;
286
+ let event_type = event_type. clone ( ) ;
287
+ let device_content_tasks = devices. into_iter ( ) . map ( |device| spawn ( {
288
+ let event_type = event_type. clone ( ) ;
289
+ let content = content. clone ( ) ;
290
+
291
+ async move {
292
+ if !device. is_cross_signed_by_owner ( ) {
293
+ info ! ( "Device {} is not verified, skipping encryption" , device. device_id( ) ) ;
294
+ return None ;
295
+ }
296
+ match device
297
+ . inner
298
+ . encrypt_event_raw ( & event_type. to_string ( ) , & content)
299
+ . await {
300
+ Ok ( encrypted) => Some ( ( device. device_id ( ) . to_owned ( ) . into ( ) , encrypted. cast ( ) ) ) ,
301
+ Err ( e) =>{ info ! ( "Failed to encrypt to_device event from widget for device: {} because, {}" , device. device_id( ) , e) ; None } ,
302
+ }
303
+ }
304
+ } ) ) ;
305
+ let device_encrypted_content_map =
306
+ join_all ( device_content_tasks) . await . into_iter ( ) . flatten ( ) . flatten ( ) ;
307
+ Ok ( device_encrypted_content_map)
308
+ }
309
+
310
+ /// Convert the device content map for one user into the same content
311
+ /// map with encrypted content This needs to flatten the vectors
312
+ /// we get from `encrypted_content_for_devices`
313
+ /// since one `DeviceIdOrAllDevices` id can be multiple devices.
314
+ async fn encrypted_device_content_map (
315
+ client : & Client ,
316
+ user_id : & UserId ,
317
+ event_type : & ToDeviceEventType ,
318
+ device_content_map : BTreeMap < DeviceIdOrAllDevices , Raw < AnyToDeviceEventContent > > ,
319
+ ) -> BTreeMap < DeviceIdOrAllDevices , Raw < AnyToDeviceEventContent > > {
320
+ let device_map_futures =
321
+ device_content_map. into_iter ( ) . map ( |( device_or_all_id, content) | spawn ( {
322
+ let client = client. clone ( ) ;
323
+ let user_id = user_id. to_owned ( ) ;
324
+ let event_type = event_type. clone ( ) ;
325
+ async move {
326
+ let Ok ( user_devices) = client. encryption ( ) . get_user_devices ( & user_id) . await else {
327
+ warn ! ( "Failed to get user devices for user: {}" , user_id) ;
328
+ return None ;
329
+ } ;
330
+ let Ok ( user_identity) = client. encryption ( ) . get_user_identity ( & user_id) . await else {
331
+ warn ! ( "Failed to get user identity for user: {}" , user_id) ;
332
+ return None ;
333
+ } ;
334
+ if user_identity. map ( |i|i. has_verification_violation ( ) ) . unwrap_or ( false ) {
335
+ info ! ( "User {} has a verification violation, skipping encryption" , user_id) ;
336
+ return None ;
337
+ }
338
+ let devices: Vec < Device > = match device_or_all_id {
339
+ DeviceIdOrAllDevices :: DeviceId ( device_id) => {
340
+ vec ! [ user_devices. get( & device_id) ] . into_iter ( ) . flatten ( ) . collect ( )
341
+ }
342
+ DeviceIdOrAllDevices :: AllDevices => user_devices. devices ( ) . collect ( ) ,
343
+ } ;
344
+ encrypted_content_for_devices (
345
+ & content,
346
+ devices,
347
+ & event_type,
348
+ )
349
+ . await
350
+ . map_err ( |e| info ! ( "WidgetDriver: could not encrypt content for to device widget event content: {}. because, {}" , content. json( ) , e) )
351
+ . ok ( )
352
+ } } ) ) ;
353
+ let content_map_iterator = join_all ( device_map_futures) . await . into_iter ( ) ;
354
+
355
+ // The first flatten takes the iterator over Result<Option<impl Iterator<Item =
356
+ // (DeviceIdOrAllDevices, Raw<AnyToDeviceEventContent>)>>, JoinError>>
357
+ // and flattens the Result (drops Err() items)
358
+ // The second takes the iterator over: Option<impl Iterator<Item =
359
+ // (DeviceIdOrAllDevices, Raw<AnyToDeviceEventContent>)>>
360
+ // and flattens the Option (drops None items)
361
+ // The third takes the iterator over iterators: impl Iterator<Item =
362
+ // (DeviceIdOrAllDevices, Raw<AnyToDeviceEventContent>)>
363
+ // and flattens it to just an iterator over (DeviceIdOrAllDevices,
364
+ // Raw<AnyToDeviceEventContent>)
365
+ content_map_iterator. flatten ( ) . flatten ( ) . flatten ( ) . collect ( )
366
+ }
367
+
368
+ let request = if encrypted {
369
+ // We first want to get all missing session before we start any to device
370
+ // sending!
371
+ client. claim_one_time_keys ( messages. keys ( ) . map ( |u| u. as_ref ( ) ) ) . await ?;
372
+ let encrypted_content: BTreeMap <
373
+ OwnedUserId ,
374
+ BTreeMap < DeviceIdOrAllDevices , Raw < AnyToDeviceEventContent > > ,
375
+ > = join_all ( messages. into_iter ( ) . map ( |( user_id, device_content_map) | {
376
+ let event_type = event_type. clone ( ) ;
377
+ async move {
378
+ (
379
+ user_id. clone ( ) ,
380
+ encrypted_device_content_map (
381
+ & self . room . client ( ) ,
382
+ & user_id,
383
+ & event_type,
384
+ device_content_map,
385
+ )
386
+ . await ,
387
+ )
388
+ }
389
+ } ) )
390
+ . await
391
+ . into_iter ( )
392
+ . collect ( ) ;
393
+
394
+ RumaToDeviceRequest :: new_raw (
395
+ ToDeviceEventType :: RoomEncrypted ,
396
+ TransactionId :: new ( ) ,
397
+ encrypted_content,
398
+ )
399
+ } else {
400
+ RumaToDeviceRequest :: new_raw ( event_type, TransactionId :: new ( ) , messages)
401
+ } ;
402
+
403
+ let response = client. send ( request) . await ;
404
+
405
+ response. map_err ( Into :: into)
212
406
}
213
407
}
214
408
215
409
/// A simple entity that wraps an `UnboundedReceiver`
216
410
/// along with the drop guard for the room event handler.
217
- pub ( crate ) struct EventReceiver {
218
- rx : UnboundedReceiver < Raw < AnyTimelineEvent > > ,
219
- _drop_guards : [ EventHandlerDropGuard ; 2 ] ,
411
+ pub ( crate ) struct EventReceiver < E > {
412
+ rx : UnboundedReceiver < E > ,
413
+ _drop_guards : Vec < EventHandlerDropGuard > ,
220
414
}
221
415
222
- impl EventReceiver {
223
- pub ( crate ) async fn recv ( & mut self ) -> Option < Raw < AnyTimelineEvent > > {
416
+ impl < T > EventReceiver < T > {
417
+ pub ( crate ) async fn recv ( & mut self ) -> Option < T > {
224
418
self . rx . recv ( ) . await
225
419
}
226
420
}
227
421
228
- fn attach_room_id ( raw_ev : & Raw < AnySyncTimelineEvent > , room_id : & RoomId ) -> Raw < AnyTimelineEvent > {
229
- let mut ev_obj = raw_ev. deserialize_as :: < BTreeMap < String , Box < RawJsonValue > > > ( ) . unwrap ( ) ;
230
- ev_obj. insert ( "room_id" . to_owned ( ) , serde_json:: value:: to_raw_value ( room_id) . unwrap ( ) ) ;
231
- Raw :: new ( & ev_obj) . unwrap ( ) . cast ( )
422
+ fn with_attached_room_id (
423
+ raw : & Raw < AnySyncTimelineEvent > ,
424
+ room_id : & RoomId ,
425
+ ) -> Result < Raw < AnyTimelineEvent > > {
426
+ match raw. deserialize_as :: < BTreeMap < String , Box < RawJsonValue > > > ( ) {
427
+ Ok ( mut ev_mut) => {
428
+ ev_mut. insert ( "room_id" . to_owned ( ) , serde_json:: value:: to_raw_value ( room_id) ?) ;
429
+ Ok ( Raw :: new ( & ev_mut) ?. cast ( ) )
430
+ }
431
+ Err ( e) => Err ( Error :: from ( e) ) ,
432
+ }
433
+ }
434
+
435
+ fn with_attached_encryption_flag (
436
+ raw : Raw < AnyToDeviceEvent > ,
437
+ encryption_info : & Option < EncryptionInfo > ,
438
+ ) -> Result < Raw < AnyToDeviceEvent > > {
439
+ match raw. deserialize_as :: < BTreeMap < String , Box < RawJsonValue > > > ( ) {
440
+ Ok ( mut ev_mut) => {
441
+ let encrypted = encryption_info. is_some ( ) ;
442
+ ev_mut. insert ( "encrypted" . to_owned ( ) , serde_json:: value:: to_raw_value ( & encrypted) ?) ;
443
+ Ok ( Raw :: new ( & ev_mut) ?. cast ( ) )
444
+ }
445
+ Err ( e) => Err ( Error :: from ( e) ) ,
446
+ }
232
447
}
0 commit comments