feat: Add last features for use in moxxmpp
This commit is contained in:
parent
4085631804
commit
092ce36410
@ -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<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(
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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>{};
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -211,6 +211,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.
|
||||
|
@ -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>{};
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user