feat: Add last features for use in moxxmpp

This commit is contained in:
2023-01-01 16:49:19 +01:00
parent 4085631804
commit 092ce36410
14 changed files with 216 additions and 88 deletions

View File

@@ -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';
@@ -252,6 +253,12 @@ class OmemoDoubleRatchet {
};
}
/// Returns the OMEMO compatible fingerprint of the ratchet session.
Future<String> getOmemoFingerprint() async {
final curveKey = await ik.toCurve25519();
return HEX.encode(await curveKey.getBytes());
}
Future<List<int>?> _trySkippedMessageKeys(OmemoMessage header, List<int> ciphertext) async {
final key = SkippedKey(
OmemoPublicKey.fromBytes(header.dhPub!, KeyPairType.x25519),

View File

@@ -9,7 +9,6 @@ const privateKeyLength = 32;
const publicKeyLength = 32;
class OmemoPublicKey {
const OmemoPublicKey(this._pubkey);
factory OmemoPublicKey.fromBytes(List<int> bytes, KeyPairType type) {
@@ -55,7 +54,6 @@ class OmemoPublicKey {
}
class OmemoPrivateKey {
const OmemoPrivateKey(this._privkey, this.type);
final List<int> _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

View File

@@ -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<String, dynamic> data) {
factory OmemoDevice.fromJson(Map<String, dynamic> 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<Device> generateNewDevice(String jid, { int opkAmount = 100 }) async {
static Future<OmemoDevice> 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<Device> replaceOnetimePrekey(int id) async {
Future<OmemoDevice> 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<Device> replaceSignedPrekey() async {
Future<OmemoDevice> 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<String> 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<Map<String, dynamic>> toJson() async {
/// Serialise the OPKs
@@ -236,7 +244,7 @@ class Device {
}
@visibleForTesting
Future<bool> equals(Device other) async {
Future<bool> equals(OmemoDevice other) async {
var opksMatch = true;
if (opks.length != other.opks.length) {
opksMatch = false;

View File

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

View File

@@ -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<void> Function(EncryptionResult result, String recipientJid) sendEmptyOmemoMessage;
final Future<void> 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<List<int>?> Function(String jid) fetchDeviceList;
final Future<List<int>?> 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<OmemoBundle?> Function(String jid, int id) fetchDeviceBundle;
final Future<OmemoBundle?> Function(String jid, int id) fetchDeviceBundleImpl;
/// Subscribe to the device list PEP node of @jid.
final Future<void> Function(String jid) subscribeToDeviceListNodeImpl;
/// Map bare JID to its known devices
Map<String, List<int>> _deviceList = {};
@@ -65,6 +69,8 @@ class OmemoManager {
/// Map bare a ratchet key to its ratchet. Note that this is also locked by
/// _ratchetCriticalSectionLock.
Map<RatchetMapKey, OmemoDoubleRatchet> _ratchetMap = {};
/// Map bare JID to whether we already tried to subscribe to the device list node.
final Map<String, bool> _subscriptionMap = {};
/// For preventing a race condition in encryption/decryption
final Map<String, Queue<Completer<void>>> _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<OmemoEvent> _eventStreamController = StreamController<OmemoEvent>.broadcast();
Stream<OmemoEvent> get eventStream => _eventStreamController.stream;
/// Enter the critical section for performing cryptographic operations on the ratchets
Future<void> _enterRatchetCriticalSection(String jid) async {
@@ -379,7 +386,7 @@ class OmemoManager {
List<int> 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<OmemoBundle>.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<DecryptionResult> 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<EncryptionResult?> onOutgoingStanza(OmemoOutgoingStanza stanza) async {
return _encryptToJids(
Future<EncryptionResult> 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<void> 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<void> regenerateDevice({ int opkAmount = 100 }) async {
Future<void> 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<Device> getDevice() => _deviceLock.synchronized(() => _device);
Future<OmemoDevice> getDevice() => _deviceLock.synchronized(() => _device);
/// Returns the id of the device used for encryption and decryption.
Future<int> getDeviceId() async => (await getDevice()).id;
/// Directly aquire the current device as a OMEMO device bundle.
Future<OmemoBundle> getDeviceBundle() async => (await getDevice()).toBundle();
/// Directly aquire the current device's fingerprint.
Future<String> 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<List<DeviceFingerprint>?> getFingerprintsForJid(String jid) async {
@@ -674,10 +717,11 @@ class OmemoManager {
final fingerprints = List<DeviceFingerprint>.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<void> 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<void> replaceDevice(OmemoDevice newDevice) async {
await _deviceLock.synchronized(() {
_device = newDevice;
});
}
}

View File

@@ -45,7 +45,7 @@ class OmemoSessionManager {
// NOTE: Dart has some issues with just casting a List<dynamic> to List<Map<...>>, as
// such we need to convert the items by hand.
return OmemoSessionManager(
Device.fromJson(data['device']! as Map<String, dynamic>),
OmemoDevice.fromJson(data['device']! as Map<String, dynamic>),
(data['devices']! as Map<String, dynamic>).map<String, List<int>>(
(key, value) {
return MapEntry(
@@ -62,7 +62,7 @@ class OmemoSessionManager {
/// Generate a new cryptographic identity.
static Future<OmemoSessionManager> 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<OmemoEvent> get eventStream => _eventStreamController.stream;
/// Returns our own device.
Future<Device> getDevice() async {
Future<OmemoDevice> getDevice() async {
return _deviceLock.synchronized(() => _device);
}
@@ -625,7 +625,7 @@ class OmemoSessionManager {
/// identity. Triggers an event to commit it to storage.
Future<void> 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));

View File

@@ -23,7 +23,7 @@ class OmemoIncomingStanza {
final List<EncryptedKey> keys;
/// The string payload included in the <encrypted /> element.
final String payload;
final String? payload;
}
/// Describes a stanza that is to be sent out

View File

@@ -18,6 +18,9 @@ class AlwaysTrustingTrustManager extends TrustManager {
@override
Future<void> setEnabled(String jid, int deviceId, bool enabled) async {}
@override
Future<void> removeTrustDecisionsForJid(String jid) async {}
@override
Future<Map<String, dynamic>> toJson() async => <String, dynamic>{};
}

View File

@@ -19,4 +19,7 @@ abstract class TrustManager {
/// Serialize the trust manager to JSON.
Future<Map<String, dynamic>> toJson();
/// Removes all trust decisions for [jid].
Future<void> removeTrustDecisionsForJid(String jid);
}

View File

@@ -212,6 +212,14 @@ abstract class BlindTrustBeforeVerificationTrustManager extends TrustManager {
);
}
@override
Future<void> 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.
@visibleForOverriding

View File

@@ -18,6 +18,9 @@ class NeverTrustingTrustManager extends TrustManager {
@override
Future<void> setEnabled(String jid, int deviceId, bool enabled) async {}
@override
Future<void> removeTrustDecisionsForJid(String jid) async {}
@override
Future<Map<String, dynamic>> toJson() async => <String, dynamic>{};
}

View File

@@ -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;

View File

@@ -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(

View File

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