Skip to content

Commit 1c0694a

Browse files
committed
feat: Send state event to timeline when sharing megolm session
1 parent 0960e35 commit 1c0694a

File tree

2 files changed

+84
-37
lines changed

2 files changed

+84
-37
lines changed

lib/encryption/key_manager.dart

Lines changed: 83 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -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;

lib/src/utils/event_localizations.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ abstract class EventLocalizations {
119119
EventTypes.Sticker: (event, i18n, body) => i18n.sentASticker(
120120
event.senderFromMemoryOrFallback.calcDisplayname(i18n: i18n),
121121
),
122+
'sdk.dart.matrix.new_megolm_session': (event, i18n, body) => body,
122123
EventTypes.Redaction: (event, i18n, body) => i18n.redactedAnEvent(event),
123124
EventTypes.RoomAliases: (event, i18n, body) => i18n.changedTheRoomAliases(
124125
event.senderFromMemoryOrFallback.calcDisplayname(i18n: i18n),

0 commit comments

Comments
 (0)