From d7c4ce8c9efe73cb8ebc99ace21c35e5431414ea Mon Sep 17 00:00:00 2001 From: Krille Date: Mon, 3 Feb 2025 16:07:59 +0100 Subject: [PATCH] feat: Send state event to timeline when sharing megolm session --- lib/encryption/key_manager.dart | 96 +++++++++++++++++++------- lib/src/utils/event_localizations.dart | 1 + 2 files changed, 73 insertions(+), 24 deletions(-) diff --git a/lib/encryption/key_manager.dart b/lib/encryption/key_manager.dart index 3d18032df..805527fd8 100644 --- a/lib/encryption/key_manager.dart +++ b/lib/encryption/key_manager.dart @@ -293,6 +293,43 @@ class KeyManager { return sess; } + void _sendEncryptionInfoEvent({ + required String roomId, + required List userIds, + List? deviceIds, + }) async { + await client.database?.transaction(() async { + await client.handleSync( + SyncUpdate( + nextBatch: '', + rooms: RoomsUpdate( + join: { + roomId: JoinedRoomUpdate( + timeline: TimelineUpdate( + events: [ + MatrixEvent( + eventId: + 'fake_event_${client.generateUniqueTransactionId()}', + content: { + 'body': + '${userIds.join(', ')} can now read along${deviceIds != null ? ' on a new device' : ''}', + if (deviceIds != null) 'devices': deviceIds, + 'users': userIds, + }, + type: 'sdk.dart.matrix.new_megolm_session', + senderId: client.userID!, + originServerTs: DateTime.now(), + ), + ], + ), + ), + }, + ), + ), + ); + }); + } + Map> _getDeviceKeyIdMap( List deviceKeys, ) { @@ -328,21 +365,6 @@ class KeyManager { return true; } - if (!wipe) { - // first check if it needs to be rotated - final encryptionContent = - room.getState(EventTypes.Encryption)?.parsedRoomEncryptionContent; - final maxMessages = encryptionContent?.rotationPeriodMsgs ?? 100; - final maxAge = encryptionContent?.rotationPeriodMs ?? - 604800000; // default of one week - if ((sess.sentMessages ?? maxMessages) >= maxMessages || - sess.creationTime - .add(Duration(milliseconds: maxAge)) - .isBefore(DateTime.now())) { - wipe = true; - } - } - final inboundSess = await loadInboundGroupSession( room.id, sess.outboundGroupSession!.session_id(), @@ -368,6 +390,7 @@ class KeyManager { // new user! Gotta send the megolm session to them devicesToReceive .addAll(newDeviceKeys.where((d) => newUsers.contains(d.userId))); + _sendEncryptionInfoEvent(roomId: roomId, userIds: newUsers.toList()); } // okay, now we must test all the individual user devices, if anything new got blocked // or if we need to send to any new devices. @@ -387,12 +410,6 @@ class KeyManager { .map((e) => e.key) .toSet() : {}; - // 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 - // check if new devices got blocked - if (newBlockedDevices.difference(oldBlockedDevices).isNotEmpty) { - wipe = true; - break; - } // and now add all the new devices! final oldDeviceIds = sess.devices.containsKey(userId) ? sess.devices[userId]!.entries @@ -408,14 +425,30 @@ class KeyManager { .toSet() : {}; + // check if any new devices need keys + final newDevices = newDeviceIds.difference(oldDeviceIds); + + if (userId != client.userID && newDevices.isNotEmpty) { + _sendEncryptionInfoEvent( + roomId: roomId, + userIds: [userId], + deviceIds: newDevices.toList(), + ); + } + + // 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 + // check if new devices got blocked + if (newBlockedDevices.difference(oldBlockedDevices).isNotEmpty) { + wipe = true; + continue; + } + // check if a device got removed if (oldDeviceIds.difference(newDeviceIds).isNotEmpty) { wipe = true; - break; + continue; } - // check if any new devices need keys - final newDevices = newDeviceIds.difference(oldDeviceIds); if (newDeviceIds.isNotEmpty) { devicesToReceive.addAll( newDeviceKeys.where( @@ -426,6 +459,21 @@ class KeyManager { } } + if (!wipe) { + // first check if it needs to be rotated + final encryptionContent = + room.getState(EventTypes.Encryption)?.parsedRoomEncryptionContent; + final maxMessages = encryptionContent?.rotationPeriodMsgs ?? 100; + final maxAge = encryptionContent?.rotationPeriodMs ?? + 604800000; // default of one week + if ((sess.sentMessages ?? maxMessages) >= maxMessages || + sess.creationTime + .add(Duration(milliseconds: maxAge)) + .isBefore(DateTime.now())) { + wipe = true; + } + } + if (!wipe) { if (!use) { return false; diff --git a/lib/src/utils/event_localizations.dart b/lib/src/utils/event_localizations.dart index 1ae3b98a9..0506ce2b4 100644 --- a/lib/src/utils/event_localizations.dart +++ b/lib/src/utils/event_localizations.dart @@ -119,6 +119,7 @@ abstract class EventLocalizations { EventTypes.Sticker: (event, i18n, body) => i18n.sentASticker( event.senderFromMemoryOrFallback.calcDisplayname(i18n: i18n), ), + 'sdk.dart.matrix.new_megolm_session': (event, i18n, body) => body, EventTypes.Redaction: (event, i18n, body) => i18n.redactedAnEvent(event), EventTypes.RoomAliases: (event, i18n, body) => i18n.changedTheRoomAliases( event.senderFromMemoryOrFallback.calcDisplayname(i18n: i18n),