diff --git a/.github/workflows/app.yml b/.github/workflows/app.yml
index 91e5529d..d3044fd5 100644
--- a/.github/workflows/app.yml
+++ b/.github/workflows/app.yml
@@ -52,6 +52,7 @@ jobs:
coverage:
#runs-on: arm-ubuntu-latest-16core
runs-on: ubuntu-latest
+ timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- run: cat .github/workflows/versions.env >> $GITHUB_ENV
diff --git a/test/encryption/key_manager_test.dart b/test/encryption/key_manager_test.dart
deleted file mode 100644
index 4319aca7..00000000
--- a/test/encryption/key_manager_test.dart
+++ /dev/null
@@ -1,628 +0,0 @@
-/*
- * Famedly Matrix SDK
- * Copyright (C) 2020 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
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-import 'dart:convert';
-
-import 'package:olm/olm.dart' as olm;
-import 'package:test/test.dart';
-
-import 'package:matrix/matrix.dart';
-import '../fake_client.dart';
-
-void main() {
- group('Key Manager', tags: 'olm', () {
- Logs().level = Level.error;
- late Client client;
-
- setUpAll(() async {
- await olm.init();
- olm.get_library_version();
- client = await getClient();
- });
-
- test('handle new m.room_key', () async {
- final validSessionId = 'ciM/JWTPrmiWPPZNkRLDPQYf9AW/I46bxyLSr+Bx5oU';
- final validSenderKey = 'JBG7ZaPn54OBC7TuIEiylW3BZ+7WcGQhFBPB9pogbAg';
- final sessionKey =
- 'AgAAAAAQcQ6XrFJk6Prm8FikZDqfry/NbDz8Xw7T6e+/9Yf/q3YHIPEQlzv7IZMNcYb51ifkRzFejVvtphS7wwG2FaXIp4XS2obla14iKISR0X74ugB2vyb1AydIHE/zbBQ1ic5s3kgjMFlWpu/S3FQCnCrv+DPFGEt3ERGWxIl3Bl5X53IjPyVkz65oljz2TZESwz0GH/QFvyOOm8ci0q/gceaF3S7Dmafg3dwTKYwcA5xkcc+BLyrLRzB6Hn+oMAqSNSscnm4mTeT5zYibIhrzqyUTMWr32spFtI9dNR/RFSzfCw';
-
- client.encryption!.keyManager.clearInboundGroupSessions();
- var event = ToDeviceEvent(
- sender: '@alice:example.com',
- type: 'm.room_key',
- content: {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': '!726s6s6q:example.com',
- 'session_id': validSessionId,
- 'session_key': sessionKey,
- },
- encryptedContent: {
- 'sender_key': validSenderKey,
- },
- );
- await client.encryption!.keyManager.handleToDeviceEvent(event);
- expect(
- client.encryption!.keyManager.getInboundGroupSession(
- '!726s6s6q:example.com',
- validSessionId,
- ) !=
- null,
- true,
- );
-
- // now test a few invalid scenarios
-
- // not encrypted
- client.encryption!.keyManager.clearInboundGroupSessions();
- event = ToDeviceEvent(
- sender: '@alice:example.com',
- type: 'm.room_key',
- content: {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': '!726s6s6q:example.com',
- 'session_id': validSessionId,
- 'session_key': sessionKey,
- },
- );
- await client.encryption!.keyManager.handleToDeviceEvent(event);
- expect(
- client.encryption!.keyManager.getInboundGroupSession(
- '!726s6s6q:example.com',
- validSessionId,
- ) !=
- null,
- false,
- );
- });
-
- test('outbound group session', () async {
- final roomId = '!726s6s6q:example.com';
- expect(
- client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
- false,
- );
- var sess = await client.encryption!.keyManager
- .createOutboundGroupSession(roomId);
- expect(
- client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
- true,
- );
- await client.encryption!.keyManager
- .clearOrUseOutboundGroupSession(roomId);
- expect(
- client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
- true,
- );
- var inbound = client.encryption!.keyManager.getInboundGroupSession(
- roomId,
- sess.outboundGroupSession!.session_id(),
- );
- expect(inbound != null, true);
- expect(
- inbound!.allowedAtIndex['@alice:example.com']
- ?['L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8'],
- 0,
- );
- expect(
- inbound.allowedAtIndex['@alice:example.com']
- ?['wMIDhiQl5jEXQrTB03ePOSQfR8sA/KMrW0CIfFfXKEE'],
- 0,
- );
-
- // rotate after too many messages
- for (final _ in Iterable.generate(300)) {
- sess.outboundGroupSession!.encrypt('some string');
- }
- await client.encryption!.keyManager
- .clearOrUseOutboundGroupSession(roomId);
- expect(
- client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
- false,
- );
-
- // rotate if device is blocked
- sess = await client.encryption!.keyManager
- .createOutboundGroupSession(roomId);
- client.userDeviceKeys['@alice:example.com']!.deviceKeys['JLAFKJWSCS']!
- .blocked = true;
- await client.encryption!.keyManager
- .clearOrUseOutboundGroupSession(roomId);
- expect(
- client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
- false,
- );
- client.userDeviceKeys['@alice:example.com']!.deviceKeys['JLAFKJWSCS']!
- .blocked = false;
-
- // lazy-create if it would rotate
- sess = await client.encryption!.keyManager
- .createOutboundGroupSession(roomId);
- final oldSessKey = sess.outboundGroupSession!.session_key();
- client.userDeviceKeys['@alice:example.com']!.deviceKeys['JLAFKJWSCS']!
- .blocked = true;
- await client.encryption!.keyManager.prepareOutboundGroupSession(roomId);
- expect(
- client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
- true,
- );
- expect(
- client.encryption!.keyManager
- .getOutboundGroupSession(roomId)!
- .outboundGroupSession!
- .session_key() !=
- oldSessKey,
- true,
- );
- client.userDeviceKeys['@alice:example.com']!.deviceKeys['JLAFKJWSCS']!
- .blocked = false;
-
- // rotate if too far in the past
- sess = await client.encryption!.keyManager
- .createOutboundGroupSession(roomId);
- sess.creationTime = DateTime.now().subtract(Duration(days: 30));
- await client.encryption!.keyManager
- .clearOrUseOutboundGroupSession(roomId);
- expect(
- client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
- false,
- );
-
- // rotate if user leaves
- sess = await client.encryption!.keyManager
- .createOutboundGroupSession(roomId);
- final room = client.getRoomById(roomId)!;
- final member = room.getState('m.room.member', '@alice:example.com');
- member!.content['membership'] = 'leave';
- room.summary.mJoinedMemberCount = room.summary.mJoinedMemberCount! - 1;
- await client.encryption!.keyManager
- .clearOrUseOutboundGroupSession(roomId);
- expect(
- client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
- false,
- );
- member.content['membership'] = 'join';
- room.summary.mJoinedMemberCount = room.summary.mJoinedMemberCount! + 1;
-
- // do not rotate if new device is added
- sess = await client.encryption!.keyManager
- .createOutboundGroupSession(roomId);
- sess.outboundGroupSession!.encrypt(
- 'foxies',
- ); // so that the new device will have a different index
- client.userDeviceKeys['@alice:example.com']?.deviceKeys['NEWDEVICE'] =
- DeviceKeys.fromJson(
- {
- 'user_id': '@alice:example.com',
- 'device_id': 'NEWDEVICE',
- 'algorithms': [
- AlgorithmTypes.olmV1Curve25519AesSha2,
- AlgorithmTypes.megolmV1AesSha2,
- ],
- 'keys': {
- 'curve25519:NEWDEVICE':
- 'bnKQp6pPW0l9cGoIgHpBoK5OUi4h0gylJ7upc4asFV8',
- 'ed25519:NEWDEVICE': 'ZZhPdvWYg3MRpGy2MwtI+4MHXe74wPkBli5hiEOUi8Y',
- },
- 'signatures': {
- '@alice:example.com': {
- 'ed25519:NEWDEVICE':
- '94GSg8N9vNB8wyWHJtKaaX3MGNWPVOjBatJM+TijY6B1RlDFJT5Cl1h/tjr17AoQz0CDdOf6uFhrYsBkH1/ABg',
- },
- },
- },
- client,
- );
- await client.encryption!.keyManager
- .clearOrUseOutboundGroupSession(roomId);
- expect(
- client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
- true,
- );
- inbound = client.encryption!.keyManager.getInboundGroupSession(
- roomId,
- sess.outboundGroupSession!.session_id(),
- );
- expect(
- inbound!.allowedAtIndex['@alice:example.com']
- ?['L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8'],
- 0,
- );
- expect(
- inbound.allowedAtIndex['@alice:example.com']
- ?['wMIDhiQl5jEXQrTB03ePOSQfR8sA/KMrW0CIfFfXKEE'],
- 0,
- );
- expect(
- inbound.allowedAtIndex['@alice:example.com']
- ?['bnKQp6pPW0l9cGoIgHpBoK5OUi4h0gylJ7upc4asFV8'],
- 1,
- );
-
- // do not rotate if new user is added
- member.content['membership'] = 'leave';
- room.summary.mJoinedMemberCount = room.summary.mJoinedMemberCount! - 1;
- sess = await client.encryption!.keyManager
- .createOutboundGroupSession(roomId);
- member.content['membership'] = 'join';
- room.summary.mJoinedMemberCount = room.summary.mJoinedMemberCount! + 1;
- await client.encryption!.keyManager
- .clearOrUseOutboundGroupSession(roomId);
- expect(
- client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
- true,
- );
-
- // force wipe
- sess = await client.encryption!.keyManager
- .createOutboundGroupSession(roomId);
- await client.encryption!.keyManager
- .clearOrUseOutboundGroupSession(roomId, wipe: true);
- expect(
- client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
- false,
- );
-
- // load from database
- sess = await client.encryption!.keyManager
- .createOutboundGroupSession(roomId);
- client.encryption!.keyManager.clearOutboundGroupSessions();
- expect(
- client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
- false,
- );
- await client.encryption!.keyManager.loadOutboundGroupSession(roomId);
- expect(
- client.encryption!.keyManager.getOutboundGroupSession(roomId) != null,
- true,
- );
- });
-
- test('inbound group session', () async {
- final roomId = '!726s6s6q:example.com';
- final sessionId = 'ciM/JWTPrmiWPPZNkRLDPQYf9AW/I46bxyLSr+Bx5oU';
- final senderKey = 'JBG7ZaPn54OBC7TuIEiylW3BZ+7WcGQhFBPB9pogbAg';
- final sessionContent = {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': '!726s6s6q:example.com',
- 'session_id': 'ciM/JWTPrmiWPPZNkRLDPQYf9AW/I46bxyLSr+Bx5oU',
- 'session_key':
- 'AgAAAAAQcQ6XrFJk6Prm8FikZDqfry/NbDz8Xw7T6e+/9Yf/q3YHIPEQlzv7IZMNcYb51ifkRzFejVvtphS7wwG2FaXIp4XS2obla14iKISR0X74ugB2vyb1AydIHE/zbBQ1ic5s3kgjMFlWpu/S3FQCnCrv+DPFGEt3ERGWxIl3Bl5X53IjPyVkz65oljz2TZESwz0GH/QFvyOOm8ci0q/gceaF3S7Dmafg3dwTKYwcA5xkcc+BLyrLRzB6Hn+oMAqSNSscnm4mTeT5zYibIhrzqyUTMWr32spFtI9dNR/RFSzfCw',
- };
- client.encryption!.keyManager.clearInboundGroupSessions();
- expect(
- client.encryption!.keyManager
- .getInboundGroupSession(roomId, sessionId) !=
- null,
- false,
- );
- await client.encryption!.keyManager
- .setInboundGroupSession(roomId, sessionId, senderKey, sessionContent);
- expect(
- client.encryption!.keyManager
- .getInboundGroupSession(roomId, sessionId) !=
- null,
- true,
- );
-
- expect(
- client.encryption!.keyManager
- .getInboundGroupSession(roomId, sessionId) !=
- null,
- true,
- );
-
- client.encryption!.keyManager.clearInboundGroupSessions();
- expect(
- client.encryption!.keyManager
- .getInboundGroupSession(roomId, sessionId) !=
- null,
- false,
- );
- await client.encryption!.keyManager
- .loadInboundGroupSession(roomId, sessionId);
- expect(
- client.encryption!.keyManager
- .getInboundGroupSession(roomId, sessionId) !=
- null,
- true,
- );
-
- client.encryption!.keyManager.clearInboundGroupSessions();
- expect(
- client.encryption!.keyManager
- .getInboundGroupSession(roomId, sessionId) !=
- null,
- false,
- );
- });
-
- test('setInboundGroupSession', () async {
- final session = olm.OutboundGroupSession();
- session.create();
- final inbound = olm.InboundGroupSession();
- inbound.create(session.session_key());
- final senderKey = client.identityKey;
- final roomId = '!someroom:example.org';
- final sessionId = inbound.session_id();
- final room = Room(id: roomId, client: client);
- final nextSyncUpdateFuture = client.onSync.stream
- .firstWhere((update) => update.rooms != null)
- .timeout(const Duration(seconds: 5));
- client.rooms.add(room);
- // we build up an encrypted message so that we can test if it successfully decrypted afterwards
- await client.handleSync(
- SyncUpdate(
- nextBatch: '',
- rooms: RoomsUpdate(
- join: {
- room.id: JoinedRoomUpdate(
- timeline: TimelineUpdate(
- events: [
- Event(
- senderId: '@test:example.com',
- type: 'm.room.encrypted',
- room: room,
- eventId: '12345',
- originServerTs: DateTime.now(),
- content: {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- '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: '',
- ),
- ],
- ),
- ),
- },
- ),
- ),
- );
- expect(room.lastEvent?.type, 'm.room.encrypted');
- // set a payload...
- var sessionPayload = {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': roomId,
- 'forwarding_curve25519_key_chain': [client.identityKey],
- 'session_id': sessionId,
- 'session_key': inbound.export_session(1),
- 'sender_key': senderKey,
- 'sender_claimed_ed25519_key': client.fingerprintKey,
- };
- await client.encryption!.keyManager.setInboundGroupSession(
- roomId,
- sessionId,
- senderKey,
- sessionPayload,
- forwarded: true,
- );
- expect(
- client.encryption!.keyManager
- .getInboundGroupSession(roomId, sessionId)
- ?.inboundGroupSession
- ?.first_known_index(),
- 1,
- );
- expect(
- client.encryption!.keyManager
- .getInboundGroupSession(roomId, sessionId)
- ?.forwardingCurve25519KeyChain
- .length,
- 1,
- );
-
- // not set one with a higher first known index
- sessionPayload = {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': roomId,
- 'forwarding_curve25519_key_chain': [client.identityKey],
- 'session_id': sessionId,
- 'session_key': inbound.export_session(2),
- 'sender_key': senderKey,
- 'sender_claimed_ed25519_key': client.fingerprintKey,
- };
- await client.encryption!.keyManager.setInboundGroupSession(
- roomId,
- sessionId,
- senderKey,
- sessionPayload,
- forwarded: true,
- );
- expect(
- client.encryption!.keyManager
- .getInboundGroupSession(roomId, sessionId)
- ?.inboundGroupSession
- ?.first_known_index(),
- 1,
- );
- expect(
- client.encryption!.keyManager
- .getInboundGroupSession(roomId, sessionId)
- ?.forwardingCurve25519KeyChain
- .length,
- 1,
- );
-
- // set one with a lower first known index
- sessionPayload = {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': roomId,
- 'forwarding_curve25519_key_chain': [client.identityKey],
- 'session_id': sessionId,
- 'session_key': inbound.export_session(0),
- 'sender_key': senderKey,
- 'sender_claimed_ed25519_key': client.fingerprintKey,
- };
- await client.encryption!.keyManager.setInboundGroupSession(
- roomId,
- sessionId,
- senderKey,
- sessionPayload,
- forwarded: true,
- );
- expect(
- client.encryption!.keyManager
- .getInboundGroupSession(roomId, sessionId)
- ?.inboundGroupSession
- ?.first_known_index(),
- 0,
- );
- expect(
- client.encryption!.keyManager
- .getInboundGroupSession(roomId, sessionId)
- ?.forwardingCurve25519KeyChain
- .length,
- 1,
- );
-
- // not set one with a longer forwarding chain
- sessionPayload = {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': roomId,
- 'forwarding_curve25519_key_chain': [client.identityKey, 'beep'],
- 'session_id': sessionId,
- 'session_key': inbound.export_session(0),
- 'sender_key': senderKey,
- 'sender_claimed_ed25519_key': client.fingerprintKey,
- };
- await client.encryption!.keyManager.setInboundGroupSession(
- roomId,
- sessionId,
- senderKey,
- sessionPayload,
- forwarded: true,
- );
- expect(
- client.encryption!.keyManager
- .getInboundGroupSession(roomId, sessionId)
- ?.inboundGroupSession
- ?.first_known_index(),
- 0,
- );
- expect(
- client.encryption!.keyManager
- .getInboundGroupSession(roomId, sessionId)
- ?.forwardingCurve25519KeyChain
- .length,
- 1,
- );
-
- // set one with a shorter forwarding chain
- sessionPayload = {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': roomId,
- 'forwarding_curve25519_key_chain': [],
- 'session_id': sessionId,
- 'session_key': inbound.export_session(0),
- 'sender_key': senderKey,
- 'sender_claimed_ed25519_key': client.fingerprintKey,
- };
- await client.encryption!.keyManager.setInboundGroupSession(
- roomId,
- sessionId,
- senderKey,
- sessionPayload,
- forwarded: true,
- );
- expect(
- client.encryption!.keyManager
- .getInboundGroupSession(roomId, sessionId)
- ?.inboundGroupSession
- ?.first_known_index(),
- 0,
- );
- expect(
- client.encryption!.keyManager
- .getInboundGroupSession(roomId, sessionId)
- ?.forwardingCurve25519KeyChain
- .length,
- 0,
- );
-
- // test that it decrypted the last event
- expect(room.lastEvent?.type, 'm.room.message');
- expect(room.lastEvent?.content['body'], 'foxies');
-
- // test if a fake sync has been performed to update the GUI and store the
- // decrypted last event
- final syncUpdate = await nextSyncUpdateFuture;
- expect(syncUpdate.rooms?.join?.containsKey(room.id), true);
-
- inbound.free();
- session.free();
- });
-
- test('Reused deviceID attack', () async {
- Logs().level = Level.warning;
-
- // Ensure the device came from sync
- expect(
- client.userDeviceKeys['@alice:example.com']?.deviceKeys['JLAFKJWSCS'] !=
- null,
- true,
- );
-
- // Alice removes her device
- client.userDeviceKeys['@alice:example.com']?.deviceKeys
- .remove('JLAFKJWSCS');
-
- // Alice adds her device with same device ID but different keys
- final oldResp =
- FakeMatrixApi.currentApi?.api['POST']?['/client/v3/keys/query'](null);
- FakeMatrixApi.currentApi?.api['POST']?['/client/v3/keys/query'] = (_) {
- oldResp['device_keys']['@alice:example.com']['JLAFKJWSCS'] = {
- 'user_id': '@alice:example.com',
- 'device_id': 'JLAFKJWSCS',
- 'algorithms': [
- 'm.olm.v1.curve25519-aes-sha2',
- 'm.megolm.v1.aes-sha2',
- ],
- 'keys': {
- 'curve25519:JLAFKJWSCS':
- 'WbwrNyD7nvtmcLQ0TTuVPFGJq6JznfjrVsjIpmBqvDw',
- 'ed25519:JLAFKJWSCS': 'vl0d54pTVRcvBgUzoQFa8e6TldHWG9O8bh0iuIvgd/I',
- },
- 'signatures': {
- '@alice:example.com': {
- 'ed25519:JLAFKJWSCS':
- 's/L86jLa8BTroL8GsBeqO0gRLC3ZrSA7Gch6UoLI2SefC1+1ycmnP9UGbLPh3qBJOmlhczMpBLZwelg87qNNDA',
- },
- },
- };
- return oldResp;
- };
- client.userDeviceKeys['@alice:example.com']!.outdated = true;
- await client.updateUserDeviceKeys();
- expect(
- client.userDeviceKeys['@alice:example.com']?.deviceKeys['JLAFKJWSCS'],
- null,
- );
- });
-
- test('dispose client', () async {
- await client.dispose(closeDatabase: false);
- });
- });
-}
diff --git a/test/encryption/key_request_test.dart b/test/encryption/key_request_test.dart
deleted file mode 100644
index fb0af33a..00000000
--- a/test/encryption/key_request_test.dart
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- * Famedly Matrix SDK
- * Copyright (C) 2020 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
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-import 'dart:convert';
-
-import 'package:olm/olm.dart' as olm;
-import 'package:test/test.dart';
-
-import 'package:matrix/matrix.dart';
-import '../fake_client.dart';
-
-Map jsonDecode(dynamic payload) {
- if (payload is String) {
- try {
- return json.decode(payload);
- } catch (e) {
- return {};
- }
- }
- if (payload is Map) return payload;
- return {};
-}
-
-void main() {
- /// All Tests related to device keys
- group('Key Request', tags: 'olm', () {
- Logs().level = Level.error;
-
- setUpAll(() async {
- await olm.init();
- olm.get_library_version();
- });
-
- final validSessionId = 'ciM/JWTPrmiWPPZNkRLDPQYf9AW/I46bxyLSr+Bx5oU';
- final validSenderKey = 'JBG7ZaPn54OBC7TuIEiylW3BZ+7WcGQhFBPB9pogbAg';
- test('Create Request', () async {
- final matrix = await getClient();
- final requestRoom = matrix.getRoomById('!726s6s6q:example.com')!;
- await matrix.encryption!.keyManager.request(
- requestRoom,
- 'sessionId',
- validSenderKey,
- tryOnlineBackup: false,
- );
- var foundEvent = false;
- for (final entry in FakeMatrixApi.calledEndpoints.entries) {
- final payload = jsonDecode(entry.value.first);
- if (entry.key
- .startsWith('/client/v3/sendToDevice/m.room_key_request') &&
- (payload['messages'] is Map) &&
- (payload['messages']['@alice:example.com'] is Map) &&
- (payload['messages']['@alice:example.com']['*'] is Map)) {
- final content = payload['messages']['@alice:example.com']['*'];
- if (content['action'] == 'request' &&
- content['body']['room_id'] == '!726s6s6q:example.com' &&
- content['body']['session_id'] == 'sessionId') {
- foundEvent = true;
- break;
- }
- }
- }
- expect(foundEvent, true);
- await matrix.dispose(closeDatabase: true);
- });
- test('Reply To Request', () async {
- final matrix = await getClient();
- await matrix.abortSync();
-
- matrix.setUserId('@alice:example.com'); // we need to pretend to be alice
- FakeMatrixApi.calledEndpoints.clear();
- await matrix
- .userDeviceKeys['@alice:example.com']!.deviceKeys['OTHERDEVICE']!
- .setBlocked(false);
- await matrix
- .userDeviceKeys['@alice:example.com']!.deviceKeys['OTHERDEVICE']!
- .setVerified(true);
- final session = await matrix.encryption!.keyManager
- .loadInboundGroupSession('!726s6s6q:example.com', validSessionId);
- // test a successful share
- var event = ToDeviceEvent(
- sender: '@alice:example.com',
- type: 'm.room_key_request',
- content: {
- 'action': 'request',
- 'body': {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': '!726s6s6q:example.com',
- 'sender_key': validSenderKey,
- 'session_id': validSessionId,
- },
- 'request_id': 'request_1',
- 'requesting_device_id': 'OTHERDEVICE',
- },
- );
- await matrix.encryption!.keyManager.handleToDeviceEvent(event);
- Logs().i(FakeMatrixApi.calledEndpoints.keys.toString());
- expect(
- FakeMatrixApi.calledEndpoints.keys.any(
- (k) => k.startsWith('/client/v3/sendToDevice/m.room.encrypted'),
- ),
- true,
- );
-
- // test a successful foreign share
- FakeMatrixApi.calledEndpoints.clear();
- session!.allowedAtIndex['@test:fakeServer.notExisting'] = {
- matrix.userDeviceKeys['@test:fakeServer.notExisting']!
- .deviceKeys['OTHERDEVICE']!.curve25519Key!: 0,
- };
- event = ToDeviceEvent(
- sender: '@test:fakeServer.notExisting',
- type: 'm.room_key_request',
- content: {
- 'action': 'request',
- 'body': {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': '!726s6s6q:example.com',
- 'sender_key': validSenderKey,
- 'session_id': validSessionId,
- },
- 'request_id': 'request_a1',
- 'requesting_device_id': 'OTHERDEVICE',
- },
- );
- await matrix.encryption!.keyManager.handleToDeviceEvent(event);
- Logs().i(FakeMatrixApi.calledEndpoints.keys.toString());
- expect(
- FakeMatrixApi.calledEndpoints.keys.any(
- (k) => k.startsWith('/client/v3/sendToDevice/m.room.encrypted'),
- ),
- true,
- );
- session.allowedAtIndex.remove('@test:fakeServer.notExisting');
-
- // test various fail scenarios
-
- // unknown person
- FakeMatrixApi.calledEndpoints.clear();
- event = ToDeviceEvent(
- sender: '@test:fakeServer.notExisting',
- type: 'm.room_key_request',
- content: {
- 'action': 'request',
- 'body': {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': '!726s6s6q:example.com',
- 'sender_key': validSenderKey,
- 'session_id': validSessionId,
- },
- 'request_id': 'request_a2',
- 'requesting_device_id': 'OTHERDEVICE',
- },
- );
- await matrix.encryption!.keyManager.handleToDeviceEvent(event);
- Logs().i(FakeMatrixApi.calledEndpoints.keys.toString());
- expect(
- FakeMatrixApi.calledEndpoints.keys.any(
- (k) => k.startsWith('/client/v3/sendToDevice/m.room.encrypted'),
- ),
- false,
- );
-
- // no body
- FakeMatrixApi.calledEndpoints.clear();
- event = ToDeviceEvent(
- sender: '@alice:example.com',
- type: 'm.room_key_request',
- content: {
- 'action': 'request',
- 'request_id': 'request_2',
- 'requesting_device_id': 'OTHERDEVICE',
- },
- );
- await matrix.encryption!.keyManager.handleToDeviceEvent(event);
- expect(
- FakeMatrixApi.calledEndpoints.keys.any(
- (k) => k.startsWith('/client/v3/sendToDevice/m.room.encrypted'),
- ),
- false,
- );
-
- // request by ourself
- FakeMatrixApi.calledEndpoints.clear();
- event = ToDeviceEvent(
- sender: '@alice:example.com',
- type: 'm.room_key_request',
- content: {
- 'action': 'request',
- 'body': {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': '!726s6s6q:example.com',
- 'sender_key': validSenderKey,
- 'session_id': validSessionId,
- },
- 'request_id': 'request_3',
- 'requesting_device_id': 'JLAFKJWSCS',
- },
- );
- await matrix.encryption!.keyManager.handleToDeviceEvent(event);
- expect(
- FakeMatrixApi.calledEndpoints.keys.any(
- (k) => k.startsWith('/client/v3/sendToDevice/m.room.encrypted'),
- ),
- false,
- );
-
- // device not found
- FakeMatrixApi.calledEndpoints.clear();
- event = ToDeviceEvent(
- sender: '@alice:example.com',
- type: 'm.room_key_request',
- content: {
- 'action': 'request',
- 'body': {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': '!726s6s6q:example.com',
- 'sender_key': validSenderKey,
- 'session_id': validSessionId,
- },
- 'request_id': 'request_4',
- 'requesting_device_id': 'blubb',
- },
- );
- await matrix.encryption!.keyManager.handleToDeviceEvent(event);
- expect(
- FakeMatrixApi.calledEndpoints.keys.any(
- (k) => k.startsWith('/client/v3/sendToDevice/m.room.encrypted'),
- ),
- false,
- );
-
- // unknown room
- FakeMatrixApi.calledEndpoints.clear();
- event = ToDeviceEvent(
- sender: '@alice:example.com',
- type: 'm.room_key_request',
- content: {
- 'action': 'request',
- 'body': {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': '!invalid:example.com',
- 'sender_key': validSenderKey,
- 'session_id': validSessionId,
- },
- 'request_id': 'request_5',
- 'requesting_device_id': 'OTHERDEVICE',
- },
- );
- await matrix.encryption!.keyManager.handleToDeviceEvent(event);
- expect(
- FakeMatrixApi.calledEndpoints.keys.any(
- (k) => k.startsWith('/client/v3/sendToDevice/m.room.encrypted'),
- ),
- false,
- );
-
- // unknwon session
- FakeMatrixApi.calledEndpoints.clear();
- event = ToDeviceEvent(
- sender: '@alice:example.com',
- type: 'm.room_key_request',
- content: {
- 'action': 'request',
- 'body': {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': '!726s6s6q:example.com',
- 'sender_key': validSenderKey,
- 'session_id': 'invalid',
- },
- 'request_id': 'request_6',
- 'requesting_device_id': 'OTHERDEVICE',
- },
- );
- await matrix.encryption!.keyManager.handleToDeviceEvent(event);
- expect(
- FakeMatrixApi.calledEndpoints.keys.any(
- (k) => k.startsWith('/client/v3/sendToDevice/m.room.encrypted'),
- ),
- false,
- );
-
- FakeMatrixApi.calledEndpoints.clear();
- await matrix.dispose(closeDatabase: true);
- });
- test('Receive shared keys', () async {
- final matrix = await getClient();
- final requestRoom = matrix.getRoomById('!726s6s6q:example.com')!;
- await matrix.encryption!.keyManager.request(
- requestRoom,
- validSessionId,
- validSenderKey,
- tryOnlineBackup: false,
- );
-
- final session = (await matrix.encryption!.keyManager
- .loadInboundGroupSession(requestRoom.id, validSessionId))!;
- final sessionKey = session.inboundGroupSession!
- .export_session(session.inboundGroupSession!.first_known_index());
- matrix.encryption!.keyManager.clearInboundGroupSessions();
- var event = ToDeviceEvent(
- sender: '@alice:example.com',
- type: 'm.forwarded_room_key',
- content: {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': '!726s6s6q:example.com',
- 'session_id': validSessionId,
- 'session_key': sessionKey,
- 'sender_key': validSenderKey,
- 'forwarding_curve25519_key_chain': [],
- 'sender_claimed_ed25519_key':
- 'L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8',
- },
- encryptedContent: {
- 'sender_key': 'L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8',
- },
- );
- await matrix.encryption!.keyManager.handleToDeviceEvent(event);
- expect(
- matrix.encryption!.keyManager
- .getInboundGroupSession(requestRoom.id, validSessionId) !=
- null,
- true,
- );
-
- // test ToDeviceEvent without sender_key in content
- event = ToDeviceEvent(
- sender: '@alice:example.com',
- type: 'm.forwarded_room_key',
- content: {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': '!726s6s6q:example.com',
- 'session_id': validSessionId,
- 'session_key': sessionKey,
- 'forwarding_curve25519_key_chain': [],
- 'sender_claimed_ed25519_key':
- 'L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8',
- },
- encryptedContent: {
- 'sender_key': 'L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8',
- },
- );
-
- // now test a few invalid scenarios
-
- // request not found
- matrix.encryption!.keyManager.clearInboundGroupSessions();
- event = ToDeviceEvent(
- sender: '@alice:example.com',
- type: 'm.forwarded_room_key',
- content: {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': '!726s6s6q:example.com',
- 'session_id': validSessionId,
- 'session_key': sessionKey,
- 'sender_key': validSenderKey,
- 'forwarding_curve25519_key_chain': [],
- 'sender_claimed_ed25519_key':
- 'L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8',
- },
- encryptedContent: {
- 'sender_key': 'L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8',
- },
- );
- await matrix.encryption!.keyManager.handleToDeviceEvent(event);
- expect(
- matrix.encryption!.keyManager
- .getInboundGroupSession(requestRoom.id, validSessionId) !=
- null,
- false,
- );
-
- // unknown device
- await matrix.encryption!.keyManager
- .request(requestRoom, validSessionId, null, tryOnlineBackup: false);
- matrix.encryption!.keyManager.clearInboundGroupSessions();
- event = ToDeviceEvent(
- sender: '@alice:example.com',
- type: 'm.forwarded_room_key',
- content: {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': '!726s6s6q:example.com',
- 'session_id': validSessionId,
- 'session_key': sessionKey,
- 'sender_key': validSenderKey,
- 'forwarding_curve25519_key_chain': [],
- 'sender_claimed_ed25519_key':
- 'L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8',
- },
- encryptedContent: {
- 'sender_key': 'invalid',
- },
- );
- await matrix.encryption!.keyManager.handleToDeviceEvent(event);
- expect(
- matrix.encryption!.keyManager
- .getInboundGroupSession(requestRoom.id, validSessionId) !=
- null,
- false,
- );
-
- // no encrypted content
- await matrix.encryption!.keyManager.request(
- requestRoom,
- validSessionId,
- validSenderKey,
- tryOnlineBackup: false,
- );
- matrix.encryption!.keyManager.clearInboundGroupSessions();
- event = ToDeviceEvent(
- sender: '@alice:example.com',
- type: 'm.forwarded_room_key',
- content: {
- 'algorithm': AlgorithmTypes.megolmV1AesSha2,
- 'room_id': '!726s6s6q:example.com',
- 'session_id': validSessionId,
- 'session_key': sessionKey,
- 'sender_key': validSenderKey,
- 'forwarding_curve25519_key_chain': [],
- 'sender_claimed_ed25519_key':
- 'L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8',
- },
- );
- await matrix.encryption!.keyManager.handleToDeviceEvent(event);
- expect(
- matrix.encryption!.keyManager
- .getInboundGroupSession(requestRoom.id, validSessionId) !=
- null,
- false,
- );
-
- // There is a non awaiting setInboundGroupSession call on the database
- await Future.delayed(Duration(seconds: 1));
-
- await matrix.dispose(closeDatabase: true);
- });
- });
-}