diff --git a/lib/src/crypto.dart b/lib/src/crypto.dart index 4933615..dbe97a0 100644 --- a/lib/src/crypto.dart +++ b/lib/src/crypto.dart @@ -113,7 +113,7 @@ Future>> aes256CbcDecrypt( ), ); } catch (ex) { - return Result(MalformedCiphertextError(ex)); + return Result(MalformedCiphertextError(ex)); } } diff --git a/lib/src/double_ratchet/double_ratchet.dart b/lib/src/double_ratchet/double_ratchet.dart index 122aa7c..9c3fcb6 100644 --- a/lib/src/double_ratchet/double_ratchet.dart +++ b/lib/src/double_ratchet/double_ratchet.dart @@ -247,11 +247,15 @@ class OmemoDoubleRatchet { /// Decrypt [ciphertext] using keys derived from the message key [mk]. Also computes the /// HMAC from the [OMEMOMessage] embedded in [message]. - /// + /// /// If the computed HMAC does not match the HMAC in [message], returns /// [InvalidMessageHMACError]. If it matches, returns the decrypted /// payload. - Future>> _decrypt(OMEMOAuthenticatedMessage message, List ciphertext, List mk) async { + Future>> _decrypt( + OMEMOAuthenticatedMessage message, + List ciphertext, + List mk, + ) async { final keys = await deriveEncryptionKeys(mk, encryptHkdfInfoString); final hmacInput = concat([sessionAd, message.message]); @@ -260,7 +264,8 @@ class OmemoDoubleRatchet { return Result(InvalidMessageHMACError()); } - final plaintext = await aes256CbcDecrypt(ciphertext, keys.encryptionKey, keys.iv); + final plaintext = + await aes256CbcDecrypt(ciphertext, keys.encryptionKey, keys.iv); if (plaintext.isType()) { return Result(plaintext.get()); } @@ -270,10 +275,13 @@ class OmemoDoubleRatchet { /// Checks whether we could decrypt the payload in [header] with a skipped key. If yes, /// attempts to decrypt it. If not, returns null. - /// + /// /// If the decryption is successful, returns the plaintext payload. If an error occurs, like /// an [InvalidMessageHMACError], that is returned instead. - Future?>> _trySkippedMessageKeys(OMEMOAuthenticatedMessage message, OMEMOMessage header) async { + Future?>> _trySkippedMessageKeys( + OMEMOAuthenticatedMessage message, + OMEMOMessage header, + ) async { final key = SkippedKey( OmemoPublicKey.fromBytes(header.dhPub, KeyPairType.x25519), header.n, @@ -289,10 +297,12 @@ class OmemoDoubleRatchet { } /// Decrypt the payload (deeply) embedded in [message]. - /// + /// /// If everything goes well, returns the plaintext payload. If an error occurs, that /// is returned instead. - Future>> ratchetDecrypt(OMEMOAuthenticatedMessage message) async { + Future>> ratchetDecrypt( + OMEMOAuthenticatedMessage message, + ) async { final header = OMEMOMessage.fromBuffer(message.message); // Try skipped keys @@ -343,10 +353,10 @@ class OmemoDoubleRatchet { // Fill-in the header and serialize it here so we do it only once final header = OMEMOMessage() - ..dhPub = await dhs.pk.getBytes() - ..pn = pn - ..n = ns - ..ciphertext = ciphertext; + ..dhPub = await dhs.pk.getBytes() + ..pn = pn + ..n = ns + ..ciphertext = ciphertext; final headerBytes = header.writeToBuffer(); // Increment the send counter diff --git a/lib/src/omemo/encryption_result.dart b/lib/src/omemo/encryption_result.dart index 112b2fd..36a06ad 100644 --- a/lib/src/omemo/encryption_result.dart +++ b/lib/src/omemo/encryption_result.dart @@ -1,8 +1,6 @@ import 'package:meta/meta.dart'; -import 'package:omemo_dart/src/errors.dart'; import 'package:omemo_dart/src/omemo/encrypted_key.dart'; import 'package:omemo_dart/src/omemo/errors.dart'; -import 'package:omemo_dart/src/omemo/ratchet_map_key.dart'; @immutable class EncryptionResult { @@ -19,7 +17,7 @@ class EncryptionResult { /// for the ratchet with said device Id. final Map> encryptedKeys; - /// Mapping of a JID to + /// Mapping of a JID to final Map> deviceEncryptionErrors; // TODO: Turn this into a property that is computed in [onOutgoingStanza]. diff --git a/lib/src/omemo/omemo.dart b/lib/src/omemo/omemo.dart index 3dd4b7e..dff324f 100644 --- a/lib/src/omemo/omemo.dart +++ b/lib/src/omemo/omemo.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:collection'; import 'dart:convert'; import 'package:collection/collection.dart'; import 'package:cryptography/cryptography.dart'; @@ -139,11 +138,12 @@ class OmemoManager { /// Fetches the device list from the server for [jid] and downloads OMEMO bundles /// for devices we have no session with. - /// + /// /// Returns a list of new bundles, that may be empty. Future> _fetchNewOmemoBundles(String jid) async { // Do we have to request the device list or are we already up-to-date? - if (!_deviceListRequested.containsKey(jid) || !_deviceList.containsKey(jid)) { + if (!_deviceListRequested.containsKey(jid) || + !_deviceList.containsKey(jid)) { final newDeviceList = await fetchDeviceListImpl(jid); if (newDeviceList != null) { // Figure out what bundles we must fetch @@ -190,11 +190,17 @@ class OmemoManager { return bundles; } - Future _maybeSendEmptyMessage(RatchetMapKey key, bool created, bool replaced) async { + Future _maybeSendEmptyMessage( + RatchetMapKey key, + bool created, + bool replaced, + ) async { final ratchet = _ratchetMap[key]!; if (ratchet.acknowledged) { // The ratchet is acknowledged - _log.finest('Checking whether to heartbeat to ${key.jid}, ratchet.nr (${ratchet.nr}) >= 53: ${ratchet.nr >= 53}, created: $created, replaced: $replaced'); + _log.finest( + 'Checking whether to heartbeat to ${key.jid}, ratchet.nr (${ratchet.nr}) >= 53: ${ratchet.nr >= 53}, created: $created, replaced: $replaced', + ); if (ratchet.nr >= 53 || created || replaced) { await sendEmptyOmemoMessageImpl( await _onOutgoingStanzaImpl( @@ -222,7 +228,7 @@ class OmemoManager { } } - /// + /// Future onIncomingStanza(OmemoIncomingStanza stanza) async { return _ratchetQueue.synchronized( [stanza.bareSenderJid], @@ -230,7 +236,9 @@ class OmemoManager { ); } - Future _onIncomingStanzaImpl(OmemoIncomingStanza stanza) async { + Future _onIncomingStanzaImpl( + OmemoIncomingStanza stanza, + ) async { // Find the correct key for our device final deviceId = await getDeviceId(); final key = stanza.keys.firstWhereOrNull((key) => key.rid == deviceId); @@ -242,7 +250,8 @@ class OmemoManager { } // Check how we should process the message - final ratchetKey = RatchetMapKey(stanza.bareSenderJid, stanza.senderDeviceId); + final ratchetKey = + RatchetMapKey(stanza.bareSenderJid, stanza.senderDeviceId); var processAsKex = key.kex; if (key.kex && _ratchetMap.containsKey(ratchetKey)) { final ratchet = _ratchetMap[ratchetKey]!; @@ -288,7 +297,7 @@ class OmemoManager { ); final kex = await x3dhFromInitialMessage( X3DHMessage( - kexIk, + kexIk, kexEk, kexMessage.pkId, ), @@ -369,7 +378,11 @@ class OmemoManager { } // Send the hearbeat, if we have to - await _maybeSendEmptyMessage(ratchetKey, true, _ratchetMap.containsKey(ratchetKey)); + await _maybeSendEmptyMessage( + ratchetKey, + true, + _ratchetMap.containsKey(ratchetKey), + ); return DecryptionResult( result.get(), @@ -380,7 +393,8 @@ class OmemoManager { if (!_ratchetMap.containsKey(ratchetKey)) { // TODO: Check if we recently failed to build a session with the device // This causes omemo_dart to build a session with the device. - if (!_deviceList[stanza.bareSenderJid]!.contains(stanza.senderDeviceId)) { + if (!_deviceList[stanza.bareSenderJid]! + .contains(stanza.senderDeviceId)) { _deviceList[stanza.bareSenderJid]!.add(stanza.senderDeviceId); } await _sendOmemoHeartbeat(stanza.bareSenderJid); @@ -397,10 +411,14 @@ class OmemoManager { // Correctly decode the message OMEMOAuthenticatedMessage authMessage; if (key.kex) { - _log.finest('Extracting OMEMOAuthenticatedMessage from OMEMOKeyExchange'); - authMessage = OMEMOKeyExchange.fromBuffer(base64Decode(key.value)).message; + _log.finest( + 'Extracting OMEMOAuthenticatedMessage from OMEMOKeyExchange', + ); + authMessage = + OMEMOKeyExchange.fromBuffer(base64Decode(key.value)).message; } else { - authMessage = OMEMOAuthenticatedMessage.fromBuffer(base64Decode(key.value)); + authMessage = + OMEMOAuthenticatedMessage.fromBuffer(base64Decode(key.value)); } final keyAndHmac = await ratchet.ratchetDecrypt(authMessage); @@ -459,7 +477,9 @@ class OmemoManager { ); } - Future _onOutgoingStanzaImpl(OmemoOutgoingStanza stanza) async { + Future _onOutgoingStanzaImpl( + OmemoOutgoingStanza stanza, + ) async { // Encrypt the payload, if we have any final List payloadKey; final List ciphertext; @@ -545,7 +565,9 @@ class OmemoManager { _eventStreamController.add( RatchetsAddedEvent( Map.fromEntries( - addedRatchetKeys.map((key) => MapEntry(key, _ratchetMap[key]!)).toList(), + addedRatchetKeys + .map((key) => MapEntry(key, _ratchetMap[key]!)) + .toList(), ), ), ); @@ -728,7 +750,9 @@ class OmemoManager { Future _ratchetAcknowledged(String jid, int device) async { final ratchetKey = RatchetMapKey(jid, device); if (!_ratchetMap.containsKey(ratchetKey)) { - _log.warning('Cannot mark $jid:$device as acknowledged as the ratchet does not exist'); + _log.warning( + 'Cannot mark $jid:$device as acknowledged as the ratchet does not exist', + ); } else { // Commit final ratchet = _ratchetMap[ratchetKey]!..acknowledged = true; @@ -740,7 +764,7 @@ class OmemoManager { /// If ratchets with [jid] exists, returns a list of fingerprints for each /// ratchet. - /// + /// /// If not ratchets exists, returns null. Future?> getFingerprintsForJid(String jid) async { return _ratchetQueue.synchronized( @@ -750,7 +774,9 @@ class OmemoManager { } /// Same as [getFingerprintsForJid], but without acquiring the lock for [jid]. - Future?> _getFingerprintsForJidImpl(String jid) async { + Future?> _getFingerprintsForJidImpl( + String jid, + ) async { // Check if we know of the JID. if (!_deviceList.containsKey(jid)) { return null; diff --git a/lib/src/omemo/queue.dart b/lib/src/omemo/queue.dart index a63f02e..8f99df7 100644 --- a/lib/src/omemo/queue.dart +++ b/lib/src/omemo/queue.dart @@ -87,7 +87,10 @@ class RatchetAccessQueue { }); } - Future synchronized(List jids, Future Function() function) async { + Future synchronized( + List jids, + Future Function() function, + ) async { await enterCriticalSection(jids); final result = await function(); await leaveCriticalSection(jids); diff --git a/lib/src/x3dh/x3dh.dart b/lib/src/x3dh/x3dh.dart index 8f261a1..1e82d01 100644 --- a/lib/src/x3dh/x3dh.dart +++ b/lib/src/x3dh/x3dh.dart @@ -71,7 +71,8 @@ Future> kdf(List km) async { /// Alice builds a session with Bob using his bundle [bundle] and Alice's identity key /// pair [ik]. -Future> x3dhFromBundle( +Future> + x3dhFromBundle( OmemoBundle bundle, OmemoKeyPair ik, ) async { diff --git a/test/omemo_test.dart b/test/omemo_test.dart index 3aa9110..c7b7fba 100644 --- a/test/omemo_test.dart +++ b/test/omemo_test.dart @@ -203,7 +203,7 @@ void main() { // Alice now sends 52 messages that Bob decrypts for (var i = 0; i < 52; i++) { - Logger.root.finest('${i+1}/52'); + Logger.root.finest('${i + 1}/52'); final aliceResultLoop = await aliceManager.onOutgoingStanza( OmemoOutgoingStanza( [bobJid], @@ -934,7 +934,10 @@ void main() { expect(aliceResult.isSuccess(2), isFalse); expect(aliceResult.deviceEncryptionErrors[cocoJid]!.length, 1); - expect(aliceResult.deviceEncryptionErrors[cocoJid]!.first.error, const TypeMatcher(),); + expect( + aliceResult.deviceEncryptionErrors[cocoJid]!.first.error, + const TypeMatcher(), + ); // Bob decrypts it final bobResult = await bobManager.onIncomingStanza( @@ -1243,7 +1246,10 @@ void main() { Logger.root.info('Removing all ratchets for $bobJid'); await aliceManager.removeAllRatchets(bobJid); - expect(aliceManager.getRatchet(RatchetMapKey(bobJid, bobDevice.id)), isNull); + expect( + aliceManager.getRatchet(RatchetMapKey(bobJid, bobDevice.id)), + isNull, + ); // Alice prepares an empty OMEMO message await aliceManager.sendOmemoHeartbeat(bobJid); diff --git a/test/queue_test.dart b/test/queue_test.dart index 2cd19d3..b424593 100644 --- a/test/queue_test.dart +++ b/test/queue_test.dart @@ -1,9 +1,12 @@ import 'dart:async'; - import 'package:omemo_dart/src/omemo/queue.dart'; import 'package:test/test.dart'; -Future testMethod(RatchetAccessQueue queue, List data, int duration) async { +Future testMethod( + RatchetAccessQueue queue, + List data, + int duration, +) async { await queue.enterCriticalSection(data); await Future.delayed(Duration(seconds: duration)); @@ -48,7 +51,10 @@ void main() { expect(queue.runningOperations.length, 4); expect( queue.runningOperations.containsAll([ - 'a', 'b', 'c', 'd', + 'a', + 'b', + 'c', + 'd', ]), isTrue, );