feat: Add a base trust manager class
This commit is contained in:
parent
e9f190036c
commit
dafd0af1e5
@ -11,4 +11,6 @@ export 'src/omemo/encrypted_key.dart';
|
|||||||
export 'src/omemo/encryption_result.dart';
|
export 'src/omemo/encryption_result.dart';
|
||||||
export 'src/omemo/fingerprint.dart';
|
export 'src/omemo/fingerprint.dart';
|
||||||
export 'src/omemo/sessionmanager.dart';
|
export 'src/omemo/sessionmanager.dart';
|
||||||
|
export 'src/trust/base.dart';
|
||||||
|
//export 'src/trust/btbv.dart';
|
||||||
export 'src/x3dh/x3dh.dart';
|
export 'src/x3dh/x3dh.dart';
|
||||||
|
@ -19,6 +19,7 @@ import 'package:omemo_dart/src/omemo/ratchet_map_key.dart';
|
|||||||
import 'package:omemo_dart/src/protobuf/omemo_authenticated_message.dart';
|
import 'package:omemo_dart/src/protobuf/omemo_authenticated_message.dart';
|
||||||
import 'package:omemo_dart/src/protobuf/omemo_key_exchange.dart';
|
import 'package:omemo_dart/src/protobuf/omemo_key_exchange.dart';
|
||||||
import 'package:omemo_dart/src/protobuf/omemo_message.dart';
|
import 'package:omemo_dart/src/protobuf/omemo_message.dart';
|
||||||
|
import 'package:omemo_dart/src/trust/base.dart';
|
||||||
import 'package:omemo_dart/src/x3dh/x3dh.dart';
|
import 'package:omemo_dart/src/x3dh/x3dh.dart';
|
||||||
import 'package:synchronized/synchronized.dart';
|
import 'package:synchronized/synchronized.dart';
|
||||||
|
|
||||||
@ -27,13 +28,13 @@ const omemoPayloadInfoString = 'OMEMO Payload';
|
|||||||
|
|
||||||
class OmemoSessionManager {
|
class OmemoSessionManager {
|
||||||
|
|
||||||
OmemoSessionManager(this._device, this._deviceMap, this._ratchetMap)
|
OmemoSessionManager(this._device, this._deviceMap, this._ratchetMap, this._trustManager)
|
||||||
: _lock = Lock(),
|
: _lock = Lock(),
|
||||||
_deviceLock = Lock(),
|
_deviceLock = Lock(),
|
||||||
_eventStreamController = StreamController<OmemoEvent>.broadcast();
|
_eventStreamController = StreamController<OmemoEvent>.broadcast();
|
||||||
|
|
||||||
/// Deserialise the OmemoSessionManager from JSON data [data].
|
/// Deserialise the OmemoSessionManager from JSON data [data].
|
||||||
factory OmemoSessionManager.fromJson(Map<String, dynamic> data) {
|
factory OmemoSessionManager.fromJson(Map<String, dynamic> data, TrustManager trustManager) {
|
||||||
final ratchetMap = <RatchetMapKey, OmemoDoubleRatchet>{};
|
final ratchetMap = <RatchetMapKey, OmemoDoubleRatchet>{};
|
||||||
for (final rawRatchet in data['sessions']! as List<Map<String, dynamic>>) {
|
for (final rawRatchet in data['sessions']! as List<Map<String, dynamic>>) {
|
||||||
final key = RatchetMapKey(rawRatchet['jid']! as String, rawRatchet['deviceId']! as int);
|
final key = RatchetMapKey(rawRatchet['jid']! as String, rawRatchet['deviceId']! as int);
|
||||||
@ -41,20 +42,20 @@ class OmemoSessionManager {
|
|||||||
ratchetMap[key] = ratchet;
|
ratchetMap[key] = ratchet;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(PapaTutuWawa): Handle Trust behaviour
|
|
||||||
return OmemoSessionManager(
|
return OmemoSessionManager(
|
||||||
Device.fromJson(data['device']! as Map<String, dynamic>),
|
Device.fromJson(data['device']! as Map<String, dynamic>),
|
||||||
data['devices']! as Map<String, List<int>>,
|
data['devices']! as Map<String, List<int>>,
|
||||||
ratchetMap,
|
ratchetMap,
|
||||||
|
trustManager,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a new cryptographic identity.
|
/// Generate a new cryptographic identity.
|
||||||
static Future<OmemoSessionManager> generateNewIdentity(String jid, { 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 Device.generateNewDevice(jid, opkAmount: opkAmount);
|
||||||
|
|
||||||
return OmemoSessionManager(device, {}, {});
|
return OmemoSessionManager(device, {}, {}, trustManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lock for _ratchetMap and _bundleMap
|
/// Lock for _ratchetMap and _bundleMap
|
||||||
@ -75,6 +76,9 @@ class OmemoSessionManager {
|
|||||||
/// and its lock
|
/// and its lock
|
||||||
final Lock _deviceLock;
|
final Lock _deviceLock;
|
||||||
|
|
||||||
|
/// The trust manager
|
||||||
|
final TrustManager _trustManager;
|
||||||
|
|
||||||
/// A stream that receives events regarding the session
|
/// A stream that receives events regarding the session
|
||||||
Stream<OmemoEvent> get eventStream => _eventStreamController.stream;
|
Stream<OmemoEvent> get eventStream => _eventStreamController.stream;
|
||||||
|
|
||||||
@ -218,6 +222,9 @@ class OmemoSessionManager {
|
|||||||
// We assume that the user already checked if the session exists
|
// We assume that the user already checked if the session exists
|
||||||
for (final jid in jids) {
|
for (final jid in jids) {
|
||||||
for (final deviceId in _deviceMap[jid]!) {
|
for (final deviceId in _deviceMap[jid]!) {
|
||||||
|
// Only encrypt to devices that are trusted
|
||||||
|
if (!(await _trustManager.isTrusted(jid, deviceId))) continue;
|
||||||
|
|
||||||
final ratchetKey = RatchetMapKey(jid, deviceId);
|
final ratchetKey = RatchetMapKey(jid, deviceId);
|
||||||
final ratchet = _ratchetMap[ratchetKey]!;
|
final ratchet = _ratchetMap[ratchetKey]!;
|
||||||
final ciphertext = (await ratchet.ratchetEncrypt(keyPayload)).ciphertext;
|
final ciphertext = (await ratchet.ratchetEncrypt(keyPayload)).ciphertext;
|
||||||
|
11
lib/src/trust/always.dart
Normal file
11
lib/src/trust/always.dart
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import 'package:meta/meta.dart';
|
||||||
|
import 'package:omemo_dart/src/trust/base.dart';
|
||||||
|
|
||||||
|
/// Only use for testing!
|
||||||
|
/// An implementation of TrustManager that always trusts every device and thus
|
||||||
|
/// has no internal state.
|
||||||
|
@visibleForTesting
|
||||||
|
class AlwaysTrustingTrustManager extends TrustManager {
|
||||||
|
@override
|
||||||
|
Future<bool> isTrusted(String jid, int deviceId) async => true;
|
||||||
|
}
|
7
lib/src/trust/base.dart
Normal file
7
lib/src/trust/base.dart
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
/// The base class for managing trust in OMEMO sessions.
|
||||||
|
// ignore: one_member_abstracts
|
||||||
|
abstract class TrustManager {
|
||||||
|
/// Return true when the device with id [deviceId] of Jid [jid] is trusted, i.e. if an
|
||||||
|
/// encrypted message should be sent to this device. If not, return false.
|
||||||
|
Future<bool> isTrusted(String jid, int deviceId);
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:omemo_dart/omemo_dart.dart';
|
import 'package:omemo_dart/omemo_dart.dart';
|
||||||
|
import 'package:omemo_dart/src/trust/always.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
@ -10,8 +11,16 @@ void main() {
|
|||||||
var deviceModified = false;
|
var deviceModified = false;
|
||||||
var ratchetModified = 0;
|
var ratchetModified = 0;
|
||||||
var deviceMapModified = 0;
|
var deviceMapModified = 0;
|
||||||
final aliceSession = await OmemoSessionManager.generateNewIdentity(aliceJid, opkAmount: 1);
|
final aliceSession = await OmemoSessionManager.generateNewIdentity(
|
||||||
final bobSession = await OmemoSessionManager.generateNewIdentity(bobJid, opkAmount: 1);
|
aliceJid,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
|
final bobSession = await OmemoSessionManager.generateNewIdentity(
|
||||||
|
bobJid,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
final bobOpks = (await bobSession.getDevice()).opks.values.toList();
|
final bobOpks = (await bobSession.getDevice()).opks.values.toList();
|
||||||
bobSession.eventStream.listen((event) {
|
bobSession.eventStream.listen((event) {
|
||||||
if (event is DeviceModifiedEvent) {
|
if (event is DeviceModifiedEvent) {
|
||||||
@ -83,10 +92,22 @@ void main() {
|
|||||||
const bobJid = 'bob@other.server.example';
|
const bobJid = 'bob@other.server.example';
|
||||||
|
|
||||||
// Alice and Bob generate their sessions
|
// Alice and Bob generate their sessions
|
||||||
final aliceSession = await OmemoSessionManager.generateNewIdentity(aliceJid, opkAmount: 1);
|
final aliceSession = await OmemoSessionManager.generateNewIdentity(
|
||||||
final bobSession = await OmemoSessionManager.generateNewIdentity(bobJid, opkAmount: 1);
|
aliceJid,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
|
final bobSession = await OmemoSessionManager.generateNewIdentity(
|
||||||
|
bobJid,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
// Bob's other device
|
// Bob's other device
|
||||||
final bobSession2 = await OmemoSessionManager.generateNewIdentity(bobJid, opkAmount: 1);
|
final bobSession2 = await OmemoSessionManager.generateNewIdentity(
|
||||||
|
bobJid,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
|
|
||||||
// Alice encrypts a message for Bob
|
// Alice encrypts a message for Bob
|
||||||
const messagePlaintext = 'Hello Bob!';
|
const messagePlaintext = 'Hello Bob!';
|
||||||
@ -149,9 +170,21 @@ void main() {
|
|||||||
const bobJid = 'bob@other.server.example';
|
const bobJid = 'bob@other.server.example';
|
||||||
|
|
||||||
// Alice and Bob generate their sessions
|
// Alice and Bob generate their sessions
|
||||||
final aliceSession1 = await OmemoSessionManager.generateNewIdentity(aliceJid, opkAmount: 1);
|
final aliceSession1 = await OmemoSessionManager.generateNewIdentity(
|
||||||
final aliceSession2 = await OmemoSessionManager.generateNewIdentity(aliceJid, opkAmount: 1);
|
aliceJid,
|
||||||
final bobSession = await OmemoSessionManager.generateNewIdentity(bobJid, opkAmount: 1);
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
|
final aliceSession2 = await OmemoSessionManager.generateNewIdentity(
|
||||||
|
aliceJid,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
|
final bobSession = await OmemoSessionManager.generateNewIdentity(
|
||||||
|
bobJid,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
|
|
||||||
// Alice encrypts a message for Bob
|
// Alice encrypts a message for Bob
|
||||||
const messagePlaintext = 'Hello Bob!';
|
const messagePlaintext = 'Hello Bob!';
|
||||||
@ -192,8 +225,16 @@ void main() {
|
|||||||
const bobJid = 'bob@other.server.example';
|
const bobJid = 'bob@other.server.example';
|
||||||
|
|
||||||
// Alice and Bob generate their sessions
|
// Alice and Bob generate their sessions
|
||||||
final aliceSession = await OmemoSessionManager.generateNewIdentity(aliceJid, opkAmount: 1);
|
final aliceSession = await OmemoSessionManager.generateNewIdentity(
|
||||||
final bobSession = await OmemoSessionManager.generateNewIdentity(bobJid, opkAmount: 1);
|
aliceJid,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
|
final bobSession = await OmemoSessionManager.generateNewIdentity(
|
||||||
|
bobJid,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
|
|
||||||
// Alice encrypts a message for Bob
|
// Alice encrypts a message for Bob
|
||||||
final aliceMessage = await aliceSession.encryptToJid(
|
final aliceMessage = await aliceSession.encryptToJid(
|
||||||
@ -225,7 +266,11 @@ void main() {
|
|||||||
test('Test rotating the Signed Prekey', () async {
|
test('Test rotating the Signed Prekey', () async {
|
||||||
// Generate the session
|
// Generate the session
|
||||||
const aliceJid = 'alice@some.server';
|
const aliceJid = 'alice@some.server';
|
||||||
final aliceSession = await OmemoSessionManager.generateNewIdentity(aliceJid, opkAmount: 1);
|
final aliceSession = await OmemoSessionManager.generateNewIdentity(
|
||||||
|
aliceJid,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
|
|
||||||
// Setup an event listener
|
// Setup an event listener
|
||||||
final oldDevice = await aliceSession.getDevice();
|
final oldDevice = await aliceSession.getDevice();
|
||||||
@ -254,8 +299,16 @@ void main() {
|
|||||||
const bobJid = 'bob@other.server.example';
|
const bobJid = 'bob@other.server.example';
|
||||||
|
|
||||||
// Alice and Bob generate their sessions
|
// Alice and Bob generate their sessions
|
||||||
final aliceSession = await OmemoSessionManager.generateNewIdentity(aliceJid, opkAmount: 1);
|
final aliceSession = await OmemoSessionManager.generateNewIdentity(
|
||||||
final bobSession = await OmemoSessionManager.generateNewIdentity(bobJid, opkAmount: 1);
|
aliceJid,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
|
final bobSession = await OmemoSessionManager.generateNewIdentity(
|
||||||
|
bobJid,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
|
|
||||||
// Alice encrypts a message for Bob
|
// Alice encrypts a message for Bob
|
||||||
const messagePlaintext = 'Hello Bob!';
|
const messagePlaintext = 'Hello Bob!';
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
import 'package:omemo_dart/omemo_dart.dart';
|
import 'package:omemo_dart/omemo_dart.dart';
|
||||||
|
import 'package:omemo_dart/src/trust/always.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('Test serialising and deserialising the Device', () async {
|
test('Test serialising and deserialising the Device', () async {
|
||||||
// Generate a random session
|
// Generate a random session
|
||||||
final oldSession = await OmemoSessionManager.generateNewIdentity('user@test.server', opkAmount: 1);
|
final oldSession = await OmemoSessionManager.generateNewIdentity(
|
||||||
|
'user@test.server',
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
final oldDevice = await oldSession.getDevice();
|
final oldDevice = await oldSession.getDevice();
|
||||||
final serialised = await oldDevice.toJson();
|
final serialised = await oldDevice.toJson();
|
||||||
|
|
||||||
@ -14,7 +19,11 @@ void main() {
|
|||||||
|
|
||||||
test('Test serialising and deserialising the Device after rotating the SPK', () async {
|
test('Test serialising and deserialising the Device after rotating the SPK', () async {
|
||||||
// Generate a random session
|
// Generate a random session
|
||||||
final oldSession = await OmemoSessionManager.generateNewIdentity('user@test.server', opkAmount: 1);
|
final oldSession = await OmemoSessionManager.generateNewIdentity(
|
||||||
|
'user@test.server',
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
final oldDevice = await (await oldSession.getDevice()).replaceSignedPrekey();
|
final oldDevice = await (await oldSession.getDevice()).replaceSignedPrekey();
|
||||||
final serialised = await oldDevice.toJson();
|
final serialised = await oldDevice.toJson();
|
||||||
|
|
||||||
@ -26,8 +35,16 @@ void main() {
|
|||||||
// Generate a random ratchet
|
// Generate a random ratchet
|
||||||
const aliceJid = 'alice@server.example';
|
const aliceJid = 'alice@server.example';
|
||||||
const bobJid = 'bob@other.server.example';
|
const bobJid = 'bob@other.server.example';
|
||||||
final aliceSession = await OmemoSessionManager.generateNewIdentity(aliceJid, opkAmount: 1);
|
final aliceSession = await OmemoSessionManager.generateNewIdentity(
|
||||||
final bobSession = await OmemoSessionManager.generateNewIdentity(bobJid, opkAmount: 1);
|
aliceJid,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
|
final bobSession = await OmemoSessionManager.generateNewIdentity(
|
||||||
|
bobJid,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 1,
|
||||||
|
);
|
||||||
final aliceMessage = await aliceSession.encryptToJid(
|
final aliceMessage = await aliceSession.encryptToJid(
|
||||||
bobJid,
|
bobJid,
|
||||||
'Hello Bob!',
|
'Hello Bob!',
|
||||||
@ -50,8 +67,16 @@ void main() {
|
|||||||
|
|
||||||
test('Test serialising and deserialising the OmemoSessionManager', () async {
|
test('Test serialising and deserialising the OmemoSessionManager', () async {
|
||||||
// Generate a random session
|
// Generate a random session
|
||||||
final oldSession = await OmemoSessionManager.generateNewIdentity('a@server', opkAmount: 4);
|
final oldSession = await OmemoSessionManager.generateNewIdentity(
|
||||||
final bobSession = await OmemoSessionManager.generateNewIdentity('b@other.server', opkAmount: 4);
|
'a@server',
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 4,
|
||||||
|
);
|
||||||
|
final bobSession = await OmemoSessionManager.generateNewIdentity(
|
||||||
|
'b@other.server',
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
opkAmount: 4,
|
||||||
|
);
|
||||||
await oldSession.addSessionFromBundle(
|
await oldSession.addSessionFromBundle(
|
||||||
'bob@localhost',
|
'bob@localhost',
|
||||||
(await bobSession.getDevice()).id,
|
(await bobSession.getDevice()).id,
|
||||||
@ -60,7 +85,10 @@ void main() {
|
|||||||
|
|
||||||
// Serialise and deserialise
|
// Serialise and deserialise
|
||||||
final serialised = await oldSession.toJson();
|
final serialised = await oldSession.toJson();
|
||||||
final newSession = OmemoSessionManager.fromJson(serialised);
|
final newSession = OmemoSessionManager.fromJson(
|
||||||
|
serialised,
|
||||||
|
AlwaysTrustingTrustManager(),
|
||||||
|
);
|
||||||
|
|
||||||
final oldDevice = await oldSession.getDevice();
|
final oldDevice = await oldSession.getDevice();
|
||||||
final newDevice = await newSession.getDevice();
|
final newDevice = await newSession.getDevice();
|
||||||
|
Loading…
Reference in New Issue
Block a user