diff --git a/lib/src/client.dart b/lib/src/client.dart index 6e324e84..f2b4fafa 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -1135,7 +1135,7 @@ class Client { var outdatedLists = {}; for (var userId in trackedUserIds) { if (!userDeviceKeys.containsKey(userId)) { - _userDeviceKeys[userId] = DeviceKeysList(userId); + _userDeviceKeys[userId] = DeviceKeysList(userId, this); } var deviceKeysList = userDeviceKeys[userId]; if (deviceKeysList.outdated) { @@ -1151,7 +1151,7 @@ class Client { for (final rawDeviceKeyListEntry in response.deviceKeys.entries) { final userId = rawDeviceKeyListEntry.key; if (!userDeviceKeys.containsKey(userId)) { - _userDeviceKeys[userId] = DeviceKeysList(userId); + _userDeviceKeys[userId] = DeviceKeysList(userId, this); } final oldKeys = Map.from(_userDeviceKeys[userId].deviceKeys); @@ -1230,7 +1230,7 @@ class Client { for (final crossSigningKeyListEntry in keys.entries) { final userId = crossSigningKeyListEntry.key; if (!userDeviceKeys.containsKey(userId)) { - _userDeviceKeys[userId] = DeviceKeysList(userId); + _userDeviceKeys[userId] = DeviceKeysList(userId, this); } final oldKeys = Map.from( _userDeviceKeys[userId].crossSigningKeys); diff --git a/lib/src/utils/device_keys_list.dart b/lib/src/utils/device_keys_list.dart index c32f713b..7e4b08fc 100644 --- a/lib/src/utils/device_keys_list.dart +++ b/lib/src/utils/device_keys_list.dart @@ -54,6 +54,8 @@ class DeviceKeysList { } Future startVerification() async { + print('++++++++++++'); + print(client.toString()); final roomId = await User(userId, room: Room(client: client)).startDirectChat(); if (roomId == null) { @@ -95,7 +97,7 @@ class DeviceKeysList { } } - DeviceKeysList(this.userId); + DeviceKeysList(this.userId, this.client); } abstract class SignableKey extends MatrixSignableKey { @@ -239,7 +241,8 @@ abstract class SignableKey extends MatrixSignableKey { Future setVerified(bool newVerified, [bool sign = true]) { _verified = newVerified; - if (sign && + if (newVerified && + sign && client.encryptionEnabled && client.encryption.crossSigning.signable([this])) { // sign the key! diff --git a/test/device_keys_list_test.dart b/test/device_keys_list_test.dart index c1f32042..a98ff1b6 100644 --- a/test/device_keys_list_test.dart +++ b/test/device_keys_list_test.dart @@ -20,6 +20,10 @@ import 'dart:convert'; import 'package:famedlysdk/famedlysdk.dart'; import 'package:test/test.dart'; +import 'package:olm/olm.dart' as olm; + +import './fake_client.dart'; +import './fake_matrix_api.dart'; void main() { /// All Tests related to device keys @@ -49,6 +53,125 @@ void main() { expect(json.encode(key.toJson()), json.encode(rawJson)); expect(key.directVerified, false); expect(key.blocked, true); + + rawJson = { + 'user_id': '@test:fakeServer.notExisting', + 'usage': ['master'], + 'keys': { + 'ed25519:82mAXjsmbTbrE6zyShpR869jnrANO75H8nYY0nDLoJ8': + '82mAXjsmbTbrE6zyShpR869jnrANO75H8nYY0nDLoJ8', + }, + 'signatures': {}, + }; + final crossKey = CrossSigningKey.fromJson(rawJson, null); + expect(json.encode(crossKey.toJson()), json.encode(rawJson)); + expect(crossKey.usage.first, 'master'); + }); + + var olmEnabled = true; + try { + olm.init(); + olm.Account(); + } catch (_) { + olmEnabled = false; + print('[LibOlm] Failed to load LibOlm: ' + _.toString()); + } + print('[LibOlm] Enabled: $olmEnabled'); + + if (!olmEnabled) return; + + Client client; + + test('setupClient', () async { + client = await getClient(); + }); + + test('set blocked / verified', () async { + final key = + client.userDeviceKeys[client.userID].deviceKeys['OTHERDEVICE']; + final masterKey = client.userDeviceKeys[client.userID].masterKey; + masterKey.setDirectVerified(true); + // we need to populate the ssss cache to be able to test signing easily + final handle = client.encryption.ssss.open(); + handle.unlock(recoveryKey: SSSS_KEY); + await handle.maybeCacheAll(); + + expect(key.verified, true); + await key.setBlocked(true); + expect(key.verified, false); + await key.setBlocked(false); + expect(key.directVerified, false); + expect(key.verified, true); // still verified via cross-sgining + + expect(masterKey.verified, true); + await masterKey.setBlocked(true); + expect(masterKey.verified, false); + await masterKey.setBlocked(false); + expect(masterKey.verified, true); + + FakeMatrixApi.calledEndpoints.clear(); + await key.setVerified(true); + await Future.delayed(Duration(milliseconds: 10)); + expect( + FakeMatrixApi.calledEndpoints.keys + .any((k) => k == '/client/r0/keys/signatures/upload'), + true); + expect(key.directVerified, true); + + FakeMatrixApi.calledEndpoints.clear(); + await key.setVerified(false); + await Future.delayed(Duration(milliseconds: 10)); + expect( + FakeMatrixApi.calledEndpoints.keys + .any((k) => k == '/client/r0/keys/signatures/upload'), + false); + expect(key.directVerified, false); + }); + + test('verification based on signatures', () async { + final user = client.userDeviceKeys[client.userID]; + user.masterKey.setDirectVerified(true); + expect(user.deviceKeys['GHTYAJCE'].crossVerified, true); + expect(user.deviceKeys['GHTYAJCE'].signed, true); + expect(user.getKey('GHTYAJCE').crossVerified, true); + expect(user.deviceKeys['OTHERDEVICE'].crossVerified, true); + expect(user.selfSigningKey.crossVerified, true); + expect( + user + .getKey('F9ypFzgbISXCzxQhhSnXMkc1vq12Luna3Nw5rqViOJY') + .crossVerified, + true); + expect(user.userSigningKey.crossVerified, true); + expect(user.verified, UserVerifiedStatus.verified); + user.masterKey.setDirectVerified(false); + expect(user.deviceKeys['GHTYAJCE'].crossVerified, false); + expect(user.deviceKeys['OTHERDEVICE'].crossVerified, false); + expect(user.verified, UserVerifiedStatus.unknown); + user.masterKey.setDirectVerified(true); + user.deviceKeys['GHTYAJCE'].signatures.clear(); + expect(user.deviceKeys['GHTYAJCE'].verified, + true); // it's our own device, should be direct verified + expect( + user.deviceKeys['GHTYAJCE'].signed, false); // not verified for others + user.deviceKeys['OTHERDEVICE'].signatures.clear(); + expect(user.verified, UserVerifiedStatus.unknownDevice); + }); + + test('start verification', () async { + var req = client + .userDeviceKeys['@alice:example.com'].deviceKeys['JLAFKJWSCS'] + .startVerification(); + expect(req != null, true); + expect(req.room != null, false); + + req = + await client.userDeviceKeys['@alice:example.com'].startVerification(); + expect(req != null, true); + expect(req.room != null, true); + }); + + test('dispose client', () async { + await client.dispose(closeDatabase: true); }); }); } diff --git a/test/fake_matrix_api.dart b/test/fake_matrix_api.dart index 322b2b71..4c022583 100644 --- a/test/fake_matrix_api.dart +++ b/test/fake_matrix_api.dart @@ -1799,7 +1799,12 @@ class FakeMatrixApi extends MockClient { 'ed25519:GHTYAJCE': 'gjL//fyaFHADt9KBADGag8g7F8Up78B/K1zXeiEPLJo' }, - 'signatures': {}, + 'signatures': { + '@test:fakeServer.notExisting': { + 'ed25519:F9ypFzgbISXCzxQhhSnXMkc1vq12Luna3Nw5rqViOJY': + 'Q4/55vZjEJD7M2EC40bgZqd9Zuy/4C75UPVopJdXeioQVaKtFf6EF0nUUuql0yD+r3hinsZcock0wO6Q2xcoAQ', + }, + }, }, 'OTHERDEVICE': { 'user_id': '@test:fakeServer.notExisting', @@ -1812,7 +1817,12 @@ class FakeMatrixApi extends MockClient { 'curve25519:OTHERDEVICE': 'blah', 'ed25519:OTHERDEVICE': 'blah' }, - 'signatures': {}, + 'signatures': { + '@test:fakeServer.notExisting': { + 'ed25519:F9ypFzgbISXCzxQhhSnXMkc1vq12Luna3Nw5rqViOJY': + 'o7ucKPWrF2VKx7wYqP1f+aw4QohLMz7kX+SIw6aWCYsLC3XyIlg8rX/7QQ9B8figCVnRK7IjtjWvQodBCfWCAA', + }, + }, }, }, '@othertest:fakeServer.notExisting': { @@ -1860,7 +1870,12 @@ class FakeMatrixApi extends MockClient { 'ed25519:F9ypFzgbISXCzxQhhSnXMkc1vq12Luna3Nw5rqViOJY': 'F9ypFzgbISXCzxQhhSnXMkc1vq12Luna3Nw5rqViOJY', }, - 'signatures': {}, + 'signatures': { + '@test:fakeServer.notExisting': { + 'ed25519:82mAXjsmbTbrE6zyShpR869jnrANO75H8nYY0nDLoJ8': + 'afkrbGvPn5Zb5zc7Lk9cz2skI3QrzI/L0st1GS+/GATxNjMzc6vKmGu7r9cMb1GJxy4RdeUpfH3L7Fs/fNL1Dw', + }, + }, }, '@othertest:fakeServer.notExisting': { 'user_id': '@othertest:fakeServer.notExisting', @@ -1879,7 +1894,12 @@ class FakeMatrixApi extends MockClient { 'ed25519:0PiwulzJ/RU86LlzSSZ8St80HUMN3dqjKa/orIJoA0g': '0PiwulzJ/RU86LlzSSZ8St80HUMN3dqjKa/orIJoA0g', }, - 'signatures': {}, + 'signatures': { + '@test:fakeServer.notExisting': { + 'ed25519:82mAXjsmbTbrE6zyShpR869jnrANO75H8nYY0nDLoJ8': + 'pvgbZxEbllaElhpiRnb7/uOIUhrglvHCFnpoxr3/5ZrWa0EK/uaefhex9eEV4uBLrHjHg2ymwdNaM7ap9+sBBg', + }, + }, }, '@othertest:fakeServer.notExisting': { 'user_id': '@othertest:fakeServer.notExisting',