@@ -293,6 +293,43 @@ class KeyManager {
293293 return sess;
294294 }
295295
296+ void _sendEncryptionInfoEvent ({
297+ required String roomId,
298+ required List <String > userIds,
299+ List <String >? deviceIds,
300+ }) async {
301+ await client.database? .transaction (() async {
302+ await client.handleSync (
303+ SyncUpdate (
304+ nextBatch: '' ,
305+ rooms: RoomsUpdate (
306+ join: {
307+ roomId: JoinedRoomUpdate (
308+ timeline: TimelineUpdate (
309+ events: [
310+ MatrixEvent (
311+ eventId:
312+ 'fake_event_${client .generateUniqueTransactionId ()}' ,
313+ content: {
314+ 'body' :
315+ '${userIds .join (', ' )} can now read along${deviceIds != null ? ' on a new device' : '' }' ,
316+ if (deviceIds != null ) 'devices' : deviceIds,
317+ 'users' : userIds,
318+ },
319+ type: 'sdk.dart.matrix.new_megolm_session' ,
320+ senderId: client.userID! ,
321+ originServerTs: DateTime .now (),
322+ ),
323+ ],
324+ ),
325+ ),
326+ },
327+ ),
328+ ),
329+ );
330+ });
331+ }
332+
296333 Map <String , Map <String , bool >> _getDeviceKeyIdMap (
297334 List <DeviceKeys > deviceKeys,
298335 ) {
@@ -328,21 +365,6 @@ class KeyManager {
328365 return true ;
329366 }
330367
331- if (! wipe) {
332- // first check if it needs to be rotated
333- final encryptionContent =
334- room.getState (EventTypes .Encryption )? .parsedRoomEncryptionContent;
335- final maxMessages = encryptionContent? .rotationPeriodMsgs ?? 100 ;
336- final maxAge = encryptionContent? .rotationPeriodMs ??
337- 604800000 ; // default of one week
338- if ((sess.sentMessages ?? maxMessages) >= maxMessages ||
339- sess.creationTime
340- .add (Duration (milliseconds: maxAge))
341- .isBefore (DateTime .now ())) {
342- wipe = true ;
343- }
344- }
345-
346368 final inboundSess = await loadInboundGroupSession (
347369 room.id,
348370 sess.outboundGroupSession! .session_id (),
@@ -357,8 +379,8 @@ class KeyManager {
357379 final newDeviceKeys = await room.getUserDeviceKeys ();
358380 final newDeviceKeyIds = _getDeviceKeyIdMap (newDeviceKeys);
359381 // first check for user differences
360- final oldUserIds = Set . from ( sess.devices.keys);
361- final newUserIds = Set . from ( newDeviceKeyIds.keys);
382+ final oldUserIds = sess.devices.keys. toSet ( );
383+ final newUserIds = newDeviceKeyIds.keys. toSet ( );
362384 if (oldUserIds.difference (newUserIds).isNotEmpty) {
363385 // a user left the room, we must wipe the session
364386 wipe = true ;
@@ -368,6 +390,7 @@ class KeyManager {
368390 // new user! Gotta send the megolm session to them
369391 devicesToReceive
370392 .addAll (newDeviceKeys.where ((d) => newUsers.contains (d.userId)));
393+ _sendEncryptionInfoEvent (roomId: roomId, userIds: newUsers.toList ());
371394 }
372395 // okay, now we must test all the individual user devices, if anything new got blocked
373396 // or if we need to send to any new devices.
@@ -389,37 +412,45 @@ class KeyManager {
389412 .map ((e) => e.key),
390413 )
391414 : < String > {};
392- // we don't really care about old devices that got dropped (deleted), we only care if new ones got added and if new ones got blocked
393- // check if new devices got blocked
394- if (newBlockedDevices.difference (oldBlockedDevices).isNotEmpty) {
395- wipe = true ;
396- break ;
397- }
398415 // and now add all the new devices!
399416 final oldDeviceIds = sess.devices.containsKey (userId)
400- ? Set .from (
401- sess.devices[userId]! .entries
402- .where ((e) => ! e.value)
403- .map ((e) => e.key),
404- )
417+ ? sess.devices[userId]! .entries
418+ .where ((e) => ! e.value)
419+ .map ((e) => e.key)
420+ .toSet ()
405421 : < String > {};
406422 final newDeviceIds = newDeviceKeyIds.containsKey (userId)
407- ? Set .from (
408- newDeviceKeyIds[userId]!
409- .entries
410- .where ((e) => ! e.value)
411- .map ((e) => e.key),
412- )
423+ ? newDeviceKeyIds[userId]!
424+ .entries
425+ .where ((e) => ! e.value)
426+ .map ((e) => e.key)
427+ .toSet ()
413428 : < String > {};
414429
430+ // check if any new devices need keys
431+ final newDevices = newDeviceIds.difference (oldDeviceIds);
432+
433+ if (userId != client.userID && newDevices.isNotEmpty) {
434+ _sendEncryptionInfoEvent (
435+ roomId: roomId,
436+ userIds: [userId],
437+ deviceIds: newDevices.toList (),
438+ );
439+ }
440+
441+ // we don't really care about old devices that got dropped (deleted), we only care if new ones got added and if new ones got blocked
442+ // check if new devices got blocked
443+ if (newBlockedDevices.difference (oldBlockedDevices).isNotEmpty) {
444+ wipe = true ;
445+ continue ;
446+ }
447+
415448 // check if a device got removed
416449 if (oldDeviceIds.difference (newDeviceIds).isNotEmpty) {
417450 wipe = true ;
418- break ;
451+ continue ;
419452 }
420453
421- // check if any new devices need keys
422- final newDevices = newDeviceIds.difference (oldDeviceIds);
423454 if (newDeviceIds.isNotEmpty) {
424455 devicesToReceive.addAll (
425456 newDeviceKeys.where (
@@ -430,6 +461,21 @@ class KeyManager {
430461 }
431462 }
432463
464+ if (! wipe) {
465+ // first check if it needs to be rotated
466+ final encryptionContent =
467+ room.getState (EventTypes .Encryption )? .parsedRoomEncryptionContent;
468+ final maxMessages = encryptionContent? .rotationPeriodMsgs ?? 100 ;
469+ final maxAge = encryptionContent? .rotationPeriodMs ??
470+ 604800000 ; // default of one week
471+ if ((sess.sentMessages ?? maxMessages) >= maxMessages ||
472+ sess.creationTime
473+ .add (Duration (milliseconds: maxAge))
474+ .isBefore (DateTime .now ())) {
475+ wipe = true ;
476+ }
477+ }
478+
433479 if (! wipe) {
434480 if (! use) {
435481 return false ;
0 commit comments