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