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');
});