feat: Stop overriding the BTBV manager

This commit is contained in:
PapaTutuWawa 2023-06-17 15:21:11 +02:00
parent 28e7ad59b0
commit 4fb25a3ab7
6 changed files with 89 additions and 109 deletions

View File

@ -42,7 +42,7 @@ void main() async {
// request it using PEP and then convert the device bundle into a OmemoBundle object. // request it using PEP and then convert the device bundle into a OmemoBundle object.
final bobManager = OmemoManager( final bobManager = OmemoManager(
await OmemoDevice.generateNewDevice(bobJid), await OmemoDevice.generateNewDevice(bobJid),
MemoryBTBVTrustManager(), BlindTrustBeforeVerificationTrustManager(),
(result, recipient) async => {}, (result, recipient) async => {},
(jid) async => [], (jid) async => [],
(jid, id) async => null, (jid, id) async => null,

View File

@ -20,7 +20,4 @@ class AlwaysTrustingTrustManager extends TrustManager {
@override @override
Future<void> removeTrustDecisionsForJid(String jid) async {} Future<void> removeTrustDecisionsForJid(String jid) async {}
@override
Future<Map<String, dynamic>> toJson() async => <String, dynamic>{};
} }

View File

@ -17,9 +17,6 @@ abstract class TrustManager {
/// if [enabled] is false. /// if [enabled] is false.
Future<void> setEnabled(String jid, int deviceId, bool enabled); Future<void> setEnabled(String jid, int deviceId, bool enabled);
/// Serialize the trust manager to JSON.
Future<Map<String, dynamic>> toJson();
/// Removes all trust decisions for [jid]. /// Removes all trust decisions for [jid].
Future<void> removeTrustDecisionsForJid(String jid); Future<void> removeTrustDecisionsForJid(String jid);
} }

View File

@ -3,47 +3,64 @@ import 'package:omemo_dart/src/omemo/ratchet_map_key.dart';
import 'package:omemo_dart/src/trust/base.dart'; import 'package:omemo_dart/src/trust/base.dart';
import 'package:synchronized/synchronized.dart'; import 'package:synchronized/synchronized.dart';
@immutable
class BTBVTrustData {
const BTBVTrustData(
this.jid,
this.device,
this.state,
this.enabled,
);
/// The JID in question.
final String jid;
/// The device (ratchet) in question.
final int device;
/// The trust state of the ratchet.
final BTBVTrustState state;
/// Flag indicating whether the ratchet is enabled (true) or not (false).
final bool enabled;
}
/// A callback for when a trust decision is to be commited to persistent storage.
typedef BTBVTrustCommitCallback = Future<void> Function(BTBVTrustData data);
/// A stub-implementation of [BTBVTrustCommitCallback].
Future<void> btbvCommitStub(BTBVTrustData _) async {}
/// A callback for when all trust decisions for a JID should be removed from persistent storage.
typedef BTBVRemoveTrustForJidCallback = Future<void> Function(String jid);
/// A stub-implementation of [BTBVRemoveTrustForJidCallback].
Future<void> btbvRemoveTrustStub(String _) async {}
/// Every device is in either of those two trust states: /// Every device is in either of those two trust states:
/// - notTrusted: The device is absolutely not trusted /// - notTrusted: The device is absolutely not trusted
/// - blindTrust: The fingerprint is not verified using OOB means /// - blindTrust: The fingerprint is not verified using OOB means
/// - verified: The fingerprint has been verified using OOB means /// - verified: The fingerprint has been verified using OOB means
enum BTBVTrustState { enum BTBVTrustState {
notTrusted, // = 1 notTrusted(1),
blindTrust, // = 2 blindTrust(2),
verified, // = 3 verified(3);
}
int _trustToInt(BTBVTrustState state) { const BTBVTrustState(this.value);
switch (state) {
case BTBVTrustState.notTrusted:
return 1;
case BTBVTrustState.blindTrust:
return 2;
case BTBVTrustState.verified:
return 3;
}
}
BTBVTrustState _trustFromInt(int i) { /// The value backing the trust state.
switch (i) { final int value;
case 1:
return BTBVTrustState.notTrusted;
case 2:
return BTBVTrustState.blindTrust;
case 3:
return BTBVTrustState.verified;
default:
return BTBVTrustState.notTrusted;
}
} }
/// A TrustManager that implements the idea of Blind Trust Before Verification. /// A TrustManager that implements the idea of Blind Trust Before Verification.
/// See https://gultsch.de/trust.html for more details. /// See https://gultsch.de/trust.html for more details.
abstract class BlindTrustBeforeVerificationTrustManager extends TrustManager { class BlindTrustBeforeVerificationTrustManager extends TrustManager {
BlindTrustBeforeVerificationTrustManager({ BlindTrustBeforeVerificationTrustManager({
Map<RatchetMapKey, BTBVTrustState>? trustCache, Map<RatchetMapKey, BTBVTrustState>? trustCache,
Map<RatchetMapKey, bool>? enablementCache, Map<RatchetMapKey, bool>? enablementCache,
Map<String, List<int>>? devices, Map<String, List<int>>? devices,
this.commit = btbvCommitStub,
this.removeTrust = btbvRemoveTrustStub,
}) : trustCache = trustCache ?? {}, }) : trustCache = trustCache ?? {},
enablementCache = enablementCache ?? {}, enablementCache = enablementCache ?? {},
devices = devices ?? {}, devices = devices ?? {},
@ -67,6 +84,12 @@ abstract class BlindTrustBeforeVerificationTrustManager extends TrustManager {
/// The lock for devices and trustCache /// The lock for devices and trustCache
final Lock _lock; final Lock _lock;
/// Callback for commiting trust data to persistent storage.
final BTBVTrustCommitCallback commit;
/// Callback for removing trust data for a JID.
final BTBVRemoveTrustForJidCallback removeTrust;
/// Returns true if [jid] has at least one device that is verified. If not, returns false. /// Returns true if [jid] has at least one device that is verified. If not, returns false.
/// Note that this function accesses devices and trustCache, which requires that the /// Note that this function accesses devices and trustCache, which requires that the
/// lock for those two maps (_lock) has been aquired before calling. /// lock for those two maps (_lock) has been aquired before calling.
@ -125,7 +148,14 @@ abstract class BlindTrustBeforeVerificationTrustManager extends TrustManager {
} }
// Commit the state // Commit the state
await commitState(); await commit(
BTBVTrustData(
jid,
deviceId,
trustCache[key]!,
enablementCache[key]!,
),
);
}); });
} }
@ -152,10 +182,18 @@ abstract class BlindTrustBeforeVerificationTrustManager extends TrustManager {
BTBVTrustState state, BTBVTrustState state,
) async { ) async {
await _lock.synchronized(() async { await _lock.synchronized(() async {
trustCache[RatchetMapKey(jid, deviceId)] = state; final key = RatchetMapKey(jid, deviceId);
trustCache[key] = state;
// Commit the state // Commit the state
await commitState(); await commit(
BTBVTrustData(
jid,
deviceId,
state,
enablementCache[key]!,
),
);
}); });
} }
@ -171,88 +209,39 @@ abstract class BlindTrustBeforeVerificationTrustManager extends TrustManager {
@override @override
Future<void> setEnabled(String jid, int deviceId, bool enabled) async { Future<void> setEnabled(String jid, int deviceId, bool enabled) async {
final key = RatchetMapKey(jid, deviceId);
await _lock.synchronized(() async { await _lock.synchronized(() async {
enablementCache[RatchetMapKey(jid, deviceId)] = enabled; enablementCache[key] = enabled;
});
// Commit the state // Commit the state
await commitState(); await commit(
} BTBVTrustData(
jid,
@override deviceId,
Future<Map<String, dynamic>> toJson() async { trustCache[key]!,
return { enabled,
'devices': devices,
'trust': trustCache.map(
(key, value) => MapEntry(
key.toJsonKey(),
_trustToInt(value),
), ),
), );
'enable': });
enablementCache.map((key, value) => MapEntry(key.toJsonKey(), value)),
};
}
/// From a serialized version of a BTBV trust manager, extract the device list.
/// NOTE: This is needed as Dart cannot just cast a List<dynamic> to List<int> and so on.
static Map<String, List<int>> deviceListFromJson(Map<String, dynamic> json) {
return (json['devices']! as Map<String, dynamic>).map<String, List<int>>(
(key, value) => MapEntry(
key,
(value as List<dynamic>).map<int>((i) => i as int).toList(),
),
);
}
/// From a serialized version of a BTBV trust manager, extract the trust cache.
/// NOTE: This is needed as Dart cannot just cast a List<dynamic> to List<int> and so on.
static Map<RatchetMapKey, BTBVTrustState> trustCacheFromJson(
Map<String, dynamic> json,
) {
return (json['trust']! as Map<String, dynamic>)
.map<RatchetMapKey, BTBVTrustState>(
(key, value) => MapEntry(
RatchetMapKey.fromJsonKey(key),
_trustFromInt(value as int),
),
);
}
/// From a serialized version of a BTBV trust manager, extract the enable cache.
/// NOTE: This is needed as Dart cannot just cast a List<dynamic> to List<int> and so on.
static Map<RatchetMapKey, bool> enableCacheFromJson(
Map<String, dynamic> json,
) {
return (json['enable']! as Map<String, dynamic>).map<RatchetMapKey, bool>(
(key, value) => MapEntry(
RatchetMapKey.fromJsonKey(key),
value as bool,
),
);
} }
@override @override
Future<void> removeTrustDecisionsForJid(String jid) async { Future<void> removeTrustDecisionsForJid(String jid) async {
await _lock.synchronized(() async { await _lock.synchronized(() async {
// Clear the caches
for (final device in devices[jid]!) {
final key = RatchetMapKey(jid, device);
trustCache.remove(key);
enablementCache.remove(key);
}
devices.remove(jid); devices.remove(jid);
await commitState();
// Commit the state
await removeTrust(jid);
}); });
} }
/// Called when the state of the trust manager has been changed. Allows the user to
/// commit the trust state to persistent storage.
@visibleForOverriding
Future<void> commitState();
@visibleForTesting @visibleForTesting
BTBVTrustState getDeviceTrust(String jid, int deviceId) => BTBVTrustState getDeviceTrust(String jid, int deviceId) =>
trustCache[RatchetMapKey(jid, deviceId)]!; trustCache[RatchetMapKey(jid, deviceId)]!;
} }
/// A BTBV TrustManager that does not commit its state to persistent storage. Well suited
/// for testing.
class MemoryBTBVTrustManager extends BlindTrustBeforeVerificationTrustManager {
@override
Future<void> commitState() async {}
}

View File

@ -20,7 +20,4 @@ class NeverTrustingTrustManager extends TrustManager {
@override @override
Future<void> removeTrustDecisionsForJid(String jid) async {} Future<void> removeTrustDecisionsForJid(String jid) async {}
@override
Future<Map<String, dynamic>> toJson() async => <String, dynamic>{};
} }

View File

@ -4,7 +4,7 @@ import 'package:test/test.dart';
void main() { void main() {
test('Test the Blind Trust Before Verification TrustManager', () async { test('Test the Blind Trust Before Verification TrustManager', () async {
// Caroline's BTBV manager // Caroline's BTBV manager
final btbv = MemoryBTBVTrustManager(); final btbv = BlindTrustBeforeVerificationTrustManager();
// Example data // Example data
const aliceJid = 'alice@some.server'; const aliceJid = 'alice@some.server';
const bobJid = 'bob@other.server'; const bobJid = 'bob@other.server';