From 092ce36410f5d3cb7c581ac1d9e0404c5655bbea Mon Sep 17 00:00:00 2001 From: "Alexander \"PapaTutuWawa" Date: Sun, 1 Jan 2023 16:49:19 +0100 Subject: [PATCH] feat: Add last features for use in moxxmpp --- lib/src/double_ratchet/double_ratchet.dart | 7 ++ lib/src/keys.dart | 3 - lib/src/omemo/device.dart | 34 ++++--- lib/src/omemo/events.dart | 2 +- lib/src/omemo/omemomanager.dart | 112 +++++++++++++++++---- lib/src/omemo/sessionmanager.dart | 10 +- lib/src/omemo/stanza.dart | 2 +- lib/src/trust/always.dart | 3 + lib/src/trust/base.dart | 3 + lib/src/trust/btbv.dart | 8 ++ lib/src/trust/never.dart | 3 + test/omemo_test.dart | 4 +- test/omemomanager_test.dart | 109 ++++++++++++-------- test/serialisation_test.dart | 4 +- 14 files changed, 216 insertions(+), 88 deletions(-) diff --git a/lib/src/double_ratchet/double_ratchet.dart b/lib/src/double_ratchet/double_ratchet.dart index f0f11a7..cc6996f 100644 --- a/lib/src/double_ratchet/double_ratchet.dart +++ b/lib/src/double_ratchet/double_ratchet.dart @@ -1,5 +1,6 @@ import 'dart:convert'; import 'package:cryptography/cryptography.dart'; +import 'package:hex/hex.dart'; import 'package:meta/meta.dart'; import 'package:omemo_dart/src/crypto.dart'; import 'package:omemo_dart/src/double_ratchet/crypto.dart'; @@ -251,6 +252,12 @@ class OmemoDoubleRatchet { 'kex': kex, }; } + + /// Returns the OMEMO compatible fingerprint of the ratchet session. + Future getOmemoFingerprint() async { + final curveKey = await ik.toCurve25519(); + return HEX.encode(await curveKey.getBytes()); + } Future?> _trySkippedMessageKeys(OmemoMessage header, List ciphertext) async { final key = SkippedKey( diff --git a/lib/src/keys.dart b/lib/src/keys.dart index b15a0b8..1731f8e 100644 --- a/lib/src/keys.dart +++ b/lib/src/keys.dart @@ -9,7 +9,6 @@ const privateKeyLength = 32; const publicKeyLength = 32; class OmemoPublicKey { - const OmemoPublicKey(this._pubkey); factory OmemoPublicKey.fromBytes(List bytes, KeyPairType type) { @@ -55,7 +54,6 @@ class OmemoPublicKey { } class OmemoPrivateKey { - const OmemoPrivateKey(this._privkey, this.type); final List _privkey; final KeyPairType type; @@ -85,7 +83,6 @@ class OmemoPrivateKey { /// A generic wrapper class for both Ed25519 and X25519 keypairs class OmemoKeyPair { - const OmemoKeyPair(this.pk, this.sk, this.type); /// Create an OmemoKeyPair just from a [type] and the bytes of the private and public diff --git a/lib/src/omemo/device.dart b/lib/src/omemo/device.dart index 2a92b00..4a8ab6d 100644 --- a/lib/src/omemo/device.dart +++ b/lib/src/omemo/device.dart @@ -1,5 +1,6 @@ import 'dart:convert'; import 'package:cryptography/cryptography.dart'; +import 'package:hex/hex.dart'; import 'package:meta/meta.dart'; import 'package:omemo_dart/src/helpers.dart'; import 'package:omemo_dart/src/keys.dart'; @@ -8,8 +9,8 @@ import 'package:omemo_dart/src/x3dh/x3dh.dart'; /// This class represents an OmemoBundle but with all keypairs belonging to the keys @immutable -class Device { - const Device( +class OmemoDevice { + const OmemoDevice( this.jid, this.id, this.ik, @@ -22,7 +23,7 @@ class Device { ); /// Deserialize the Device - factory Device.fromJson(Map data) { + factory OmemoDevice.fromJson(Map data) { // NOTE: We use the way OpenSSH names their keys, meaning that ik is the Identity // Keypair's private key, while ik_pub refers to the Identity Keypair's public // key. @@ -66,7 +67,7 @@ class Device { ), ); - return Device( + return OmemoDevice( data['jid']! as String, data['id']! as int, OmemoKeyPair.fromBytes( @@ -92,7 +93,7 @@ class Device { } /// Generate a completely new device, i.e. cryptographic identity. - static Future generateNewDevice(String jid, { int opkAmount = 100 }) async { + static Future generateNewDevice(String jid, { int opkAmount = 100 }) async { final id = generateRandom32BitNumber(); final ik = await OmemoKeyPair.generateNewPair(KeyPairType.ed25519); final spk = await OmemoKeyPair.generateNewPair(KeyPairType.x25519); @@ -104,7 +105,7 @@ class Device { opks[i] = await OmemoKeyPair.generateNewPair(KeyPairType.x25519); } - return Device(jid, id, ik, spk, spkId, signature, null, null, opks); + return OmemoDevice(jid, id, ik, spk, spkId, signature, null, null, opks); } /// Our bare Jid @@ -134,10 +135,10 @@ class Device { /// This replaces the Onetime-Prekey with id [id] with a completely new one. Returns /// a new Device object that copies over everything but replaces said key. @internal - Future replaceOnetimePrekey(int id) async { + Future replaceOnetimePrekey(int id) async { opks[id] = await OmemoKeyPair.generateNewPair(KeyPairType.x25519); - return Device( + return OmemoDevice( jid, this.id, ik, @@ -153,12 +154,12 @@ class Device { /// This replaces the Signed-Prekey with a completely new one. Returns a new Device object /// that copies over everything but replaces the Signed-Prekey and its signature. @internal - Future replaceSignedPrekey() async { + Future replaceSignedPrekey() async { final newSpk = await OmemoKeyPair.generateNewPair(KeyPairType.x25519); final newSpkId = generateRandom32BitNumber(); final newSignature = await sig(ik, await newSpk.pk.getBytes()); - return Device( + return OmemoDevice( jid, id, ik, @@ -174,8 +175,8 @@ class Device { /// Returns a new device that is equal to this one with the exception that the new /// device's id is a new number between 0 and 2**32 - 1. @internal - Device withNewId() { - return Device( + OmemoDevice withNewId() { + return OmemoDevice( jid, generateRandom32BitNumber(), ik, @@ -207,6 +208,13 @@ class Device { ); } + /// Returns the fingerprint of the current device + Future getFingerprint() async { + // Since the local key is Ed25519, we must convert it to Curve25519 first + final curveKey = await ik.pk.toCurve25519(); + return HEX.encode(await curveKey.getBytes()); + } + /// Serialise the device information. Future> toJson() async { /// Serialise the OPKs @@ -236,7 +244,7 @@ class Device { } @visibleForTesting - Future equals(Device other) async { + Future equals(OmemoDevice other) async { var opksMatch = true; if (opks.length != other.opks.length) { opksMatch = false; diff --git a/lib/src/omemo/events.dart b/lib/src/omemo/events.dart index cf075ce..12ffa4e 100644 --- a/lib/src/omemo/events.dart +++ b/lib/src/omemo/events.dart @@ -31,5 +31,5 @@ class DeviceListModifiedEvent extends OmemoEvent { /// and thus should be republished. class DeviceModifiedEvent extends OmemoEvent { DeviceModifiedEvent(this.device); - final Device device; + final OmemoDevice device; } diff --git a/lib/src/omemo/omemomanager.dart b/lib/src/omemo/omemomanager.dart index b4bb606..bf99a49 100644 --- a/lib/src/omemo/omemomanager.dart +++ b/lib/src/omemo/omemomanager.dart @@ -38,9 +38,10 @@ class OmemoManager { OmemoManager( this._device, this._trustManager, - this.sendEmptyOmemoMessage, - this.fetchDeviceList, - this.fetchDeviceBundle, + this.sendEmptyOmemoMessageImpl, + this.fetchDeviceListImpl, + this.fetchDeviceBundleImpl, + this.subscribeToDeviceListNodeImpl, ); final Logger _log = Logger('OmemoManager'); @@ -49,14 +50,17 @@ class OmemoManager { /// Send an empty OMEMO:2 message using the encrypted payload @result to /// @recipientJid. - final Future Function(EncryptionResult result, String recipientJid) sendEmptyOmemoMessage; + final Future Function(EncryptionResult result, String recipientJid) sendEmptyOmemoMessageImpl; /// Fetch the list of device ids associated with @jid. If the device list cannot be /// fetched, return null. - final Future?> Function(String jid) fetchDeviceList; + final Future?> Function(String jid) fetchDeviceListImpl; /// Fetch the device bundle for the device with id @id of jid. If it cannot be fetched, return null. - final Future Function(String jid, int id) fetchDeviceBundle; + final Future Function(String jid, int id) fetchDeviceBundleImpl; + + /// Subscribe to the device list PEP node of @jid. + final Future Function(String jid) subscribeToDeviceListNodeImpl; /// Map bare JID to its known devices Map> _deviceList = {}; @@ -65,6 +69,8 @@ class OmemoManager { /// Map bare a ratchet key to its ratchet. Note that this is also locked by /// _ratchetCriticalSectionLock. Map _ratchetMap = {}; + /// Map bare JID to whether we already tried to subscribe to the device list node. + final Map _subscriptionMap = {}; /// For preventing a race condition in encryption/decryption final Map>> _ratchetCriticalSectionQueue = {}; final Lock _ratchetCriticalSectionLock = Lock(); @@ -76,10 +82,11 @@ class OmemoManager { /// Our own keys... final Lock _deviceLock = Lock(); // ignore: prefer_final_fields - Device _device; + OmemoDevice _device; /// The event bus of the session manager final StreamController _eventStreamController = StreamController.broadcast(); + Stream get eventStream => _eventStreamController.stream; /// Enter the critical section for performing cryptographic operations on the ratchets Future _enterRatchetCriticalSection(String jid) async { @@ -379,7 +386,7 @@ class OmemoManager { List bundlesToFetch; if (!_deviceListRequested.containsKey(jid) || !_deviceList.containsKey(jid)) { // We don't have an up-to-date version of the device list - final newDeviceList = await fetchDeviceList(jid); + final newDeviceList = await fetchDeviceListImpl(jid); if (newDeviceList == null) return []; _deviceList[jid] = newDeviceList; @@ -404,7 +411,7 @@ class OmemoManager { final newBundles = List.empty(growable: true); for (final id in bundlesToFetch) { - final bundle = await fetchDeviceBundle(jid, id); + final bundle = await fetchDeviceBundleImpl(jid, id); if (bundle != null) newBundles.add(bundle); } @@ -460,6 +467,11 @@ class OmemoManager { continue; } + if (!_subscriptionMap.containsKey(jid)) { + unawaited(subscribeToDeviceListNodeImpl(jid)); + _subscriptionMap[jid] = true; + } + for (final deviceId in devices) { // Empty OMEMO messages are allowed to bypass trust if (plaintext != null) { @@ -553,11 +565,18 @@ class OmemoManager { Future onIncomingStanza(OmemoIncomingStanza stanza) async { await _enterRatchetCriticalSection(stanza.bareSenderJid); + if (!_subscriptionMap.containsKey(stanza.bareSenderJid)) { + unawaited(subscribeToDeviceListNodeImpl(stanza.bareSenderJid)); + _subscriptionMap[stanza.bareSenderJid] = true; + } + final ratchetKey = RatchetMapKey(stanza.bareSenderJid, stanza.senderDeviceId); final _InternalDecryptionResult result; try { result = await _decryptMessage( - base64.decode(stanza.payload), + stanza.payload != null ? + base64.decode(stanza.payload!) : + null, stanza.bareSenderJid, stanza.senderDeviceId, stanza.keys, @@ -578,7 +597,7 @@ class OmemoManager { if (ratchet!.acknowledged) { // Ratchet is acknowledged if (ratchet.nr > 53 || result.ratchetCreated) { - await sendEmptyOmemoMessage( + await sendEmptyOmemoMessageImpl( await _encryptToJids( [stanza.bareSenderJid], null, @@ -601,7 +620,7 @@ class OmemoManager { stanza.senderDeviceId, enterCriticalSection: false, ); - await sendEmptyOmemoMessage( + await sendEmptyOmemoMessageImpl( await _encryptToJids( [stanza.bareSenderJid], null, @@ -619,11 +638,29 @@ class OmemoManager { /// Call when sending out an encrypted stanza. Will handle everything and /// encrypt it. - Future onOutgoingStanza(OmemoOutgoingStanza stanza) async { - return _encryptToJids( + Future onOutgoingStanza(OmemoOutgoingStanza stanza) async { + _log.finest('Waiting to enter critical section'); + await _enterRatchetCriticalSection(stanza.recipientJids.first); + _log.finest('Entered critical section'); + + final result = _encryptToJids( stanza.recipientJids, stanza.payload, ); + + await _leaveRatchetCriticalSection(stanza.recipientJids.first); + + return result; + } + + // Sends a hearbeat message as specified by XEP-0384 to [jid]. + Future sendOmemoHeartbeat(String jid) async { + // TODO(Unknown): Include some error handling + final result = await _encryptToJids( + [jid], + null, + ); + await sendEmptyOmemoMessageImpl(result, jid); } /// Mark the ratchet for device [deviceId] from [jid] as acked. @@ -646,9 +683,9 @@ class OmemoManager { /// Generates an entirely new device. May be useful when the user wants to reset their cryptographic /// identity. Triggers an event to commit it to storage. - Future regenerateDevice({ int opkAmount = 100 }) async { + Future regenerateDevice() async { await _deviceLock.synchronized(() async { - _device = await Device.generateNewDevice(_device.jid, opkAmount: opkAmount); + _device = await OmemoDevice.generateNewDevice(_device.jid); // Commit it _eventStreamController.add(DeviceModifiedEvent(_device)); @@ -656,11 +693,17 @@ class OmemoManager { } /// Returns the device used for encryption and decryption. - Future getDevice() => _deviceLock.synchronized(() => _device); + Future getDevice() => _deviceLock.synchronized(() => _device); /// Returns the id of the device used for encryption and decryption. Future getDeviceId() async => (await getDevice()).id; + /// Directly aquire the current device as a OMEMO device bundle. + Future getDeviceBundle() async => (await getDevice()).toBundle(); + + /// Directly aquire the current device's fingerprint. + Future getDeviceFingerprint() async => (await getDevice()).getFingerprint(); + /// Returns the fingerprints for all devices of [jid] that we have a session with. /// If there are not sessions with [jid], then returns null. Future?> getFingerprintsForJid(String jid) async { @@ -674,10 +717,11 @@ class OmemoManager { final fingerprints = List.empty(growable: true); for (final key in fingerprintKeys) { + final curveKey = await _ratchetMap[key]!.ik.toCurve25519(); fingerprints.add( DeviceFingerprint( key.deviceId, - HEX.encode(await _ratchetMap[key]!.ik.getBytes()), + HEX.encode(await curveKey.getBytes()), ), ); } @@ -689,6 +733,7 @@ class OmemoManager { /// Ensures that the device list is fetched again on the next message sending. void onNewConnection() { _deviceListRequested.clear(); + _subscriptionMap.clear(); } /// Sets the device list for [jid] to [devices]. Triggers a DeviceListModifiedEvent. @@ -704,4 +749,35 @@ class OmemoManager { _deviceList = deviceList; _ratchetMap = ratchetMap; } + + /// Removes all ratchets for JID [jid]. This also removes all trust decisions for + /// [jid] from the trust manager. This function triggers a RatchetRemovedEvent for + /// every removed ratchet and a DeviceListModifiedEvent afterwards. Behaviour for + /// the trust manager is dependent on its implementation. + Future removeAllRatchets(String jid) async { + await _enterRatchetCriticalSection(jid); + + for (final deviceId in _deviceList[jid]!) { + // Remove the ratchet and commit it + _ratchetMap.remove(jid); + _eventStreamController.add(RatchetRemovedEvent(jid, deviceId)); + } + + // Remove the devices from the device list cache and commit it + _deviceList.remove(jid); + _deviceListRequested.remove(jid); + _eventStreamController.add(DeviceListModifiedEvent(_deviceList)); + + // Remove trust decisions + await _trustManager.removeTrustDecisionsForJid(jid); + + await _leaveRatchetCriticalSection(jid); + } + + /// Replaces the internal device with [newDevice]. Does not trigger an event. + Future replaceDevice(OmemoDevice newDevice) async { + await _deviceLock.synchronized(() { + _device = newDevice; + }); + } } diff --git a/lib/src/omemo/sessionmanager.dart b/lib/src/omemo/sessionmanager.dart index fa79d10..271ee20 100644 --- a/lib/src/omemo/sessionmanager.dart +++ b/lib/src/omemo/sessionmanager.dart @@ -45,7 +45,7 @@ class OmemoSessionManager { // NOTE: Dart has some issues with just casting a List to List>, as // such we need to convert the items by hand. return OmemoSessionManager( - Device.fromJson(data['device']! as Map), + OmemoDevice.fromJson(data['device']! as Map), (data['devices']! as Map).map>( (key, value) { return MapEntry( @@ -62,7 +62,7 @@ class OmemoSessionManager { /// Generate a new cryptographic identity. static Future generateNewIdentity(String jid, TrustManager trustManager, { int opkAmount = 100 }) async { assert(opkAmount > 0, 'opkAmount must be bigger than 0.'); - final device = await Device.generateNewDevice(jid, opkAmount: opkAmount); + final device = await OmemoDevice.generateNewDevice(jid, opkAmount: opkAmount); return OmemoSessionManager(device, {}, {}, trustManager); } @@ -84,7 +84,7 @@ class OmemoSessionManager { /// Our own keys... // ignore: prefer_final_fields - Device _device; + OmemoDevice _device; /// and its lock final Lock _deviceLock; @@ -96,7 +96,7 @@ class OmemoSessionManager { Stream get eventStream => _eventStreamController.stream; /// Returns our own device. - Future getDevice() async { + Future getDevice() async { return _deviceLock.synchronized(() => _device); } @@ -625,7 +625,7 @@ class OmemoSessionManager { /// identity. Triggers an event to commit it to storage. Future regenerateDevice({ int opkAmount = 100 }) async { await _deviceLock.synchronized(() async { - _device = await Device.generateNewDevice(_device.jid, opkAmount: opkAmount); + _device = await OmemoDevice.generateNewDevice(_device.jid, opkAmount: opkAmount); // Commit it _eventStreamController.add(DeviceModifiedEvent(_device)); diff --git a/lib/src/omemo/stanza.dart b/lib/src/omemo/stanza.dart index 9ed4149..c883887 100644 --- a/lib/src/omemo/stanza.dart +++ b/lib/src/omemo/stanza.dart @@ -23,7 +23,7 @@ class OmemoIncomingStanza { final List keys; /// The string payload included in the element. - final String payload; + final String? payload; } /// Describes a stanza that is to be sent out diff --git a/lib/src/trust/always.dart b/lib/src/trust/always.dart index c91687a..b55aa35 100644 --- a/lib/src/trust/always.dart +++ b/lib/src/trust/always.dart @@ -18,6 +18,9 @@ class AlwaysTrustingTrustManager extends TrustManager { @override Future setEnabled(String jid, int deviceId, bool enabled) async {} + @override + Future removeTrustDecisionsForJid(String jid) async {} + @override Future> toJson() async => {}; } diff --git a/lib/src/trust/base.dart b/lib/src/trust/base.dart index 77d716b..86f46bb 100644 --- a/lib/src/trust/base.dart +++ b/lib/src/trust/base.dart @@ -19,4 +19,7 @@ abstract class TrustManager { /// Serialize the trust manager to JSON. Future> toJson(); + + /// Removes all trust decisions for [jid]. + Future removeTrustDecisionsForJid(String jid); } diff --git a/lib/src/trust/btbv.dart b/lib/src/trust/btbv.dart index 9bfc7a2..6fd9381 100644 --- a/lib/src/trust/btbv.dart +++ b/lib/src/trust/btbv.dart @@ -211,6 +211,14 @@ abstract class BlindTrustBeforeVerificationTrustManager extends TrustManager { ), ); } + + @override + Future removeTrustDecisionsForJid(String jid) async { + await _lock.synchronized(() async { + devices.remove(jid); + await commitState(); + }); + } /// Called when the state of the trust manager has been changed. Allows the user to /// commit the trust state to persistent storage. diff --git a/lib/src/trust/never.dart b/lib/src/trust/never.dart index fdc829c..687aba7 100644 --- a/lib/src/trust/never.dart +++ b/lib/src/trust/never.dart @@ -18,6 +18,9 @@ class NeverTrustingTrustManager extends TrustManager { @override Future setEnabled(String jid, int deviceId, bool enabled) async {} + @override + Future removeTrustDecisionsForJid(String jid) async {} + @override Future> toJson() async => {}; } diff --git a/test/omemo_test.dart b/test/omemo_test.dart index c31679e..3ae18e4 100644 --- a/test/omemo_test.dart +++ b/test/omemo_test.dart @@ -14,7 +14,7 @@ void main() { test('Test replacing a onetime prekey', () async { const aliceJid = 'alice@server.example'; - final device = await Device.generateNewDevice(aliceJid, opkAmount: 1); + final device = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1); final newDevice = await device.replaceOnetimePrekey(0); @@ -327,7 +327,7 @@ void main() { // Setup an event listener final oldDevice = await aliceSession.getDevice(); - Device? newDevice; + OmemoDevice? newDevice; aliceSession.eventStream.listen((event) { if (event is DeviceModifiedEvent) { newDevice = event.device; diff --git a/test/omemomanager_test.dart b/test/omemomanager_test.dart index 6308a2a..448d6fa 100644 --- a/test/omemomanager_test.dart +++ b/test/omemomanager_test.dart @@ -18,8 +18,8 @@ void main() { var aliceEmptyMessageSent = 0; var bobEmptyMessageSent = 0; - final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1); - final bobDevice = await Device.generateNewDevice(bobJid, opkAmount: 1); + final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1); + final bobDevice = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1); final aliceManager = OmemoManager( aliceDevice, @@ -35,6 +35,7 @@ void main() { expect(jid, bobJid); return bobDevice.toBundle(); }, + (jid) async {}, ); final bobManager = OmemoManager( bobDevice, @@ -50,6 +51,7 @@ void main() { expect(jid, aliceJid); return aliceDevice.toBundle(); }, + (jid) async {}, ); // Alice sends a message @@ -66,7 +68,7 @@ void main() { aliceJid, aliceDevice.id, DateTime.now().millisecondsSinceEpoch, - aliceResult!.encryptedKeys, + aliceResult.encryptedKeys, base64.encode(aliceResult.ciphertext!), ), ); @@ -94,7 +96,7 @@ void main() { bobJid, bobDevice.id, DateTime.now().millisecondsSinceEpoch, - bobResult2!.encryptedKeys, + bobResult2.encryptedKeys, base64.encode(bobResult2.ciphertext!), ), ); @@ -111,8 +113,8 @@ void main() { var aliceEmptyMessageSent = 0; var bobEmptyMessageSent = 0; - final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1); - final bobDevice = await Device.generateNewDevice(bobJid, opkAmount: 1); + final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1); + final bobDevice = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1); final aliceManager = OmemoManager( aliceDevice, @@ -128,6 +130,7 @@ void main() { expect(jid, bobJid); return bobDevice.toBundle(); }, + (jid) async {}, ); final bobManager = OmemoManager( bobDevice, @@ -143,6 +146,7 @@ void main() { expect(jid, aliceJid); return aliceDevice.toBundle(); }, + (jid) async {}, ); // Alice sends a message @@ -159,7 +163,7 @@ void main() { aliceJid, aliceDevice.id, DateTime.now().millisecondsSinceEpoch, - aliceResult!.encryptedKeys, + aliceResult.encryptedKeys, base64.encode(aliceResult.ciphertext!), ), ); @@ -185,7 +189,7 @@ void main() { aliceJid, aliceDevice.id, DateTime.now().millisecondsSinceEpoch, - aliceResultLoop!.encryptedKeys, + aliceResultLoop.encryptedKeys, base64.encode(aliceResultLoop.ciphertext!), ), ); @@ -208,7 +212,7 @@ void main() { aliceJid, aliceDevice.id, DateTime.now().millisecondsSinceEpoch, - aliceResultFinal!.encryptedKeys, + aliceResultFinal.encryptedKeys, base64.encode(aliceResultFinal.ciphertext!), ), ); @@ -221,7 +225,7 @@ void main() { test('Test accessing data without it existing', () async { const aliceJid = 'alice@server1'; const bobJid = 'bob@server2'; - final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1); + final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1); final aliceManager = OmemoManager( aliceDevice, @@ -229,6 +233,7 @@ void main() { (result, recipientJid) async {}, (jid) async => [], (jid, id) async => null, + (jid) async {}, ); // Get non-existant fingerprints @@ -249,9 +254,9 @@ void main() { const bobJid = 'bob@server2'; var oldDevice = true; - final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1); - final bobOldDevice = await Device.generateNewDevice(bobJid, opkAmount: 1); - final bobCurrentDevice = await Device.generateNewDevice(bobJid, opkAmount: 1); + final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1); + final bobOldDevice = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1); + final bobCurrentDevice = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1); final aliceManager = OmemoManager( aliceDevice, @@ -270,6 +275,7 @@ void main() { bobOldDevice.toBundle() : bobCurrentDevice.toBundle(); }, + (jid) async {}, ); final bobManager = OmemoManager( bobCurrentDevice, @@ -277,6 +283,7 @@ void main() { (result, recipientJid) async {}, (jid) async => [], (jid, id) async => null, + (jid) async {}, ); // Alice encrypts a message to Bob @@ -293,7 +300,7 @@ void main() { aliceJid, aliceDevice.id, DateTime.now().millisecondsSinceEpoch, - aliceResult1!.encryptedKeys, + aliceResult1.encryptedKeys, base64.encode(aliceResult1.ciphertext!), ), ); @@ -317,7 +324,7 @@ void main() { aliceJid, aliceDevice.id, DateTime.now().millisecondsSinceEpoch, - aliceResult2!.encryptedKeys, + aliceResult2.encryptedKeys, base64.encode(aliceResult2.ciphertext!), ), ); @@ -331,9 +338,9 @@ void main() { const bobJid = 'bob@server2'; var bothDevices = false; - final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1); - final bobDevice1 = await Device.generateNewDevice(bobJid, opkAmount: 1); - final bobDevice2 = await Device.generateNewDevice(bobJid, opkAmount: 1); + final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1); + final bobDevice1 = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1); + final bobDevice2 = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1); final aliceManager = OmemoManager( aliceDevice, @@ -364,6 +371,7 @@ void main() { return null; }, + (jid) async {}, ); final bobManager1 = OmemoManager( bobDevice1, @@ -371,6 +379,7 @@ void main() { (result, recipientJid) async {}, (jid) async => [], (jid, id) async => null, + (jid) async {}, ); final bobManager2 = OmemoManager( bobDevice2, @@ -384,6 +393,7 @@ void main() { expect(jid, aliceJid); return aliceDevice.toBundle(); }, + (jid) async {}, ); // Alice sends a message to Bob @@ -400,7 +410,7 @@ void main() { aliceJid, aliceDevice.id, DateTime.now().millisecondsSinceEpoch, - aliceResult1!.encryptedKeys, + aliceResult1.encryptedKeys, base64.encode(aliceResult1.ciphertext!), ), ); @@ -423,7 +433,7 @@ void main() { bobJid, bobDevice2.id, DateTime.now().millisecondsSinceEpoch, - bobResult2!.encryptedKeys, + bobResult2.encryptedKeys, base64.encode(bobResult2.ciphertext!), ), ); @@ -436,9 +446,9 @@ void main() { const bobJid = 'bob@server2'; var bothDevices = false; - final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1); - final bobDevice1 = await Device.generateNewDevice(bobJid, opkAmount: 1); - final bobDevice2 = await Device.generateNewDevice(bobJid, opkAmount: 1); + final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1); + final bobDevice1 = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1); + final bobDevice2 = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1); final aliceManager = OmemoManager( aliceDevice, @@ -469,6 +479,7 @@ void main() { return null; }, + (jid) async {}, ); final bobManager1 = OmemoManager( bobDevice1, @@ -476,6 +487,7 @@ void main() { (result, recipientJid) async {}, (jid) async => null, (jid, id) async => null, + (jid) async {}, ); final bobManager2 = OmemoManager( bobDevice2, @@ -483,6 +495,7 @@ void main() { (result, recipientJid) async {}, (jid) async => null, (jid, id) async => null, + (jid) async {}, ); // Alice sends a message to Bob @@ -499,7 +512,7 @@ void main() { aliceJid, aliceDevice.id, DateTime.now().millisecondsSinceEpoch, - aliceResult1!.encryptedKeys, + aliceResult1.encryptedKeys, base64.encode(aliceResult1.ciphertext!), ), ); @@ -528,7 +541,7 @@ void main() { ), ); - expect(aliceResult2!.encryptedKeys.length, 2); + expect(aliceResult2.encryptedKeys.length, 2); // And Bob decrypts it final bobResult21 = await bobManager1.onIncomingStanza( @@ -567,7 +580,7 @@ void main() { bobJid, bobDevice2.id, DateTime.now().millisecondsSinceEpoch, - bobResult32!.encryptedKeys, + bobResult32.encryptedKeys, base64.encode(bobResult32.ciphertext!), ), ); @@ -580,9 +593,9 @@ void main() { const bobJid = 'bob@server2'; const cocoJid = 'coco@server3'; - final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1); - final bobDevice = await Device.generateNewDevice(bobJid, opkAmount: 1); - final cocoDevice = await Device.generateNewDevice(cocoJid, opkAmount: 1); + final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1); + final bobDevice = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1); + final cocoDevice = await OmemoDevice.generateNewDevice(cocoJid, opkAmount: 1); final aliceManager = OmemoManager( aliceDevice, @@ -606,6 +619,7 @@ void main() { return null; }, + (jid) async {}, ); final bobManager = OmemoManager( bobDevice, @@ -613,6 +627,7 @@ void main() { (result, recipientJid) async {}, (jid) async => null, (jid, id) async => null, + (jid) async {}, ); final cocoManager = OmemoManager( cocoDevice, @@ -620,6 +635,7 @@ void main() { (result, recipientJid) async {}, (jid) async => null, (jid, id) async => null, + (jid) async {}, ); // Alice sends a message to Bob and Coco @@ -636,7 +652,7 @@ void main() { aliceJid, aliceDevice.id, DateTime.now().millisecondsSinceEpoch, - aliceResult!.encryptedKeys, + aliceResult.encryptedKeys, base64.encode(aliceResult.ciphertext!), ), ); @@ -661,8 +677,8 @@ void main() { const bobJid = 'bob@server2'; var failure = false; - final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1); - final bobDevice = await Device.generateNewDevice(bobJid, opkAmount: 1); + final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1); + final bobDevice = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1); final aliceManager = OmemoManager( aliceDevice, @@ -682,6 +698,7 @@ void main() { null : bobDevice.toBundle(); }, + (jid) async {}, ); final bobManager = OmemoManager( bobDevice, @@ -689,6 +706,7 @@ void main() { (result, recipientJid) async {}, (jid) async => null, (jid, id) async => null, + (jid) async {}, ); // Alice sends a message to Bob and Coco @@ -705,7 +723,7 @@ void main() { aliceJid, aliceDevice.id, DateTime.now().millisecondsSinceEpoch, - aliceResult1!.encryptedKeys, + aliceResult1.encryptedKeys, base64.encode(aliceResult1.ciphertext!), ), ); @@ -737,7 +755,7 @@ void main() { aliceJid, aliceDevice.id, DateTime.now().millisecondsSinceEpoch, - aliceResult2!.encryptedKeys, + aliceResult2.encryptedKeys, base64.encode(aliceResult2.ciphertext!), ), ); @@ -750,7 +768,7 @@ void main() { const aliceJid = 'alice@server1'; const bobJid = 'bob@server2'; - final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1); + final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1); final aliceManager = OmemoManager( aliceDevice, @@ -766,6 +784,7 @@ void main() { return null; }, + (jid) async {}, ); // Alice sends a message to Bob @@ -776,7 +795,7 @@ void main() { ), ); - expect(aliceResult!.isSuccess(1), false); + expect(aliceResult.isSuccess(1), false); expect(aliceResult.jidEncryptionErrors[bobJid] is NoKeyMaterialAvailableException, true); }); @@ -785,8 +804,8 @@ void main() { const bobJid = 'bob@server2'; const cocoJid = 'coco@server3'; - final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1); - final bobDevice = await Device.generateNewDevice(bobJid, opkAmount: 1); + final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1); + final bobDevice = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1); final aliceManager = OmemoManager( aliceDevice, @@ -806,6 +825,7 @@ void main() { return null; }, + (jid) async {}, ); final bobManager = OmemoManager( bobDevice, @@ -813,6 +833,7 @@ void main() { (result, recipientJid) async {}, (jid) async => null, (jid, id) async => null, + (jid) async {}, ); // Alice sends a message to Bob and Coco @@ -823,7 +844,7 @@ void main() { ), ); - expect(aliceResult!.isSuccess(2), true); + expect(aliceResult.isSuccess(2), true); expect(aliceResult.jidEncryptionErrors[cocoJid] is NoKeyMaterialAvailableException, true); // Bob decrypts it @@ -844,8 +865,8 @@ void main() { const aliceJid = 'alice@server1'; const bobJid = 'bob@server2'; - final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1); - final bobDevice = await Device.generateNewDevice(bobJid, opkAmount: 1); + final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1); + final bobDevice = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1); final aliceManager = OmemoManager( aliceDevice, @@ -861,6 +882,7 @@ void main() { return bobDevice.toBundle(); }, + (jid) async {}, ); final bobManager = OmemoManager( bobDevice, @@ -868,6 +890,7 @@ void main() { (result, recipientJid) async {}, (jid) async => null, (jid, id) async => null, + (jid) async {}, ); // Alice encrypts a message for Bob @@ -884,7 +907,7 @@ void main() { aliceJid, aliceDevice.id, DateTime.now().millisecondsSinceEpoch, - aliceMessage!.encryptedKeys, + aliceMessage.encryptedKeys, base64.encode(aliceMessage.ciphertext!), ), @@ -905,7 +928,7 @@ void main() { messageText, ), ); - expect(bobResponseMessage!.isSuccess(1), true); + expect(bobResponseMessage.isSuccess(1), true); final aliceReceivedMessage = await aliceManager.onIncomingStanza( OmemoIncomingStanza( diff --git a/test/serialisation_test.dart b/test/serialisation_test.dart index b163288..071735d 100644 --- a/test/serialisation_test.dart +++ b/test/serialisation_test.dart @@ -18,7 +18,7 @@ void main() { final oldDevice = await oldSession.getDevice(); final serialised = jsonify(await oldDevice.toJson()); - final newDevice = Device.fromJson(serialised); + final newDevice = OmemoDevice.fromJson(serialised); expect(await oldDevice.equals(newDevice), true); }); @@ -32,7 +32,7 @@ void main() { final oldDevice = await (await oldSession.getDevice()).replaceSignedPrekey(); final serialised = jsonify(await oldDevice.toJson()); - final newDevice = Device.fromJson(serialised); + final newDevice = OmemoDevice.fromJson(serialised); expect(await oldDevice.equals(newDevice), true); });