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 'dart:convert';
|
||||||
import 'package:cryptography/cryptography.dart';
|
import 'package:cryptography/cryptography.dart';
|
||||||
|
import 'package:hex/hex.dart';
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
import 'package:omemo_dart/src/crypto.dart';
|
import 'package:omemo_dart/src/crypto.dart';
|
||||||
import 'package:omemo_dart/src/double_ratchet/crypto.dart';
|
import 'package:omemo_dart/src/double_ratchet/crypto.dart';
|
||||||
@ -251,6 +252,12 @@ class OmemoDoubleRatchet {
|
|||||||
'kex': kex,
|
'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 {
|
Future<List<int>?> _trySkippedMessageKeys(OmemoMessage header, List<int> ciphertext) async {
|
||||||
final key = SkippedKey(
|
final key = SkippedKey(
|
||||||
|
@ -9,7 +9,6 @@ const privateKeyLength = 32;
|
|||||||
const publicKeyLength = 32;
|
const publicKeyLength = 32;
|
||||||
|
|
||||||
class OmemoPublicKey {
|
class OmemoPublicKey {
|
||||||
|
|
||||||
const OmemoPublicKey(this._pubkey);
|
const OmemoPublicKey(this._pubkey);
|
||||||
|
|
||||||
factory OmemoPublicKey.fromBytes(List<int> bytes, KeyPairType type) {
|
factory OmemoPublicKey.fromBytes(List<int> bytes, KeyPairType type) {
|
||||||
@ -55,7 +54,6 @@ class OmemoPublicKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class OmemoPrivateKey {
|
class OmemoPrivateKey {
|
||||||
|
|
||||||
const OmemoPrivateKey(this._privkey, this.type);
|
const OmemoPrivateKey(this._privkey, this.type);
|
||||||
final List<int> _privkey;
|
final List<int> _privkey;
|
||||||
final KeyPairType type;
|
final KeyPairType type;
|
||||||
@ -85,7 +83,6 @@ class OmemoPrivateKey {
|
|||||||
|
|
||||||
/// A generic wrapper class for both Ed25519 and X25519 keypairs
|
/// A generic wrapper class for both Ed25519 and X25519 keypairs
|
||||||
class OmemoKeyPair {
|
class OmemoKeyPair {
|
||||||
|
|
||||||
const OmemoKeyPair(this.pk, this.sk, this.type);
|
const OmemoKeyPair(this.pk, this.sk, this.type);
|
||||||
|
|
||||||
/// Create an OmemoKeyPair just from a [type] and the bytes of the private and public
|
/// Create an OmemoKeyPair just from a [type] and the bytes of the private and public
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:cryptography/cryptography.dart';
|
import 'package:cryptography/cryptography.dart';
|
||||||
|
import 'package:hex/hex.dart';
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
import 'package:omemo_dart/src/helpers.dart';
|
import 'package:omemo_dart/src/helpers.dart';
|
||||||
import 'package:omemo_dart/src/keys.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
|
/// This class represents an OmemoBundle but with all keypairs belonging to the keys
|
||||||
@immutable
|
@immutable
|
||||||
class Device {
|
class OmemoDevice {
|
||||||
const Device(
|
const OmemoDevice(
|
||||||
this.jid,
|
this.jid,
|
||||||
this.id,
|
this.id,
|
||||||
this.ik,
|
this.ik,
|
||||||
@ -22,7 +23,7 @@ class Device {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/// Deserialize the 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
|
// 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
|
// Keypair's private key, while ik_pub refers to the Identity Keypair's public
|
||||||
// key.
|
// key.
|
||||||
@ -66,7 +67,7 @@ class Device {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return Device(
|
return OmemoDevice(
|
||||||
data['jid']! as String,
|
data['jid']! as String,
|
||||||
data['id']! as int,
|
data['id']! as int,
|
||||||
OmemoKeyPair.fromBytes(
|
OmemoKeyPair.fromBytes(
|
||||||
@ -92,7 +93,7 @@ class Device {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a completely new device, i.e. cryptographic identity.
|
/// 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 id = generateRandom32BitNumber();
|
||||||
final ik = await OmemoKeyPair.generateNewPair(KeyPairType.ed25519);
|
final ik = await OmemoKeyPair.generateNewPair(KeyPairType.ed25519);
|
||||||
final spk = await OmemoKeyPair.generateNewPair(KeyPairType.x25519);
|
final spk = await OmemoKeyPair.generateNewPair(KeyPairType.x25519);
|
||||||
@ -104,7 +105,7 @@ class Device {
|
|||||||
opks[i] = await OmemoKeyPair.generateNewPair(KeyPairType.x25519);
|
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
|
/// Our bare Jid
|
||||||
@ -134,10 +135,10 @@ class Device {
|
|||||||
/// This replaces the Onetime-Prekey with id [id] with a completely new one. Returns
|
/// 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.
|
/// a new Device object that copies over everything but replaces said key.
|
||||||
@internal
|
@internal
|
||||||
Future<Device> replaceOnetimePrekey(int id) async {
|
Future<OmemoDevice> replaceOnetimePrekey(int id) async {
|
||||||
opks[id] = await OmemoKeyPair.generateNewPair(KeyPairType.x25519);
|
opks[id] = await OmemoKeyPair.generateNewPair(KeyPairType.x25519);
|
||||||
|
|
||||||
return Device(
|
return OmemoDevice(
|
||||||
jid,
|
jid,
|
||||||
this.id,
|
this.id,
|
||||||
ik,
|
ik,
|
||||||
@ -153,12 +154,12 @@ class Device {
|
|||||||
/// This replaces the Signed-Prekey with a completely new one. Returns a new Device object
|
/// 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.
|
/// that copies over everything but replaces the Signed-Prekey and its signature.
|
||||||
@internal
|
@internal
|
||||||
Future<Device> replaceSignedPrekey() async {
|
Future<OmemoDevice> replaceSignedPrekey() async {
|
||||||
final newSpk = await OmemoKeyPair.generateNewPair(KeyPairType.x25519);
|
final newSpk = await OmemoKeyPair.generateNewPair(KeyPairType.x25519);
|
||||||
final newSpkId = generateRandom32BitNumber();
|
final newSpkId = generateRandom32BitNumber();
|
||||||
final newSignature = await sig(ik, await newSpk.pk.getBytes());
|
final newSignature = await sig(ik, await newSpk.pk.getBytes());
|
||||||
|
|
||||||
return Device(
|
return OmemoDevice(
|
||||||
jid,
|
jid,
|
||||||
id,
|
id,
|
||||||
ik,
|
ik,
|
||||||
@ -174,8 +175,8 @@ class Device {
|
|||||||
/// Returns a new device that is equal to this one with the exception that the new
|
/// 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.
|
/// device's id is a new number between 0 and 2**32 - 1.
|
||||||
@internal
|
@internal
|
||||||
Device withNewId() {
|
OmemoDevice withNewId() {
|
||||||
return Device(
|
return OmemoDevice(
|
||||||
jid,
|
jid,
|
||||||
generateRandom32BitNumber(),
|
generateRandom32BitNumber(),
|
||||||
ik,
|
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.
|
/// Serialise the device information.
|
||||||
Future<Map<String, dynamic>> toJson() async {
|
Future<Map<String, dynamic>> toJson() async {
|
||||||
/// Serialise the OPKs
|
/// Serialise the OPKs
|
||||||
@ -236,7 +244,7 @@ class Device {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
Future<bool> equals(Device other) async {
|
Future<bool> equals(OmemoDevice other) async {
|
||||||
var opksMatch = true;
|
var opksMatch = true;
|
||||||
if (opks.length != other.opks.length) {
|
if (opks.length != other.opks.length) {
|
||||||
opksMatch = false;
|
opksMatch = false;
|
||||||
|
@ -31,5 +31,5 @@ class DeviceListModifiedEvent extends OmemoEvent {
|
|||||||
/// and thus should be republished.
|
/// and thus should be republished.
|
||||||
class DeviceModifiedEvent extends OmemoEvent {
|
class DeviceModifiedEvent extends OmemoEvent {
|
||||||
DeviceModifiedEvent(this.device);
|
DeviceModifiedEvent(this.device);
|
||||||
final Device device;
|
final OmemoDevice device;
|
||||||
}
|
}
|
||||||
|
@ -38,9 +38,10 @@ class OmemoManager {
|
|||||||
OmemoManager(
|
OmemoManager(
|
||||||
this._device,
|
this._device,
|
||||||
this._trustManager,
|
this._trustManager,
|
||||||
this.sendEmptyOmemoMessage,
|
this.sendEmptyOmemoMessageImpl,
|
||||||
this.fetchDeviceList,
|
this.fetchDeviceListImpl,
|
||||||
this.fetchDeviceBundle,
|
this.fetchDeviceBundleImpl,
|
||||||
|
this.subscribeToDeviceListNodeImpl,
|
||||||
);
|
);
|
||||||
|
|
||||||
final Logger _log = Logger('OmemoManager');
|
final Logger _log = Logger('OmemoManager');
|
||||||
@ -49,14 +50,17 @@ class OmemoManager {
|
|||||||
|
|
||||||
/// Send an empty OMEMO:2 message using the encrypted payload @result to
|
/// Send an empty OMEMO:2 message using the encrypted payload @result to
|
||||||
/// @recipientJid.
|
/// @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
|
/// Fetch the list of device ids associated with @jid. If the device list cannot be
|
||||||
/// fetched, return null.
|
/// 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.
|
/// 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 bare JID to its known devices
|
||||||
Map<String, List<int>> _deviceList = {};
|
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
|
/// Map bare a ratchet key to its ratchet. Note that this is also locked by
|
||||||
/// _ratchetCriticalSectionLock.
|
/// _ratchetCriticalSectionLock.
|
||||||
Map<RatchetMapKey, OmemoDoubleRatchet> _ratchetMap = {};
|
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
|
/// For preventing a race condition in encryption/decryption
|
||||||
final Map<String, Queue<Completer<void>>> _ratchetCriticalSectionQueue = {};
|
final Map<String, Queue<Completer<void>>> _ratchetCriticalSectionQueue = {};
|
||||||
final Lock _ratchetCriticalSectionLock = Lock();
|
final Lock _ratchetCriticalSectionLock = Lock();
|
||||||
@ -76,10 +82,11 @@ class OmemoManager {
|
|||||||
/// Our own keys...
|
/// Our own keys...
|
||||||
final Lock _deviceLock = Lock();
|
final Lock _deviceLock = Lock();
|
||||||
// ignore: prefer_final_fields
|
// ignore: prefer_final_fields
|
||||||
Device _device;
|
OmemoDevice _device;
|
||||||
|
|
||||||
/// The event bus of the session manager
|
/// The event bus of the session manager
|
||||||
final StreamController<OmemoEvent> _eventStreamController = StreamController<OmemoEvent>.broadcast();
|
final StreamController<OmemoEvent> _eventStreamController = StreamController<OmemoEvent>.broadcast();
|
||||||
|
Stream<OmemoEvent> get eventStream => _eventStreamController.stream;
|
||||||
|
|
||||||
/// Enter the critical section for performing cryptographic operations on the ratchets
|
/// Enter the critical section for performing cryptographic operations on the ratchets
|
||||||
Future<void> _enterRatchetCriticalSection(String jid) async {
|
Future<void> _enterRatchetCriticalSection(String jid) async {
|
||||||
@ -379,7 +386,7 @@ class OmemoManager {
|
|||||||
List<int> bundlesToFetch;
|
List<int> bundlesToFetch;
|
||||||
if (!_deviceListRequested.containsKey(jid) || !_deviceList.containsKey(jid)) {
|
if (!_deviceListRequested.containsKey(jid) || !_deviceList.containsKey(jid)) {
|
||||||
// We don't have an up-to-date version of the device list
|
// 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 [];
|
if (newDeviceList == null) return [];
|
||||||
|
|
||||||
_deviceList[jid] = newDeviceList;
|
_deviceList[jid] = newDeviceList;
|
||||||
@ -404,7 +411,7 @@ class OmemoManager {
|
|||||||
|
|
||||||
final newBundles = List<OmemoBundle>.empty(growable: true);
|
final newBundles = List<OmemoBundle>.empty(growable: true);
|
||||||
for (final id in bundlesToFetch) {
|
for (final id in bundlesToFetch) {
|
||||||
final bundle = await fetchDeviceBundle(jid, id);
|
final bundle = await fetchDeviceBundleImpl(jid, id);
|
||||||
if (bundle != null) newBundles.add(bundle);
|
if (bundle != null) newBundles.add(bundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,6 +467,11 @@ class OmemoManager {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_subscriptionMap.containsKey(jid)) {
|
||||||
|
unawaited(subscribeToDeviceListNodeImpl(jid));
|
||||||
|
_subscriptionMap[jid] = true;
|
||||||
|
}
|
||||||
|
|
||||||
for (final deviceId in devices) {
|
for (final deviceId in devices) {
|
||||||
// Empty OMEMO messages are allowed to bypass trust
|
// Empty OMEMO messages are allowed to bypass trust
|
||||||
if (plaintext != null) {
|
if (plaintext != null) {
|
||||||
@ -553,11 +565,18 @@ class OmemoManager {
|
|||||||
Future<DecryptionResult> onIncomingStanza(OmemoIncomingStanza stanza) async {
|
Future<DecryptionResult> onIncomingStanza(OmemoIncomingStanza stanza) async {
|
||||||
await _enterRatchetCriticalSection(stanza.bareSenderJid);
|
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 ratchetKey = RatchetMapKey(stanza.bareSenderJid, stanza.senderDeviceId);
|
||||||
final _InternalDecryptionResult result;
|
final _InternalDecryptionResult result;
|
||||||
try {
|
try {
|
||||||
result = await _decryptMessage(
|
result = await _decryptMessage(
|
||||||
base64.decode(stanza.payload),
|
stanza.payload != null ?
|
||||||
|
base64.decode(stanza.payload!) :
|
||||||
|
null,
|
||||||
stanza.bareSenderJid,
|
stanza.bareSenderJid,
|
||||||
stanza.senderDeviceId,
|
stanza.senderDeviceId,
|
||||||
stanza.keys,
|
stanza.keys,
|
||||||
@ -578,7 +597,7 @@ class OmemoManager {
|
|||||||
if (ratchet!.acknowledged) {
|
if (ratchet!.acknowledged) {
|
||||||
// Ratchet is acknowledged
|
// Ratchet is acknowledged
|
||||||
if (ratchet.nr > 53 || result.ratchetCreated) {
|
if (ratchet.nr > 53 || result.ratchetCreated) {
|
||||||
await sendEmptyOmemoMessage(
|
await sendEmptyOmemoMessageImpl(
|
||||||
await _encryptToJids(
|
await _encryptToJids(
|
||||||
[stanza.bareSenderJid],
|
[stanza.bareSenderJid],
|
||||||
null,
|
null,
|
||||||
@ -601,7 +620,7 @@ class OmemoManager {
|
|||||||
stanza.senderDeviceId,
|
stanza.senderDeviceId,
|
||||||
enterCriticalSection: false,
|
enterCriticalSection: false,
|
||||||
);
|
);
|
||||||
await sendEmptyOmemoMessage(
|
await sendEmptyOmemoMessageImpl(
|
||||||
await _encryptToJids(
|
await _encryptToJids(
|
||||||
[stanza.bareSenderJid],
|
[stanza.bareSenderJid],
|
||||||
null,
|
null,
|
||||||
@ -619,11 +638,29 @@ class OmemoManager {
|
|||||||
|
|
||||||
/// Call when sending out an encrypted stanza. Will handle everything and
|
/// Call when sending out an encrypted stanza. Will handle everything and
|
||||||
/// encrypt it.
|
/// encrypt it.
|
||||||
Future<EncryptionResult?> onOutgoingStanza(OmemoOutgoingStanza stanza) async {
|
Future<EncryptionResult> onOutgoingStanza(OmemoOutgoingStanza stanza) async {
|
||||||
return _encryptToJids(
|
_log.finest('Waiting to enter critical section');
|
||||||
|
await _enterRatchetCriticalSection(stanza.recipientJids.first);
|
||||||
|
_log.finest('Entered critical section');
|
||||||
|
|
||||||
|
final result = _encryptToJids(
|
||||||
stanza.recipientJids,
|
stanza.recipientJids,
|
||||||
stanza.payload,
|
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.
|
/// 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
|
/// 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.
|
/// identity. Triggers an event to commit it to storage.
|
||||||
Future<void> regenerateDevice({ int opkAmount = 100 }) async {
|
Future<void> regenerateDevice() async {
|
||||||
await _deviceLock.synchronized(() async {
|
await _deviceLock.synchronized(() async {
|
||||||
_device = await Device.generateNewDevice(_device.jid, opkAmount: opkAmount);
|
_device = await OmemoDevice.generateNewDevice(_device.jid);
|
||||||
|
|
||||||
// Commit it
|
// Commit it
|
||||||
_eventStreamController.add(DeviceModifiedEvent(_device));
|
_eventStreamController.add(DeviceModifiedEvent(_device));
|
||||||
@ -656,11 +693,17 @@ class OmemoManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the device used for encryption and decryption.
|
/// 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.
|
/// Returns the id of the device used for encryption and decryption.
|
||||||
Future<int> getDeviceId() async => (await getDevice()).id;
|
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.
|
/// Returns the fingerprints for all devices of [jid] that we have a session with.
|
||||||
/// If there are not sessions with [jid], then returns null.
|
/// If there are not sessions with [jid], then returns null.
|
||||||
Future<List<DeviceFingerprint>?> getFingerprintsForJid(String jid) async {
|
Future<List<DeviceFingerprint>?> getFingerprintsForJid(String jid) async {
|
||||||
@ -674,10 +717,11 @@ class OmemoManager {
|
|||||||
|
|
||||||
final fingerprints = List<DeviceFingerprint>.empty(growable: true);
|
final fingerprints = List<DeviceFingerprint>.empty(growable: true);
|
||||||
for (final key in fingerprintKeys) {
|
for (final key in fingerprintKeys) {
|
||||||
|
final curveKey = await _ratchetMap[key]!.ik.toCurve25519();
|
||||||
fingerprints.add(
|
fingerprints.add(
|
||||||
DeviceFingerprint(
|
DeviceFingerprint(
|
||||||
key.deviceId,
|
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.
|
/// Ensures that the device list is fetched again on the next message sending.
|
||||||
void onNewConnection() {
|
void onNewConnection() {
|
||||||
_deviceListRequested.clear();
|
_deviceListRequested.clear();
|
||||||
|
_subscriptionMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the device list for [jid] to [devices]. Triggers a DeviceListModifiedEvent.
|
/// Sets the device list for [jid] to [devices]. Triggers a DeviceListModifiedEvent.
|
||||||
@ -704,4 +749,35 @@ class OmemoManager {
|
|||||||
_deviceList = deviceList;
|
_deviceList = deviceList;
|
||||||
_ratchetMap = ratchetMap;
|
_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
|
// NOTE: Dart has some issues with just casting a List<dynamic> to List<Map<...>>, as
|
||||||
// such we need to convert the items by hand.
|
// such we need to convert the items by hand.
|
||||||
return OmemoSessionManager(
|
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>>(
|
(data['devices']! as Map<String, dynamic>).map<String, List<int>>(
|
||||||
(key, value) {
|
(key, value) {
|
||||||
return MapEntry(
|
return MapEntry(
|
||||||
@ -62,7 +62,7 @@ class OmemoSessionManager {
|
|||||||
/// Generate a new cryptographic identity.
|
/// Generate a new cryptographic identity.
|
||||||
static Future<OmemoSessionManager> generateNewIdentity(String jid, TrustManager trustManager, { int opkAmount = 100 }) async {
|
static Future<OmemoSessionManager> generateNewIdentity(String jid, TrustManager trustManager, { int opkAmount = 100 }) async {
|
||||||
assert(opkAmount > 0, 'opkAmount must be bigger than 0.');
|
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);
|
return OmemoSessionManager(device, {}, {}, trustManager);
|
||||||
}
|
}
|
||||||
@ -84,7 +84,7 @@ class OmemoSessionManager {
|
|||||||
|
|
||||||
/// Our own keys...
|
/// Our own keys...
|
||||||
// ignore: prefer_final_fields
|
// ignore: prefer_final_fields
|
||||||
Device _device;
|
OmemoDevice _device;
|
||||||
/// and its lock
|
/// and its lock
|
||||||
final Lock _deviceLock;
|
final Lock _deviceLock;
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ class OmemoSessionManager {
|
|||||||
Stream<OmemoEvent> get eventStream => _eventStreamController.stream;
|
Stream<OmemoEvent> get eventStream => _eventStreamController.stream;
|
||||||
|
|
||||||
/// Returns our own device.
|
/// Returns our own device.
|
||||||
Future<Device> getDevice() async {
|
Future<OmemoDevice> getDevice() async {
|
||||||
return _deviceLock.synchronized(() => _device);
|
return _deviceLock.synchronized(() => _device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -625,7 +625,7 @@ class OmemoSessionManager {
|
|||||||
/// identity. Triggers an event to commit it to storage.
|
/// identity. Triggers an event to commit it to storage.
|
||||||
Future<void> regenerateDevice({ int opkAmount = 100 }) async {
|
Future<void> regenerateDevice({ int opkAmount = 100 }) async {
|
||||||
await _deviceLock.synchronized(() async {
|
await _deviceLock.synchronized(() async {
|
||||||
_device = await Device.generateNewDevice(_device.jid, opkAmount: opkAmount);
|
_device = await OmemoDevice.generateNewDevice(_device.jid, opkAmount: opkAmount);
|
||||||
|
|
||||||
// Commit it
|
// Commit it
|
||||||
_eventStreamController.add(DeviceModifiedEvent(_device));
|
_eventStreamController.add(DeviceModifiedEvent(_device));
|
||||||
|
@ -23,7 +23,7 @@ class OmemoIncomingStanza {
|
|||||||
final List<EncryptedKey> keys;
|
final List<EncryptedKey> keys;
|
||||||
|
|
||||||
/// The string payload included in the <encrypted /> element.
|
/// The string payload included in the <encrypted /> element.
|
||||||
final String payload;
|
final String? payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes a stanza that is to be sent out
|
/// Describes a stanza that is to be sent out
|
||||||
|
@ -18,6 +18,9 @@ class AlwaysTrustingTrustManager extends TrustManager {
|
|||||||
@override
|
@override
|
||||||
Future<void> setEnabled(String jid, int deviceId, bool enabled) async {}
|
Future<void> setEnabled(String jid, int deviceId, bool enabled) async {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> removeTrustDecisionsForJid(String jid) async {}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Map<String, dynamic>> toJson() async => <String, dynamic>{};
|
Future<Map<String, dynamic>> toJson() async => <String, dynamic>{};
|
||||||
}
|
}
|
||||||
|
@ -19,4 +19,7 @@ abstract class TrustManager {
|
|||||||
|
|
||||||
/// Serialize the trust manager to JSON.
|
/// Serialize the trust manager to JSON.
|
||||||
Future<Map<String, dynamic>> toJson();
|
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
|
/// Called when the state of the trust manager has been changed. Allows the user to
|
||||||
/// commit the trust state to persistent storage.
|
/// commit the trust state to persistent storage.
|
||||||
|
@ -18,6 +18,9 @@ class NeverTrustingTrustManager extends TrustManager {
|
|||||||
@override
|
@override
|
||||||
Future<void> setEnabled(String jid, int deviceId, bool enabled) async {}
|
Future<void> setEnabled(String jid, int deviceId, bool enabled) async {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> removeTrustDecisionsForJid(String jid) async {}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Map<String, dynamic>> toJson() async => <String, dynamic>{};
|
Future<Map<String, dynamic>> toJson() async => <String, dynamic>{};
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ void main() {
|
|||||||
|
|
||||||
test('Test replacing a onetime prekey', () async {
|
test('Test replacing a onetime prekey', () async {
|
||||||
const aliceJid = 'alice@server.example';
|
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);
|
final newDevice = await device.replaceOnetimePrekey(0);
|
||||||
|
|
||||||
@ -327,7 +327,7 @@ void main() {
|
|||||||
|
|
||||||
// Setup an event listener
|
// Setup an event listener
|
||||||
final oldDevice = await aliceSession.getDevice();
|
final oldDevice = await aliceSession.getDevice();
|
||||||
Device? newDevice;
|
OmemoDevice? newDevice;
|
||||||
aliceSession.eventStream.listen((event) {
|
aliceSession.eventStream.listen((event) {
|
||||||
if (event is DeviceModifiedEvent) {
|
if (event is DeviceModifiedEvent) {
|
||||||
newDevice = event.device;
|
newDevice = event.device;
|
||||||
|
@ -18,8 +18,8 @@ void main() {
|
|||||||
var aliceEmptyMessageSent = 0;
|
var aliceEmptyMessageSent = 0;
|
||||||
var bobEmptyMessageSent = 0;
|
var bobEmptyMessageSent = 0;
|
||||||
|
|
||||||
final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1);
|
final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1);
|
||||||
final bobDevice = await Device.generateNewDevice(bobJid, opkAmount: 1);
|
final bobDevice = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1);
|
||||||
|
|
||||||
final aliceManager = OmemoManager(
|
final aliceManager = OmemoManager(
|
||||||
aliceDevice,
|
aliceDevice,
|
||||||
@ -35,6 +35,7 @@ void main() {
|
|||||||
expect(jid, bobJid);
|
expect(jid, bobJid);
|
||||||
return bobDevice.toBundle();
|
return bobDevice.toBundle();
|
||||||
},
|
},
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
final bobManager = OmemoManager(
|
final bobManager = OmemoManager(
|
||||||
bobDevice,
|
bobDevice,
|
||||||
@ -50,6 +51,7 @@ void main() {
|
|||||||
expect(jid, aliceJid);
|
expect(jid, aliceJid);
|
||||||
return aliceDevice.toBundle();
|
return aliceDevice.toBundle();
|
||||||
},
|
},
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Alice sends a message
|
// Alice sends a message
|
||||||
@ -66,7 +68,7 @@ void main() {
|
|||||||
aliceJid,
|
aliceJid,
|
||||||
aliceDevice.id,
|
aliceDevice.id,
|
||||||
DateTime.now().millisecondsSinceEpoch,
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
aliceResult!.encryptedKeys,
|
aliceResult.encryptedKeys,
|
||||||
base64.encode(aliceResult.ciphertext!),
|
base64.encode(aliceResult.ciphertext!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -94,7 +96,7 @@ void main() {
|
|||||||
bobJid,
|
bobJid,
|
||||||
bobDevice.id,
|
bobDevice.id,
|
||||||
DateTime.now().millisecondsSinceEpoch,
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
bobResult2!.encryptedKeys,
|
bobResult2.encryptedKeys,
|
||||||
base64.encode(bobResult2.ciphertext!),
|
base64.encode(bobResult2.ciphertext!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -111,8 +113,8 @@ void main() {
|
|||||||
var aliceEmptyMessageSent = 0;
|
var aliceEmptyMessageSent = 0;
|
||||||
var bobEmptyMessageSent = 0;
|
var bobEmptyMessageSent = 0;
|
||||||
|
|
||||||
final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1);
|
final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1);
|
||||||
final bobDevice = await Device.generateNewDevice(bobJid, opkAmount: 1);
|
final bobDevice = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1);
|
||||||
|
|
||||||
final aliceManager = OmemoManager(
|
final aliceManager = OmemoManager(
|
||||||
aliceDevice,
|
aliceDevice,
|
||||||
@ -128,6 +130,7 @@ void main() {
|
|||||||
expect(jid, bobJid);
|
expect(jid, bobJid);
|
||||||
return bobDevice.toBundle();
|
return bobDevice.toBundle();
|
||||||
},
|
},
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
final bobManager = OmemoManager(
|
final bobManager = OmemoManager(
|
||||||
bobDevice,
|
bobDevice,
|
||||||
@ -143,6 +146,7 @@ void main() {
|
|||||||
expect(jid, aliceJid);
|
expect(jid, aliceJid);
|
||||||
return aliceDevice.toBundle();
|
return aliceDevice.toBundle();
|
||||||
},
|
},
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Alice sends a message
|
// Alice sends a message
|
||||||
@ -159,7 +163,7 @@ void main() {
|
|||||||
aliceJid,
|
aliceJid,
|
||||||
aliceDevice.id,
|
aliceDevice.id,
|
||||||
DateTime.now().millisecondsSinceEpoch,
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
aliceResult!.encryptedKeys,
|
aliceResult.encryptedKeys,
|
||||||
base64.encode(aliceResult.ciphertext!),
|
base64.encode(aliceResult.ciphertext!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -185,7 +189,7 @@ void main() {
|
|||||||
aliceJid,
|
aliceJid,
|
||||||
aliceDevice.id,
|
aliceDevice.id,
|
||||||
DateTime.now().millisecondsSinceEpoch,
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
aliceResultLoop!.encryptedKeys,
|
aliceResultLoop.encryptedKeys,
|
||||||
base64.encode(aliceResultLoop.ciphertext!),
|
base64.encode(aliceResultLoop.ciphertext!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -208,7 +212,7 @@ void main() {
|
|||||||
aliceJid,
|
aliceJid,
|
||||||
aliceDevice.id,
|
aliceDevice.id,
|
||||||
DateTime.now().millisecondsSinceEpoch,
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
aliceResultFinal!.encryptedKeys,
|
aliceResultFinal.encryptedKeys,
|
||||||
base64.encode(aliceResultFinal.ciphertext!),
|
base64.encode(aliceResultFinal.ciphertext!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -221,7 +225,7 @@ void main() {
|
|||||||
test('Test accessing data without it existing', () async {
|
test('Test accessing data without it existing', () async {
|
||||||
const aliceJid = 'alice@server1';
|
const aliceJid = 'alice@server1';
|
||||||
const bobJid = 'bob@server2';
|
const bobJid = 'bob@server2';
|
||||||
final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1);
|
final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1);
|
||||||
|
|
||||||
final aliceManager = OmemoManager(
|
final aliceManager = OmemoManager(
|
||||||
aliceDevice,
|
aliceDevice,
|
||||||
@ -229,6 +233,7 @@ void main() {
|
|||||||
(result, recipientJid) async {},
|
(result, recipientJid) async {},
|
||||||
(jid) async => [],
|
(jid) async => [],
|
||||||
(jid, id) async => null,
|
(jid, id) async => null,
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get non-existant fingerprints
|
// Get non-existant fingerprints
|
||||||
@ -249,9 +254,9 @@ void main() {
|
|||||||
const bobJid = 'bob@server2';
|
const bobJid = 'bob@server2';
|
||||||
var oldDevice = true;
|
var oldDevice = true;
|
||||||
|
|
||||||
final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1);
|
final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1);
|
||||||
final bobOldDevice = await Device.generateNewDevice(bobJid, opkAmount: 1);
|
final bobOldDevice = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1);
|
||||||
final bobCurrentDevice = await Device.generateNewDevice(bobJid, opkAmount: 1);
|
final bobCurrentDevice = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1);
|
||||||
|
|
||||||
final aliceManager = OmemoManager(
|
final aliceManager = OmemoManager(
|
||||||
aliceDevice,
|
aliceDevice,
|
||||||
@ -270,6 +275,7 @@ void main() {
|
|||||||
bobOldDevice.toBundle() :
|
bobOldDevice.toBundle() :
|
||||||
bobCurrentDevice.toBundle();
|
bobCurrentDevice.toBundle();
|
||||||
},
|
},
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
final bobManager = OmemoManager(
|
final bobManager = OmemoManager(
|
||||||
bobCurrentDevice,
|
bobCurrentDevice,
|
||||||
@ -277,6 +283,7 @@ void main() {
|
|||||||
(result, recipientJid) async {},
|
(result, recipientJid) async {},
|
||||||
(jid) async => [],
|
(jid) async => [],
|
||||||
(jid, id) async => null,
|
(jid, id) async => null,
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Alice encrypts a message to Bob
|
// Alice encrypts a message to Bob
|
||||||
@ -293,7 +300,7 @@ void main() {
|
|||||||
aliceJid,
|
aliceJid,
|
||||||
aliceDevice.id,
|
aliceDevice.id,
|
||||||
DateTime.now().millisecondsSinceEpoch,
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
aliceResult1!.encryptedKeys,
|
aliceResult1.encryptedKeys,
|
||||||
base64.encode(aliceResult1.ciphertext!),
|
base64.encode(aliceResult1.ciphertext!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -317,7 +324,7 @@ void main() {
|
|||||||
aliceJid,
|
aliceJid,
|
||||||
aliceDevice.id,
|
aliceDevice.id,
|
||||||
DateTime.now().millisecondsSinceEpoch,
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
aliceResult2!.encryptedKeys,
|
aliceResult2.encryptedKeys,
|
||||||
base64.encode(aliceResult2.ciphertext!),
|
base64.encode(aliceResult2.ciphertext!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -331,9 +338,9 @@ void main() {
|
|||||||
const bobJid = 'bob@server2';
|
const bobJid = 'bob@server2';
|
||||||
var bothDevices = false;
|
var bothDevices = false;
|
||||||
|
|
||||||
final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1);
|
final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1);
|
||||||
final bobDevice1 = await Device.generateNewDevice(bobJid, opkAmount: 1);
|
final bobDevice1 = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1);
|
||||||
final bobDevice2 = await Device.generateNewDevice(bobJid, opkAmount: 1);
|
final bobDevice2 = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1);
|
||||||
|
|
||||||
final aliceManager = OmemoManager(
|
final aliceManager = OmemoManager(
|
||||||
aliceDevice,
|
aliceDevice,
|
||||||
@ -364,6 +371,7 @@ void main() {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
final bobManager1 = OmemoManager(
|
final bobManager1 = OmemoManager(
|
||||||
bobDevice1,
|
bobDevice1,
|
||||||
@ -371,6 +379,7 @@ void main() {
|
|||||||
(result, recipientJid) async {},
|
(result, recipientJid) async {},
|
||||||
(jid) async => [],
|
(jid) async => [],
|
||||||
(jid, id) async => null,
|
(jid, id) async => null,
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
final bobManager2 = OmemoManager(
|
final bobManager2 = OmemoManager(
|
||||||
bobDevice2,
|
bobDevice2,
|
||||||
@ -384,6 +393,7 @@ void main() {
|
|||||||
expect(jid, aliceJid);
|
expect(jid, aliceJid);
|
||||||
return aliceDevice.toBundle();
|
return aliceDevice.toBundle();
|
||||||
},
|
},
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Alice sends a message to Bob
|
// Alice sends a message to Bob
|
||||||
@ -400,7 +410,7 @@ void main() {
|
|||||||
aliceJid,
|
aliceJid,
|
||||||
aliceDevice.id,
|
aliceDevice.id,
|
||||||
DateTime.now().millisecondsSinceEpoch,
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
aliceResult1!.encryptedKeys,
|
aliceResult1.encryptedKeys,
|
||||||
base64.encode(aliceResult1.ciphertext!),
|
base64.encode(aliceResult1.ciphertext!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -423,7 +433,7 @@ void main() {
|
|||||||
bobJid,
|
bobJid,
|
||||||
bobDevice2.id,
|
bobDevice2.id,
|
||||||
DateTime.now().millisecondsSinceEpoch,
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
bobResult2!.encryptedKeys,
|
bobResult2.encryptedKeys,
|
||||||
base64.encode(bobResult2.ciphertext!),
|
base64.encode(bobResult2.ciphertext!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -436,9 +446,9 @@ void main() {
|
|||||||
const bobJid = 'bob@server2';
|
const bobJid = 'bob@server2';
|
||||||
var bothDevices = false;
|
var bothDevices = false;
|
||||||
|
|
||||||
final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1);
|
final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1);
|
||||||
final bobDevice1 = await Device.generateNewDevice(bobJid, opkAmount: 1);
|
final bobDevice1 = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1);
|
||||||
final bobDevice2 = await Device.generateNewDevice(bobJid, opkAmount: 1);
|
final bobDevice2 = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1);
|
||||||
|
|
||||||
final aliceManager = OmemoManager(
|
final aliceManager = OmemoManager(
|
||||||
aliceDevice,
|
aliceDevice,
|
||||||
@ -469,6 +479,7 @@ void main() {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
final bobManager1 = OmemoManager(
|
final bobManager1 = OmemoManager(
|
||||||
bobDevice1,
|
bobDevice1,
|
||||||
@ -476,6 +487,7 @@ void main() {
|
|||||||
(result, recipientJid) async {},
|
(result, recipientJid) async {},
|
||||||
(jid) async => null,
|
(jid) async => null,
|
||||||
(jid, id) async => null,
|
(jid, id) async => null,
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
final bobManager2 = OmemoManager(
|
final bobManager2 = OmemoManager(
|
||||||
bobDevice2,
|
bobDevice2,
|
||||||
@ -483,6 +495,7 @@ void main() {
|
|||||||
(result, recipientJid) async {},
|
(result, recipientJid) async {},
|
||||||
(jid) async => null,
|
(jid) async => null,
|
||||||
(jid, id) async => null,
|
(jid, id) async => null,
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Alice sends a message to Bob
|
// Alice sends a message to Bob
|
||||||
@ -499,7 +512,7 @@ void main() {
|
|||||||
aliceJid,
|
aliceJid,
|
||||||
aliceDevice.id,
|
aliceDevice.id,
|
||||||
DateTime.now().millisecondsSinceEpoch,
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
aliceResult1!.encryptedKeys,
|
aliceResult1.encryptedKeys,
|
||||||
base64.encode(aliceResult1.ciphertext!),
|
base64.encode(aliceResult1.ciphertext!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -528,7 +541,7 @@ void main() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(aliceResult2!.encryptedKeys.length, 2);
|
expect(aliceResult2.encryptedKeys.length, 2);
|
||||||
|
|
||||||
// And Bob decrypts it
|
// And Bob decrypts it
|
||||||
final bobResult21 = await bobManager1.onIncomingStanza(
|
final bobResult21 = await bobManager1.onIncomingStanza(
|
||||||
@ -567,7 +580,7 @@ void main() {
|
|||||||
bobJid,
|
bobJid,
|
||||||
bobDevice2.id,
|
bobDevice2.id,
|
||||||
DateTime.now().millisecondsSinceEpoch,
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
bobResult32!.encryptedKeys,
|
bobResult32.encryptedKeys,
|
||||||
base64.encode(bobResult32.ciphertext!),
|
base64.encode(bobResult32.ciphertext!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -580,9 +593,9 @@ void main() {
|
|||||||
const bobJid = 'bob@server2';
|
const bobJid = 'bob@server2';
|
||||||
const cocoJid = 'coco@server3';
|
const cocoJid = 'coco@server3';
|
||||||
|
|
||||||
final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1);
|
final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1);
|
||||||
final bobDevice = await Device.generateNewDevice(bobJid, opkAmount: 1);
|
final bobDevice = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1);
|
||||||
final cocoDevice = await Device.generateNewDevice(cocoJid, opkAmount: 1);
|
final cocoDevice = await OmemoDevice.generateNewDevice(cocoJid, opkAmount: 1);
|
||||||
|
|
||||||
final aliceManager = OmemoManager(
|
final aliceManager = OmemoManager(
|
||||||
aliceDevice,
|
aliceDevice,
|
||||||
@ -606,6 +619,7 @@ void main() {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
final bobManager = OmemoManager(
|
final bobManager = OmemoManager(
|
||||||
bobDevice,
|
bobDevice,
|
||||||
@ -613,6 +627,7 @@ void main() {
|
|||||||
(result, recipientJid) async {},
|
(result, recipientJid) async {},
|
||||||
(jid) async => null,
|
(jid) async => null,
|
||||||
(jid, id) async => null,
|
(jid, id) async => null,
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
final cocoManager = OmemoManager(
|
final cocoManager = OmemoManager(
|
||||||
cocoDevice,
|
cocoDevice,
|
||||||
@ -620,6 +635,7 @@ void main() {
|
|||||||
(result, recipientJid) async {},
|
(result, recipientJid) async {},
|
||||||
(jid) async => null,
|
(jid) async => null,
|
||||||
(jid, id) async => null,
|
(jid, id) async => null,
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Alice sends a message to Bob and Coco
|
// Alice sends a message to Bob and Coco
|
||||||
@ -636,7 +652,7 @@ void main() {
|
|||||||
aliceJid,
|
aliceJid,
|
||||||
aliceDevice.id,
|
aliceDevice.id,
|
||||||
DateTime.now().millisecondsSinceEpoch,
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
aliceResult!.encryptedKeys,
|
aliceResult.encryptedKeys,
|
||||||
base64.encode(aliceResult.ciphertext!),
|
base64.encode(aliceResult.ciphertext!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -661,8 +677,8 @@ void main() {
|
|||||||
const bobJid = 'bob@server2';
|
const bobJid = 'bob@server2';
|
||||||
var failure = false;
|
var failure = false;
|
||||||
|
|
||||||
final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1);
|
final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1);
|
||||||
final bobDevice = await Device.generateNewDevice(bobJid, opkAmount: 1);
|
final bobDevice = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1);
|
||||||
|
|
||||||
final aliceManager = OmemoManager(
|
final aliceManager = OmemoManager(
|
||||||
aliceDevice,
|
aliceDevice,
|
||||||
@ -682,6 +698,7 @@ void main() {
|
|||||||
null :
|
null :
|
||||||
bobDevice.toBundle();
|
bobDevice.toBundle();
|
||||||
},
|
},
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
final bobManager = OmemoManager(
|
final bobManager = OmemoManager(
|
||||||
bobDevice,
|
bobDevice,
|
||||||
@ -689,6 +706,7 @@ void main() {
|
|||||||
(result, recipientJid) async {},
|
(result, recipientJid) async {},
|
||||||
(jid) async => null,
|
(jid) async => null,
|
||||||
(jid, id) async => null,
|
(jid, id) async => null,
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Alice sends a message to Bob and Coco
|
// Alice sends a message to Bob and Coco
|
||||||
@ -705,7 +723,7 @@ void main() {
|
|||||||
aliceJid,
|
aliceJid,
|
||||||
aliceDevice.id,
|
aliceDevice.id,
|
||||||
DateTime.now().millisecondsSinceEpoch,
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
aliceResult1!.encryptedKeys,
|
aliceResult1.encryptedKeys,
|
||||||
base64.encode(aliceResult1.ciphertext!),
|
base64.encode(aliceResult1.ciphertext!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -737,7 +755,7 @@ void main() {
|
|||||||
aliceJid,
|
aliceJid,
|
||||||
aliceDevice.id,
|
aliceDevice.id,
|
||||||
DateTime.now().millisecondsSinceEpoch,
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
aliceResult2!.encryptedKeys,
|
aliceResult2.encryptedKeys,
|
||||||
base64.encode(aliceResult2.ciphertext!),
|
base64.encode(aliceResult2.ciphertext!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -750,7 +768,7 @@ void main() {
|
|||||||
const aliceJid = 'alice@server1';
|
const aliceJid = 'alice@server1';
|
||||||
const bobJid = 'bob@server2';
|
const bobJid = 'bob@server2';
|
||||||
|
|
||||||
final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1);
|
final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1);
|
||||||
|
|
||||||
final aliceManager = OmemoManager(
|
final aliceManager = OmemoManager(
|
||||||
aliceDevice,
|
aliceDevice,
|
||||||
@ -766,6 +784,7 @@ void main() {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Alice sends a message to Bob
|
// 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);
|
expect(aliceResult.jidEncryptionErrors[bobJid] is NoKeyMaterialAvailableException, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -785,8 +804,8 @@ void main() {
|
|||||||
const bobJid = 'bob@server2';
|
const bobJid = 'bob@server2';
|
||||||
const cocoJid = 'coco@server3';
|
const cocoJid = 'coco@server3';
|
||||||
|
|
||||||
final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1);
|
final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1);
|
||||||
final bobDevice = await Device.generateNewDevice(bobJid, opkAmount: 1);
|
final bobDevice = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1);
|
||||||
|
|
||||||
final aliceManager = OmemoManager(
|
final aliceManager = OmemoManager(
|
||||||
aliceDevice,
|
aliceDevice,
|
||||||
@ -806,6 +825,7 @@ void main() {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
final bobManager = OmemoManager(
|
final bobManager = OmemoManager(
|
||||||
bobDevice,
|
bobDevice,
|
||||||
@ -813,6 +833,7 @@ void main() {
|
|||||||
(result, recipientJid) async {},
|
(result, recipientJid) async {},
|
||||||
(jid) async => null,
|
(jid) async => null,
|
||||||
(jid, id) async => null,
|
(jid, id) async => null,
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Alice sends a message to Bob and Coco
|
// 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);
|
expect(aliceResult.jidEncryptionErrors[cocoJid] is NoKeyMaterialAvailableException, true);
|
||||||
|
|
||||||
// Bob decrypts it
|
// Bob decrypts it
|
||||||
@ -844,8 +865,8 @@ void main() {
|
|||||||
const aliceJid = 'alice@server1';
|
const aliceJid = 'alice@server1';
|
||||||
const bobJid = 'bob@server2';
|
const bobJid = 'bob@server2';
|
||||||
|
|
||||||
final aliceDevice = await Device.generateNewDevice(aliceJid, opkAmount: 1);
|
final aliceDevice = await OmemoDevice.generateNewDevice(aliceJid, opkAmount: 1);
|
||||||
final bobDevice = await Device.generateNewDevice(bobJid, opkAmount: 1);
|
final bobDevice = await OmemoDevice.generateNewDevice(bobJid, opkAmount: 1);
|
||||||
|
|
||||||
final aliceManager = OmemoManager(
|
final aliceManager = OmemoManager(
|
||||||
aliceDevice,
|
aliceDevice,
|
||||||
@ -861,6 +882,7 @@ void main() {
|
|||||||
|
|
||||||
return bobDevice.toBundle();
|
return bobDevice.toBundle();
|
||||||
},
|
},
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
final bobManager = OmemoManager(
|
final bobManager = OmemoManager(
|
||||||
bobDevice,
|
bobDevice,
|
||||||
@ -868,6 +890,7 @@ void main() {
|
|||||||
(result, recipientJid) async {},
|
(result, recipientJid) async {},
|
||||||
(jid) async => null,
|
(jid) async => null,
|
||||||
(jid, id) async => null,
|
(jid, id) async => null,
|
||||||
|
(jid) async {},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Alice encrypts a message for Bob
|
// Alice encrypts a message for Bob
|
||||||
@ -884,7 +907,7 @@ void main() {
|
|||||||
aliceJid,
|
aliceJid,
|
||||||
aliceDevice.id,
|
aliceDevice.id,
|
||||||
DateTime.now().millisecondsSinceEpoch,
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
aliceMessage!.encryptedKeys,
|
aliceMessage.encryptedKeys,
|
||||||
base64.encode(aliceMessage.ciphertext!),
|
base64.encode(aliceMessage.ciphertext!),
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -905,7 +928,7 @@ void main() {
|
|||||||
messageText,
|
messageText,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
expect(bobResponseMessage!.isSuccess(1), true);
|
expect(bobResponseMessage.isSuccess(1), true);
|
||||||
|
|
||||||
final aliceReceivedMessage = await aliceManager.onIncomingStanza(
|
final aliceReceivedMessage = await aliceManager.onIncomingStanza(
|
||||||
OmemoIncomingStanza(
|
OmemoIncomingStanza(
|
||||||
|
@ -18,7 +18,7 @@ void main() {
|
|||||||
final oldDevice = await oldSession.getDevice();
|
final oldDevice = await oldSession.getDevice();
|
||||||
final serialised = jsonify(await oldDevice.toJson());
|
final serialised = jsonify(await oldDevice.toJson());
|
||||||
|
|
||||||
final newDevice = Device.fromJson(serialised);
|
final newDevice = OmemoDevice.fromJson(serialised);
|
||||||
expect(await oldDevice.equals(newDevice), true);
|
expect(await oldDevice.equals(newDevice), true);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ void main() {
|
|||||||
final oldDevice = await (await oldSession.getDevice()).replaceSignedPrekey();
|
final oldDevice = await (await oldSession.getDevice()).replaceSignedPrekey();
|
||||||
final serialised = jsonify(await oldDevice.toJson());
|
final serialised = jsonify(await oldDevice.toJson());
|
||||||
|
|
||||||
final newDevice = Device.fromJson(serialised);
|
final newDevice = OmemoDevice.fromJson(serialised);
|
||||||
expect(await oldDevice.equals(newDevice), true);
|
expect(await oldDevice.equals(newDevice), true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user