From 343c26b3ed5263a8ef5e03e47acd57a3e381d39a Mon Sep 17 00:00:00 2001 From: Sorunome Date: Fri, 23 Oct 2020 16:25:15 +0200 Subject: [PATCH] fix: Decrypt last message on received megolm key --- lib/encryption/encryption.dart | 6 +++--- lib/encryption/key_manager.dart | 7 ++++++- lib/src/room.dart | 10 ++++++++- lib/src/timeline.dart | 1 - test/encryption/key_manager_test.dart | 30 +++++++++++++++++++++++++++ test/room_test.dart | 25 ++++++++++++++++++++++ 6 files changed, 73 insertions(+), 6 deletions(-) diff --git a/lib/encryption/encryption.dart b/lib/encryption/encryption.dart index be04610..6819117 100644 --- a/lib/encryption/encryption.dart +++ b/lib/encryption/encryption.dart @@ -238,6 +238,9 @@ class Encryption { {bool store = false, EventUpdateType updateType = EventUpdateType.timeline}) async { final doStore = () async { + if (updateType != EventUpdateType.history) { + event.room?.setState(event); + } await client.database?.storeEventUpdate( client.id, EventUpdate( @@ -248,9 +251,6 @@ class Encryption { sortOrder: event.sortOrder, ), ); - if (updateType != EventUpdateType.history) { - event.room?.setState(event); - } }; if (event.type != EventTypes.Encrypted) { return event; diff --git a/lib/encryption/key_manager.dart b/lib/encryption/key_manager.dart index 92e8a65..b530e29 100644 --- a/lib/encryption/key_manager.dart +++ b/lib/encryption/key_manager.dart @@ -150,9 +150,14 @@ class KeyManager { .markInboundGroupSessionAsUploaded(client.id, roomId, sessionId); } }); - // TODO: somehow try to decrypt last message again final room = client.getRoomById(roomId); if (room != null) { + // attempt to decrypt the last event + final event = room.getState(EventTypes.Encrypted); + if (event != null && event.content['session_id'] == sessionId) { + encryption.decryptRoomEvent(roomId, event, store: true); + } + // and finally broadcast the new session room.onSessionKeyReceived.add(sessionId); } } diff --git a/lib/src/room.dart b/lib/src/room.dart index 1b64336..2788d44 100644 --- a/lib/src/room.dart +++ b/lib/src/room.dart @@ -272,7 +272,15 @@ class Room { var lastEvent = lastEvents.isEmpty ? null - : lastEvents.reduce((a, b) => a.sortOrder > b.sortOrder ? a : b); + : lastEvents.reduce((a, b) { + if (a.sortOrder == b.sortOrder) { + // if two events have the same sort order we want to give encrypted events a lower priority + // This is so that if the same event exists in the state both encrypted *and* unencrypted, + // the unencrypted one is picked + return a.type == EventTypes.Encrypted ? b : a; + } + return a.sortOrder > b.sortOrder ? a : b; + }); if (lastEvent == null) { states.forEach((final String key, final entry) { if (!entry.containsKey('')) return; diff --git a/lib/src/timeline.dart b/lib/src/timeline.dart index 649aaa9..6050423 100644 --- a/lib/src/timeline.dart +++ b/lib/src/timeline.dart @@ -118,7 +118,6 @@ class Timeline { for (var i = 0; i < events.length; i++) { if (events[i].type == EventTypes.Encrypted && events[i].messageType == MessageTypes.BadEncrypted && - events[i].content['can_request_session'] == true && events[i].content['session_id'] == sessionId) { events[i] = await room.client.encryption .decryptRoomEvent(room.id, events[i], store: true); diff --git a/test/encryption/key_manager_test.dart b/test/encryption/key_manager_test.dart index 1dea9c4..0f40ef4 100644 --- a/test/encryption/key_manager_test.dart +++ b/test/encryption/key_manager_test.dart @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +import 'dart:convert'; + import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/src/utils/logs.dart'; import 'package:test/test.dart'; @@ -249,6 +251,30 @@ void main() { final senderKey = client.identityKey; final roomId = '!someroom:example.org'; final sessionId = inbound.session_id(); + final room = Room(id: roomId, client: client); + client.rooms.add(room); + // we build up an encrypted message so that we can test if it successfully decrypted afterwards + room.states['m.room.encrypted'] = Event( + senderId: '@test:example.com', + type: 'm.room.encrypted', + roomId: room.id, + room: room, + eventId: '12345', + originServerTs: DateTime.now(), + content: { + 'algorithm': 'm.megolm.v1.aes-sha2', + 'ciphertext': session.encrypt(json.encode({ + 'type': 'm.room.message', + 'content': {'msgtype': 'm.text', 'body': 'foxies'}, + })), + 'device_id': client.deviceID, + 'sender_key': client.identityKey, + 'session_id': sessionId, + }, + stateKey: '', + sortOrder: 42.0, + ); + expect(room.lastEvent.type, 'm.room.encrypted'); // set a payload... var sessionPayload = { 'algorithm': 'm.megolm.v1.aes-sha2', @@ -379,6 +405,10 @@ void main() { .length, 0); + // test that it decrypted the last event + expect(room.lastEvent.type, 'm.room.message'); + expect(room.lastEvent.content['body'], 'foxies'); + inbound.free(); session.free(); }); diff --git a/test/room_test.dart b/test/room_test.dart index 53cc2d7..38f96dc 100644 --- a/test/room_test.dart +++ b/test/room_test.dart @@ -179,6 +179,31 @@ void main() { expect(room.timeCreated, room.lastEvent.originServerTs); }); + test('multiple last event with same sort order', () { + room.states['m.room.encrypted'] = Event( + senderId: '@test:example.com', + type: 'm.room.encrypted', + roomId: room.id, + room: room, + eventId: '12345', + originServerTs: DateTime.now(), + content: {'msgtype': 'm.text', 'body': 'test'}, + stateKey: '', + sortOrder: 42.0); + expect(room.lastEvent.type, 'm.room.encrypted'); + room.states['m.room.messge'] = Event( + senderId: '@test:example.com', + type: 'm.room.messge', + roomId: room.id, + room: room, + eventId: '12345', + originServerTs: DateTime.now(), + content: {'msgtype': 'm.text', 'body': 'test'}, + stateKey: '', + sortOrder: 42.0); + expect(room.lastEvent.type, 'm.room.encrypted'); + }); + test('sendReadReceipt', () async { await room.sendReadReceipt('ยง1234:fakeServer.notExisting'); });