From a35266f1e403c4ccfed429116246b1c706dbaf38 Mon Sep 17 00:00:00 2001 From: Sorunome Date: Fri, 15 Jan 2021 15:43:31 +0100 Subject: [PATCH] feat: Replay last sent olm message on olm session recovery from other device --- lib/encryption/encryption.dart | 11 +- lib/encryption/olm_manager.dart | 41 ++++++- lib/src/database/database.dart | 8 +- lib/src/database/database.g.dart | 109 ++++++++++++++++-- lib/src/database/database.moor | 4 + test/canonical_json_test.dart | 2 +- test/client_test.dart | 2 +- test/device_keys_list_test.dart | 2 +- test/encryption/bootstrap_test.dart | 2 +- test/encryption/cross_signing_test.dart | 2 +- .../encrypt_decrypt_room_message_test.dart | 2 +- .../encrypt_decrypt_to_device_test.dart | 8 +- test/encryption/key_manager_test.dart | 2 +- test/encryption/key_request_test.dart | 2 +- test/encryption/key_verification_test.dart | 2 +- test/encryption/olm_manager_test.dart | 86 +++++++++++++- test/encryption/online_key_backup_test.dart | 2 +- test/encryption/ssss_test.dart | 2 +- test/event_test.dart | 2 +- test/fake_client.dart | 2 +- test/fake_database.dart | 2 +- test/fake_matrix_api.dart | 2 +- test/fake_matrix_localizations.dart | 2 +- test/markdown_test.dart | 2 +- test/matrix_api_test.dart | 2 +- test/matrix_default_localizations.dart | 2 +- test/matrix_exception_test.dart | 2 +- test/matrix_file_test.dart | 2 +- test/matrix_id_string_extension_test.dart | 2 +- test/matrix_localizations_test.dart | 2 +- test/mxc_uri_extension_test.dart | 2 +- test/room_test.dart | 2 +- test/states_map_test.dart | 2 +- test/sync_filter_test.dart | 2 +- test/timeline_test.dart | 2 +- test/uia_test.dart | 2 +- test/user_test.dart | 2 +- 37 files changed, 270 insertions(+), 57 deletions(-) diff --git a/lib/encryption/encryption.dart b/lib/encryption/encryption.dart index 12239ddf..65992f3f 100644 --- a/lib/encryption/encryption.dart +++ b/lib/encryption/encryption.dart @@ -93,6 +93,11 @@ class Encryption { // them in the background unawaited(runInRoot(() => keyManager.handleToDeviceEvent(event))); } + if (event.type == EventTypes.Dummy) { + // the previous device just had to create a new olm session, due to olm session + // corruption. We want to try to send it the last message we just sent it, if possible + unawaited(runInRoot(() => olmManager.handleToDeviceEvent(event))); + } if (event.type.startsWith('m.key.verification.')) { // some key verification event. No need to handle it now, we can easily // do this in the background @@ -336,12 +341,6 @@ class Encryption { return encryptedPayload; } - Future> encryptToDeviceMessagePayload( - DeviceKeys device, String type, Map payload) async { - return await olmManager.encryptToDeviceMessagePayload( - device, type, payload); - } - Future> encryptToDeviceMessage( List deviceKeys, String type, diff --git a/lib/encryption/olm_manager.dart b/lib/encryption/olm_manager.dart index 2f260d3b..592a6381 100644 --- a/lib/encryption/olm_manager.dart +++ b/lib/encryption/olm_manager.dart @@ -444,7 +444,7 @@ class OlmManager { } _restoredOlmSessionsTime[mapKey] = DateTime.now(); await startOutgoingOlmSessions([device]); - await client.sendToDeviceEncrypted([device], 'm.dummy', {}); + await client.sendToDeviceEncrypted([device], EventTypes.Dummy, {}); } Future decryptToDeviceEvent(ToDeviceEvent event) async { @@ -542,6 +542,16 @@ class OlmManager { }; final encryptResult = sess.first.session.encrypt(json.encode(fullPayload)); storeOlmSession(sess.first); + if (client.database != null) { + unawaited(client.database.setLastSentMessageUserDeviceKey( + json.encode({ + 'type': type, + 'content': payload, + }), + client.id, + device.userId, + device.deviceId)); + } final encryptedBody = { 'algorithm': AlgorithmTypes.olmV1Curve25519AesSha2, 'sender_key': identityKey, @@ -587,6 +597,35 @@ class OlmManager { return data; } + Future handleToDeviceEvent(ToDeviceEvent event) async { + if (event.type == EventTypes.Dummy) { + // We receive dan encrypted m.dummy. This means that the other end was not able to + // decrypt our last message. So, we re-send it. + if (event.encryptedContent == null || client.database == null) { + return; + } + final device = client.getUserDeviceKeysByCurve25519Key( + event.encryptedContent.tryGet('sender_key', '')); + if (device == null) { + return; // device not found + } + Logs().v( + '[OlmManager] Device ${device.userId}:${device.deviceId} generated a new olm session, replaying last sent message...'); + final lastSentMessageRes = await client.database + .getLastSentMessageUserDeviceKey( + client.id, device.userId, device.deviceId) + .get(); + if (lastSentMessageRes.isEmpty || + (lastSentMessageRes.first?.isEmpty ?? true)) { + return; + } + final lastSentMessage = json.decode(lastSentMessageRes.first); + // okay, time to send the message! + await client.sendToDeviceEncrypted( + [device], lastSentMessage['type'], lastSentMessage['content']); + } + } + void dispose() { for (final sessions in olmSessions.values) { for (final sess in sessions) { diff --git a/lib/src/database/database.dart b/lib/src/database/database.dart index bbe00393..9bbaacba 100644 --- a/lib/src/database/database.dart +++ b/lib/src/database/database.dart @@ -70,7 +70,7 @@ class Database extends _$Database { Database.connect(DatabaseConnection connection) : super.connect(connection); @override - int get schemaVersion => 9; + int get schemaVersion => 10; int get maxFileSize => 1 * 1024 * 1024; @@ -164,6 +164,12 @@ class Database extends _$Database { userDeviceKeysKey, userDeviceKeysKey.lastActive); from++; } + if (from == 9) { + await m.addColumnIfNotExists( + userDeviceKeysKey, userDeviceKeysKey.lastSentMessage); + await m.createIndexIfNotExists(olmSessionsIdentityIndex); + from++; + } } catch (e, s) { api.Logs().e('Database migration failed', e, s); onError.add(SdkError(exception: e, stackTrace: s)); diff --git a/lib/src/database/database.g.dart b/lib/src/database/database.g.dart index 4c04816e..621b0d15 100644 --- a/lib/src/database/database.g.dart +++ b/lib/src/database/database.g.dart @@ -769,6 +769,7 @@ class DbUserDeviceKeysKey extends DataClass final bool verified; final bool blocked; final int lastActive; + final String lastSentMessage; DbUserDeviceKeysKey( {@required this.clientId, @required this.userId, @@ -776,7 +777,8 @@ class DbUserDeviceKeysKey extends DataClass @required this.content, this.verified, this.blocked, - this.lastActive}); + this.lastActive, + this.lastSentMessage}); factory DbUserDeviceKeysKey.fromData( Map data, GeneratedDatabase db, {String prefix}) { @@ -799,6 +801,8 @@ class DbUserDeviceKeysKey extends DataClass boolType.mapFromDatabaseResponse(data['${effectivePrefix}blocked']), lastActive: intType .mapFromDatabaseResponse(data['${effectivePrefix}last_active']), + lastSentMessage: stringType + .mapFromDatabaseResponse(data['${effectivePrefix}last_sent_message']), ); } @override @@ -825,6 +829,9 @@ class DbUserDeviceKeysKey extends DataClass if (!nullToAbsent || lastActive != null) { map['last_active'] = Variable(lastActive); } + if (!nullToAbsent || lastSentMessage != null) { + map['last_sent_message'] = Variable(lastSentMessage); + } return map; } @@ -850,6 +857,9 @@ class DbUserDeviceKeysKey extends DataClass lastActive: lastActive == null && nullToAbsent ? const Value.absent() : Value(lastActive), + lastSentMessage: lastSentMessage == null && nullToAbsent + ? const Value.absent() + : Value(lastSentMessage), ); } @@ -864,6 +874,7 @@ class DbUserDeviceKeysKey extends DataClass verified: serializer.fromJson(json['verified']), blocked: serializer.fromJson(json['blocked']), lastActive: serializer.fromJson(json['last_active']), + lastSentMessage: serializer.fromJson(json['last_sent_message']), ); } @override @@ -877,6 +888,7 @@ class DbUserDeviceKeysKey extends DataClass 'verified': serializer.toJson(verified), 'blocked': serializer.toJson(blocked), 'last_active': serializer.toJson(lastActive), + 'last_sent_message': serializer.toJson(lastSentMessage), }; } @@ -887,7 +899,8 @@ class DbUserDeviceKeysKey extends DataClass String content, bool verified, bool blocked, - int lastActive}) => + int lastActive, + String lastSentMessage}) => DbUserDeviceKeysKey( clientId: clientId ?? this.clientId, userId: userId ?? this.userId, @@ -896,6 +909,7 @@ class DbUserDeviceKeysKey extends DataClass verified: verified ?? this.verified, blocked: blocked ?? this.blocked, lastActive: lastActive ?? this.lastActive, + lastSentMessage: lastSentMessage ?? this.lastSentMessage, ); @override String toString() { @@ -906,7 +920,8 @@ class DbUserDeviceKeysKey extends DataClass ..write('content: $content, ') ..write('verified: $verified, ') ..write('blocked: $blocked, ') - ..write('lastActive: $lastActive') + ..write('lastActive: $lastActive, ') + ..write('lastSentMessage: $lastSentMessage') ..write(')')) .toString(); } @@ -920,8 +935,12 @@ class DbUserDeviceKeysKey extends DataClass deviceId.hashCode, $mrjc( content.hashCode, - $mrjc(verified.hashCode, - $mrjc(blocked.hashCode, lastActive.hashCode))))))); + $mrjc( + verified.hashCode, + $mrjc( + blocked.hashCode, + $mrjc(lastActive.hashCode, + lastSentMessage.hashCode)))))))); @override bool operator ==(dynamic other) => identical(this, other) || @@ -932,7 +951,8 @@ class DbUserDeviceKeysKey extends DataClass other.content == this.content && other.verified == this.verified && other.blocked == this.blocked && - other.lastActive == this.lastActive); + other.lastActive == this.lastActive && + other.lastSentMessage == this.lastSentMessage); } class UserDeviceKeysKeyCompanion extends UpdateCompanion { @@ -943,6 +963,7 @@ class UserDeviceKeysKeyCompanion extends UpdateCompanion { final Value verified; final Value blocked; final Value lastActive; + final Value lastSentMessage; const UserDeviceKeysKeyCompanion({ this.clientId = const Value.absent(), this.userId = const Value.absent(), @@ -951,6 +972,7 @@ class UserDeviceKeysKeyCompanion extends UpdateCompanion { this.verified = const Value.absent(), this.blocked = const Value.absent(), this.lastActive = const Value.absent(), + this.lastSentMessage = const Value.absent(), }); UserDeviceKeysKeyCompanion.insert({ @required int clientId, @@ -960,6 +982,7 @@ class UserDeviceKeysKeyCompanion extends UpdateCompanion { this.verified = const Value.absent(), this.blocked = const Value.absent(), this.lastActive = const Value.absent(), + this.lastSentMessage = const Value.absent(), }) : clientId = Value(clientId), userId = Value(userId), deviceId = Value(deviceId), @@ -972,6 +995,7 @@ class UserDeviceKeysKeyCompanion extends UpdateCompanion { Expression verified, Expression blocked, Expression lastActive, + Expression lastSentMessage, }) { return RawValuesInsertable({ if (clientId != null) 'client_id': clientId, @@ -981,6 +1005,7 @@ class UserDeviceKeysKeyCompanion extends UpdateCompanion { if (verified != null) 'verified': verified, if (blocked != null) 'blocked': blocked, if (lastActive != null) 'last_active': lastActive, + if (lastSentMessage != null) 'last_sent_message': lastSentMessage, }); } @@ -991,7 +1016,8 @@ class UserDeviceKeysKeyCompanion extends UpdateCompanion { Value content, Value verified, Value blocked, - Value lastActive}) { + Value lastActive, + Value lastSentMessage}) { return UserDeviceKeysKeyCompanion( clientId: clientId ?? this.clientId, userId: userId ?? this.userId, @@ -1000,6 +1026,7 @@ class UserDeviceKeysKeyCompanion extends UpdateCompanion { verified: verified ?? this.verified, blocked: blocked ?? this.blocked, lastActive: lastActive ?? this.lastActive, + lastSentMessage: lastSentMessage ?? this.lastSentMessage, ); } @@ -1027,6 +1054,9 @@ class UserDeviceKeysKeyCompanion extends UpdateCompanion { if (lastActive.present) { map['last_active'] = Variable(lastActive.value); } + if (lastSentMessage.present) { + map['last_sent_message'] = Variable(lastSentMessage.value); + } return map; } @@ -1039,7 +1069,8 @@ class UserDeviceKeysKeyCompanion extends UpdateCompanion { ..write('content: $content, ') ..write('verified: $verified, ') ..write('blocked: $blocked, ') - ..write('lastActive: $lastActive') + ..write('lastActive: $lastActive, ') + ..write('lastSentMessage: $lastSentMessage') ..write(')')) .toString(); } @@ -1108,9 +1139,27 @@ class UserDeviceKeysKey extends Table $customConstraints: ''); } + final VerificationMeta _lastSentMessageMeta = + const VerificationMeta('lastSentMessage'); + GeneratedTextColumn _lastSentMessage; + GeneratedTextColumn get lastSentMessage => + _lastSentMessage ??= _constructLastSentMessage(); + GeneratedTextColumn _constructLastSentMessage() { + return GeneratedTextColumn('last_sent_message', $tableName, true, + $customConstraints: ''); + } + @override - List get $columns => - [clientId, userId, deviceId, content, verified, blocked, lastActive]; + List get $columns => [ + clientId, + userId, + deviceId, + content, + verified, + blocked, + lastActive, + lastSentMessage + ]; @override UserDeviceKeysKey get asDslTable => this; @override @@ -1161,6 +1210,12 @@ class UserDeviceKeysKey extends Table lastActive.isAcceptableOrUnknown( data['last_active'], _lastActiveMeta)); } + if (data.containsKey('last_sent_message')) { + context.handle( + _lastSentMessageMeta, + lastSentMessage.isAcceptableOrUnknown( + data['last_sent_message'], _lastSentMessageMeta)); + } return context; } @@ -6136,6 +6191,10 @@ abstract class _$Database extends GeneratedDatabase { Index get olmSessionsIndex => _olmSessionsIndex ??= Index( 'olm_sessions_index', 'CREATE INDEX olm_sessions_index ON olm_sessions(client_id);'); + Index _olmSessionsIdentityIndex; + Index get olmSessionsIdentityIndex => _olmSessionsIdentityIndex ??= Index( + 'olm_sessions_identity_index', + 'CREATE INDEX olm_sessions_identity_index ON olm_sessions(client_id, identity_key);'); OutboundGroupSessions _outboundGroupSessions; OutboundGroupSessions get outboundGroupSessions => _outboundGroupSessions ??= OutboundGroupSessions(this); @@ -6574,6 +6633,35 @@ abstract class _$Database extends GeneratedDatabase { ); } + Future setLastSentMessageUserDeviceKey(String last_sent_message, + int client_id, String user_id, String device_id) { + return customUpdate( + 'UPDATE user_device_keys_key SET last_sent_message = :last_sent_message WHERE client_id = :client_id AND user_id = :user_id AND device_id = :device_id', + variables: [ + Variable.withString(last_sent_message), + Variable.withInt(client_id), + Variable.withString(user_id), + Variable.withString(device_id) + ], + updates: {userDeviceKeysKey}, + updateKind: UpdateKind.update, + ); + } + + Selectable getLastSentMessageUserDeviceKey( + int client_id, String user_id, String device_id) { + return customSelect( + 'SELECT last_sent_message FROM user_device_keys_key WHERE client_id = :client_id AND user_id = :user_id AND device_id = :device_id', + variables: [ + Variable.withInt(client_id), + Variable.withString(user_id), + Variable.withString(device_id) + ], + readsFrom: { + userDeviceKeysKey + }).map((QueryRow row) => row.readString('last_sent_message')); + } + Future setVerifiedUserCrossSigningKey( bool verified, int client_id, String user_id, String public_key) { return customUpdate( @@ -7068,6 +7156,7 @@ abstract class _$Database extends GeneratedDatabase { userCrossSigningKeysIndex, olmSessions, olmSessionsIndex, + olmSessionsIdentityIndex, outboundGroupSessions, outboundGroupSessionsIndex, inboundGroupSessions, diff --git a/lib/src/database/database.moor b/lib/src/database/database.moor index c2d4e04b..695a384d 100644 --- a/lib/src/database/database.moor +++ b/lib/src/database/database.moor @@ -29,6 +29,7 @@ CREATE TABLE user_device_keys_key ( verified BOOLEAN DEFAULT false, blocked BOOLEAN DEFAULT false, last_active BIGINT, + last_sent_message TEXT, UNIQUE(client_id, user_id, device_id) ) as DbUserDeviceKeysKey; CREATE INDEX user_device_keys_key_index ON user_device_keys_key(client_id); @@ -53,6 +54,7 @@ CREATE TABLE olm_sessions ( UNIQUE(client_id, identity_key, session_id) ) AS DbOlmSessions; CREATE INDEX olm_sessions_index ON olm_sessions(client_id); +CREATE INDEX olm_sessions_identity_index ON olm_sessions(client_id, identity_key); CREATE TABLE outbound_group_sessions ( client_id INTEGER NOT NULL REFERENCES clients(client_id), @@ -204,6 +206,8 @@ setBlockedUserDeviceKey: UPDATE user_device_keys_key SET blocked = :blocked WHER storeUserDeviceKey: INSERT OR REPLACE INTO user_device_keys_key (client_id, user_id, device_id, content, verified, blocked, last_active) VALUES (:client_id, :user_id, :device_id, :content, :verified, :blocked, :last_active); removeUserDeviceKey: DELETE FROM user_device_keys_key WHERE client_id = :client_id AND user_id = :user_id AND device_id = :device_id; setLastActiveUserDeviceKey: UPDATE user_device_keys_key SET last_active = :last_active WHERE client_id = :client_id AND user_id = :user_id AND device_id = :device_id; +setLastSentMessageUserDeviceKey: UPDATE user_device_keys_key SET last_sent_message = :last_sent_message WHERE client_id = :client_id AND user_id = :user_id AND device_id = :device_id; +getLastSentMessageUserDeviceKey: SELECT last_sent_message FROM user_device_keys_key WHERE client_id = :client_id AND user_id = :user_id AND device_id = :device_id; setVerifiedUserCrossSigningKey: UPDATE user_cross_signing_keys SET verified = :verified WHERE client_id = :client_id AND user_id = :user_id AND public_key = :public_key; setBlockedUserCrossSigningKey: UPDATE user_cross_signing_keys SET blocked = :blocked WHERE client_id = :client_id AND user_id = :user_id AND public_key = :public_key; storeUserCrossSigningKey: INSERT OR REPLACE INTO user_cross_signing_keys (client_id, user_id, public_key, content, verified, blocked) VALUES (:client_id, :user_id, :public_key, :content, :verified, :blocked); diff --git a/test/canonical_json_test.dart b/test/canonical_json_test.dart index a357d4e1..3b11d00e 100644 --- a/test/canonical_json_test.dart +++ b/test/canonical_json_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2019, 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/client_test.dart b/test/client_test.dart index 16b9cb36..7b215ef2 100644 --- a/test/client_test.dart +++ b/test/client_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2019, 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/device_keys_list_test.dart b/test/device_keys_list_test.dart index b0b71ea4..0eec64a1 100644 --- a/test/device_keys_list_test.dart +++ b/test/device_keys_list_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2019, 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/encryption/bootstrap_test.dart b/test/encryption/bootstrap_test.dart index d484aeca..8cd3ad78 100644 --- a/test/encryption/bootstrap_test.dart +++ b/test/encryption/bootstrap_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/encryption/cross_signing_test.dart b/test/encryption/cross_signing_test.dart index ba64a2a2..835314c7 100644 --- a/test/encryption/cross_signing_test.dart +++ b/test/encryption/cross_signing_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/encryption/encrypt_decrypt_room_message_test.dart b/test/encryption/encrypt_decrypt_room_message_test.dart index a1f54cff..9b3c90fa 100644 --- a/test/encryption/encrypt_decrypt_room_message_test.dart +++ b/test/encryption/encrypt_decrypt_room_message_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/encryption/encrypt_decrypt_to_device_test.dart b/test/encryption/encrypt_decrypt_to_device_test.dart index 343ac837..aa08ec75 100644 --- a/test/encryption/encrypt_decrypt_to_device_test.dart +++ b/test/encryption/encrypt_decrypt_to_device_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify @@ -82,12 +82,6 @@ void main() { .encryptToDeviceMessage([device], 'm.to_device', {'hello': 'foxies'}); }); - test('encryptToDeviceMessagePayload', () async { - // just a hard test if nothing errors - await otherClient.encryption.encryptToDeviceMessagePayload( - device, 'm.to_device', {'hello': 'foxies'}); - }); - test('decryptToDeviceEvent', () async { final encryptedEvent = ToDeviceEvent( sender: '@othertest:fakeServer.notExisting', diff --git a/test/encryption/key_manager_test.dart b/test/encryption/key_manager_test.dart index fd7be177..b596687e 100644 --- a/test/encryption/key_manager_test.dart +++ b/test/encryption/key_manager_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/encryption/key_request_test.dart b/test/encryption/key_request_test.dart index 45486a62..953d7f16 100644 --- a/test/encryption/key_request_test.dart +++ b/test/encryption/key_request_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/encryption/key_verification_test.dart b/test/encryption/key_verification_test.dart index 6ecb8c0d..d8429bd6 100644 --- a/test/encryption/key_verification_test.dart +++ b/test/encryption/key_verification_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/encryption/olm_manager_test.dart b/test/encryption/olm_manager_test.dart index c1959cf5..6b32c0ff 100644 --- a/test/encryption/olm_manager_test.dart +++ b/test/encryption/olm_manager_test.dart @@ -1,6 +1,6 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts - * Copyright (C) 2020 Famedly GmbH + * Famedly Matrix SDK + * Copyright (C) 2020, 2021 Famedly GmbH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -126,6 +126,88 @@ void main() { true); }); + test('replay to_device events', () async { + final userId = '@alice:example.com'; + final deviceId = 'JLAFKJWSCS'; + final senderKey = 'L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8'; + FakeMatrixApi.calledEndpoints.clear(); + await client.database.setLastSentMessageUserDeviceKey( + json.encode({ + 'type': 'm.foxies', + 'content': { + 'floof': 'foxhole', + }, + }), + client.id, + userId, + deviceId); + var event = ToDeviceEvent( + sender: userId, + type: 'm.dummy', + content: {}, + encryptedContent: { + 'sender_key': senderKey, + }, + ); + await client.encryption.olmManager.handleToDeviceEvent(event); + expect( + FakeMatrixApi.calledEndpoints.keys.any( + (k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')), + true); + + // fail scenarios + + // not encrypted + FakeMatrixApi.calledEndpoints.clear(); + await client.database.setLastSentMessageUserDeviceKey( + json.encode({ + 'type': 'm.foxies', + 'content': { + 'floof': 'foxhole', + }, + }), + client.id, + userId, + deviceId); + event = ToDeviceEvent( + sender: userId, + type: 'm.dummy', + content: {}, + encryptedContent: null, + ); + await client.encryption.olmManager.handleToDeviceEvent(event); + expect( + FakeMatrixApi.calledEndpoints.keys.any( + (k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')), + false); + + // device not found + FakeMatrixApi.calledEndpoints.clear(); + await client.database.setLastSentMessageUserDeviceKey( + json.encode({ + 'type': 'm.foxies', + 'content': { + 'floof': 'foxhole', + }, + }), + client.id, + userId, + deviceId); + event = ToDeviceEvent( + sender: userId, + type: 'm.dummy', + content: {}, + encryptedContent: { + 'sender_key': 'invalid', + }, + ); + await client.encryption.olmManager.handleToDeviceEvent(event); + expect( + FakeMatrixApi.calledEndpoints.keys.any( + (k) => k.startsWith('/client/r0/sendToDevice/m.room.encrypted')), + false); + }); + test('dispose client', () async { await client.dispose(closeDatabase: true); }); diff --git a/test/encryption/online_key_backup_test.dart b/test/encryption/online_key_backup_test.dart index a9a933d3..c224435d 100644 --- a/test/encryption/online_key_backup_test.dart +++ b/test/encryption/online_key_backup_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/encryption/ssss_test.dart b/test/encryption/ssss_test.dart index ee91c8d0..96d83f34 100644 --- a/test/encryption/ssss_test.dart +++ b/test/encryption/ssss_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/event_test.dart b/test/event_test.dart index 2b133a24..a0d3520a 100644 --- a/test/event_test.dart +++ b/test/event_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2019, 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/fake_client.dart b/test/fake_client.dart index 2bc3b903..9020d23c 100644 --- a/test/fake_client.dart +++ b/test/fake_client.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/fake_database.dart b/test/fake_database.dart index e8b60207..b0fc07bd 100644 --- a/test/fake_database.dart +++ b/test/fake_database.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2019, 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/fake_matrix_api.dart b/test/fake_matrix_api.dart index 395fc58e..c9b36b4f 100644 --- a/test/fake_matrix_api.dart +++ b/test/fake_matrix_api.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2019, 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/fake_matrix_localizations.dart b/test/fake_matrix_localizations.dart index 7342d695..5f8324a9 100644 --- a/test/fake_matrix_localizations.dart +++ b/test/fake_matrix_localizations.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2019, 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/markdown_test.dart b/test/markdown_test.dart index d387e4fc..93532cc1 100644 --- a/test/markdown_test.dart +++ b/test/markdown_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2019, 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/matrix_api_test.dart b/test/matrix_api_test.dart index b647b927..7ee201d9 100644 --- a/test/matrix_api_test.dart +++ b/test/matrix_api_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2019, 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/matrix_default_localizations.dart b/test/matrix_default_localizations.dart index 0b5b5ccf..e7319e1c 100644 --- a/test/matrix_default_localizations.dart +++ b/test/matrix_default_localizations.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2019, 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/matrix_exception_test.dart b/test/matrix_exception_test.dart index d6982ab3..0ee347e2 100644 --- a/test/matrix_exception_test.dart +++ b/test/matrix_exception_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2019, 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/matrix_file_test.dart b/test/matrix_file_test.dart index d1109c89..e233bf82 100644 --- a/test/matrix_file_test.dart +++ b/test/matrix_file_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2019, 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/matrix_id_string_extension_test.dart b/test/matrix_id_string_extension_test.dart index 50c02a27..c3d1d61e 100644 --- a/test/matrix_id_string_extension_test.dart +++ b/test/matrix_id_string_extension_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2019, 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/matrix_localizations_test.dart b/test/matrix_localizations_test.dart index fb694757..768a3052 100644 --- a/test/matrix_localizations_test.dart +++ b/test/matrix_localizations_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2019, 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/mxc_uri_extension_test.dart b/test/mxc_uri_extension_test.dart index 3949fd20..b5c03a73 100644 --- a/test/mxc_uri_extension_test.dart +++ b/test/mxc_uri_extension_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2019, 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/room_test.dart b/test/room_test.dart index 23c30dcf..26c1c6e3 100644 --- a/test/room_test.dart +++ b/test/room_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2019, 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/states_map_test.dart b/test/states_map_test.dart index 00386a00..cae5826b 100644 --- a/test/states_map_test.dart +++ b/test/states_map_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2019, 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/sync_filter_test.dart b/test/sync_filter_test.dart index 33d8aa91..27ee6616 100644 --- a/test/sync_filter_test.dart +++ b/test/sync_filter_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/timeline_test.dart b/test/timeline_test.dart index cf543238..a57b96d7 100644 --- a/test/timeline_test.dart +++ b/test/timeline_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2019, 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/uia_test.dart b/test/uia_test.dart index 5407f05b..800ea67a 100644 --- a/test/uia_test.dart +++ b/test/uia_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify diff --git a/test/user_test.dart b/test/user_test.dart index f3a1ef1b..4867c46e 100644 --- a/test/user_test.dart +++ b/test/user_test.dart @@ -1,5 +1,5 @@ /* - * Ansible inventory script used at Famedly GmbH for managing many hosts + * Famedly Matrix SDK * Copyright (C) 2019, 2020 Famedly GmbH * * This program is free software: you can redistribute it and/or modify