feat: Make BlindTrustBeforeVerificationTrustManager abstract

This commit is contained in:
PapaTutuWawa 2022-08-08 18:58:53 +02:00
parent c1fb79a20f
commit 5158c32c3d
2 changed files with 51 additions and 21 deletions

View File

@ -13,29 +13,33 @@ enum BTBVTrustState {
verified, verified,
} }
class BlindTrustBeforeVerificationTrustManager extends TrustManager { /// A TrustManager that implements the idea of Blind Trust Before Verification.
/// See https://gultsch.de/trust.html for more details.
abstract class BlindTrustBeforeVerificationTrustManager extends TrustManager {
BlindTrustBeforeVerificationTrustManager() BlindTrustBeforeVerificationTrustManager()
: _trustCache = {}, : trustCache = {},
_devices = {}, devices = {},
_lock = Lock(); _lock = Lock();
/// The cache for Mapping a RatchetMapKey to its trust state /// The cache for Mapping a RatchetMapKey to its trust state
final Map<RatchetMapKey, BTBVTrustState> _trustCache; @protected
final Map<RatchetMapKey, BTBVTrustState> trustCache;
/// Mapping of Jids to their device identifiers /// Mapping of Jids to their device identifiers
final Map<String, List<int>> _devices; @protected
final Map<String, List<int>> devices;
/// The lock for _devices and _trustCache /// The lock for devices and trustCache
final Lock _lock; final Lock _lock;
/// 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.
bool _hasAtLeastOneVerifiedDevice(String jid) { bool _hasAtLeastOneVerifiedDevice(String jid) {
if (!_devices.containsKey(jid)) return false; if (!devices.containsKey(jid)) return false;
return _devices[jid]!.any((id) { return devices[jid]!.any((id) {
return _trustCache[RatchetMapKey(jid, id)]! == BTBVTrustState.verified; return trustCache[RatchetMapKey(jid, id)]! == BTBVTrustState.verified;
}); });
} }
@ -43,7 +47,7 @@ class BlindTrustBeforeVerificationTrustManager extends TrustManager {
Future<bool> isTrusted(String jid, int deviceId) async { Future<bool> isTrusted(String jid, int deviceId) async {
var returnValue = false; var returnValue = false;
await _lock.synchronized(() async { await _lock.synchronized(() async {
final trustCacheValue = _trustCache[RatchetMapKey(jid, deviceId)]; final trustCacheValue = trustCache[RatchetMapKey(jid, deviceId)];
if (trustCacheValue == BTBVTrustState.notTrusted) { if (trustCacheValue == BTBVTrustState.notTrusted) {
returnValue = false; returnValue = false;
return; return;
@ -71,16 +75,19 @@ class BlindTrustBeforeVerificationTrustManager extends TrustManager {
Future<void> onNewSession(String jid, int deviceId) async { Future<void> onNewSession(String jid, int deviceId) async {
await _lock.synchronized(() async { await _lock.synchronized(() async {
if (_hasAtLeastOneVerifiedDevice(jid)) { if (_hasAtLeastOneVerifiedDevice(jid)) {
_trustCache[RatchetMapKey(jid, deviceId)] = BTBVTrustState.notTrusted; trustCache[RatchetMapKey(jid, deviceId)] = BTBVTrustState.notTrusted;
} else { } else {
_trustCache[RatchetMapKey(jid, deviceId)] = BTBVTrustState.blindTrust; trustCache[RatchetMapKey(jid, deviceId)] = BTBVTrustState.blindTrust;
} }
if (_devices.containsKey(jid)) { if (devices.containsKey(jid)) {
_devices[jid]!.add(deviceId); devices[jid]!.add(deviceId);
} else { } else {
_devices[jid] = List<int>.from([deviceId]); devices[jid] = List<int>.from([deviceId]);
} }
// Commit the state
await commitState();
}); });
} }
@ -89,8 +96,8 @@ class BlindTrustBeforeVerificationTrustManager extends TrustManager {
final map = <int, BTBVTrustState>{}; final map = <int, BTBVTrustState>{};
await _lock.synchronized(() async { await _lock.synchronized(() async {
for (final deviceId in _devices[jid]!) { for (final deviceId in devices[jid]!) {
map[deviceId] = _trustCache[RatchetMapKey(jid, deviceId)]!; map[deviceId] = trustCache[RatchetMapKey(jid, deviceId)]!;
} }
}); });
@ -100,10 +107,33 @@ class BlindTrustBeforeVerificationTrustManager extends TrustManager {
/// Sets the trust of [jid]'s device with identifier [deviceId] to [state]. /// Sets the trust of [jid]'s device with identifier [deviceId] to [state].
Future<void> setDeviceTrust(String jid, int deviceId, BTBVTrustState state) async { Future<void> setDeviceTrust(String jid, int deviceId, BTBVTrustState state) async {
await _lock.synchronized(() async { await _lock.synchronized(() async {
_trustCache[RatchetMapKey(jid, deviceId)] = state; trustCache[RatchetMapKey(jid, deviceId)] = state;
// Commit the state
await commitState();
}); });
} }
/// Called when the state of the trust manager has been changed. Allows the user to
/// commit the trust state to persistent storage.
@visibleForOverriding
Future<void> commitState();
/// Called when the user wants to restore the state of the trust manager. The format
/// and actual storage mechanism is left to the user.
@visibleForOverriding
Future<void> loadState();
@visibleForTesting @visibleForTesting
BTBVTrustState getDeviceTrust(String jid, int deviceId) => _trustCache[RatchetMapKey(jid, deviceId)]!; BTBVTrustState getDeviceTrust(String jid, int 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 {}
@override
Future<void> loadState() async {}
} }

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 = BlindTrustBeforeVerificationTrustManager(); final btbv = MemoryBTBVTrustManager();
// Example data // Example data
const aliceJid = 'alice@some.server'; const aliceJid = 'alice@some.server';
const bobJid = 'bob@other.server'; const bobJid = 'bob@other.server';