feat: Remove locking from the BTBV trust manager
This commit is contained in:
parent
dad85b8467
commit
ed0701bdcd
@ -169,7 +169,6 @@ class OmemoManager {
|
|||||||
|
|
||||||
/// The OmemoManager's trust management
|
/// The OmemoManager's trust management
|
||||||
final TrustManager _trustManager;
|
final TrustManager _trustManager;
|
||||||
TrustManager get trustManager => _trustManager;
|
|
||||||
|
|
||||||
/// Our own keys...
|
/// Our own keys...
|
||||||
final Lock _deviceLock = Lock();
|
final Lock _deviceLock = Lock();
|
||||||
@ -200,7 +199,7 @@ class OmemoManager {
|
|||||||
_ratchetMap.addAll(result.ratchets);
|
_ratchetMap.addAll(result.ratchets);
|
||||||
|
|
||||||
// Load trust data
|
// Load trust data
|
||||||
await trustManager.loadTrustData(jid);
|
await _trustManager.loadTrustData(jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Result<OmemoError, String?>> _decryptAndVerifyHmac(
|
Future<Result<OmemoError, String?>> _decryptAndVerifyHmac(
|
||||||
@ -449,7 +448,7 @@ class OmemoManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Notify the trust manager
|
// Notify the trust manager
|
||||||
await trustManager.onNewSession(
|
await _trustManager.onNewSession(
|
||||||
stanza.bareSenderJid,
|
stanza.bareSenderJid,
|
||||||
stanza.senderDeviceId,
|
stanza.senderDeviceId,
|
||||||
);
|
);
|
||||||
@ -653,7 +652,7 @@ class OmemoManager {
|
|||||||
addedRatchetKeys.add(ratchetKey);
|
addedRatchetKeys.add(ratchetKey);
|
||||||
|
|
||||||
// Initiate trust
|
// Initiate trust
|
||||||
await trustManager.onNewSession(jid, bundle.id);
|
await _trustManager.onNewSession(jid, bundle.id);
|
||||||
|
|
||||||
// Track the KEX for later
|
// Track the KEX for later
|
||||||
final ik = await ownDevice.ik.pk.getBytes();
|
final ik = await ownDevice.ik.pk.getBytes();
|
||||||
@ -940,4 +939,13 @@ class OmemoManager {
|
|||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
OmemoDoubleRatchet? getRatchet(RatchetMapKey key) => _ratchetMap[key];
|
OmemoDoubleRatchet? getRatchet(RatchetMapKey key) => _ratchetMap[key];
|
||||||
|
|
||||||
|
/// Trust management functions
|
||||||
|
Future<void> withTrustManager(
|
||||||
|
String jid, Future<void> Function(TrustManager) callback) async {
|
||||||
|
await _ratchetQueue.synchronized(
|
||||||
|
[jid],
|
||||||
|
() => callback(_trustManager),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ abstract class TrustManager {
|
|||||||
|
|
||||||
/// Called by the OmemoSessionManager when a new session has been built. Should set
|
/// Called by the OmemoSessionManager when a new session has been built. Should set
|
||||||
/// a default trust state to [jid]'s device with identifier [deviceId].
|
/// a default trust state to [jid]'s device with identifier [deviceId].
|
||||||
|
@internal
|
||||||
Future<void> onNewSession(String jid, int deviceId);
|
Future<void> onNewSession(String jid, int deviceId);
|
||||||
|
|
||||||
/// Return true if the device with id [deviceId] of Jid [jid] should be used for encryption.
|
/// Return true if the device with id [deviceId] of Jid [jid] should be used for encryption.
|
||||||
@ -20,6 +21,7 @@ abstract class TrustManager {
|
|||||||
Future<void> setEnabled(String jid, int deviceId, bool enabled);
|
Future<void> setEnabled(String jid, int deviceId, bool enabled);
|
||||||
|
|
||||||
/// Removes all trust decisions for [jid].
|
/// Removes all trust decisions for [jid].
|
||||||
|
@internal
|
||||||
Future<void> removeTrustDecisionsForJid(String jid);
|
Future<void> removeTrustDecisionsForJid(String jid);
|
||||||
|
|
||||||
// ignore: comment_references
|
// ignore: comment_references
|
||||||
|
@ -2,7 +2,6 @@ import 'package:meta/meta.dart';
|
|||||||
import 'package:omemo_dart/src/helpers.dart';
|
import 'package:omemo_dart/src/helpers.dart';
|
||||||
import 'package:omemo_dart/src/omemo/ratchet_map_key.dart';
|
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';
|
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
class BTBVTrustData {
|
class BTBVTrustData {
|
||||||
@ -83,9 +82,6 @@ class BlindTrustBeforeVerificationTrustManager extends TrustManager {
|
|||||||
@protected
|
@protected
|
||||||
final Map<String, List<int>> devices = {};
|
final Map<String, List<int>> devices = {};
|
||||||
|
|
||||||
/// The lock for devices and trustCache
|
|
||||||
final Lock _lock = Lock();
|
|
||||||
|
|
||||||
/// Callback for loading trust data.
|
/// Callback for loading trust data.
|
||||||
final BTBVLoadDataCallback loadData;
|
final BTBVLoadDataCallback loadData;
|
||||||
|
|
||||||
@ -108,76 +104,63 @@ class BlindTrustBeforeVerificationTrustManager extends TrustManager {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> isTrusted(String jid, int deviceId) async {
|
Future<bool> isTrusted(String jid, int deviceId) async {
|
||||||
var returnValue = false;
|
final trustCacheValue = trustCache[RatchetMapKey(jid, deviceId)];
|
||||||
await _lock.synchronized(() async {
|
if (trustCacheValue == BTBVTrustState.notTrusted) {
|
||||||
final trustCacheValue = trustCache[RatchetMapKey(jid, deviceId)];
|
return false;
|
||||||
if (trustCacheValue == BTBVTrustState.notTrusted) {
|
} else if (trustCacheValue == BTBVTrustState.verified) {
|
||||||
returnValue = false;
|
// The key is verified, so it's safe.
|
||||||
return;
|
return true;
|
||||||
} else if (trustCacheValue == BTBVTrustState.verified) {
|
} else {
|
||||||
// The key is verified, so it's safe.
|
if (_hasAtLeastOneVerifiedDevice(jid)) {
|
||||||
returnValue = true;
|
// Do not trust if there is at least one device with full trust
|
||||||
return;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
if (_hasAtLeastOneVerifiedDevice(jid)) {
|
// We have not verified a key from [jid], so it is blind trust all the way.
|
||||||
// Do not trust if there is at least one device with full trust
|
return true;
|
||||||
returnValue = false;
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
// We have not verified a key from [jid], so it is blind trust all the way.
|
|
||||||
returnValue = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
return returnValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> onNewSession(String jid, int deviceId) async {
|
Future<void> onNewSession(String jid, int deviceId) async {
|
||||||
await _lock.synchronized(() async {
|
final key = RatchetMapKey(jid, deviceId);
|
||||||
final key = RatchetMapKey(jid, deviceId);
|
if (_hasAtLeastOneVerifiedDevice(jid)) {
|
||||||
if (_hasAtLeastOneVerifiedDevice(jid)) {
|
trustCache[key] = BTBVTrustState.notTrusted;
|
||||||
trustCache[key] = BTBVTrustState.notTrusted;
|
enablementCache[key] = false;
|
||||||
enablementCache[key] = false;
|
} else {
|
||||||
} else {
|
trustCache[key] = BTBVTrustState.blindTrust;
|
||||||
trustCache[key] = BTBVTrustState.blindTrust;
|
enablementCache[key] = true;
|
||||||
enablementCache[key] = true;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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
|
// Commit the state
|
||||||
await commit(
|
await commit(
|
||||||
BTBVTrustData(
|
BTBVTrustData(
|
||||||
jid,
|
jid,
|
||||||
deviceId,
|
deviceId,
|
||||||
trustCache[key]!,
|
trustCache[key]!,
|
||||||
enablementCache[key]!,
|
enablementCache[key]!,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a mapping from the device identifiers of [jid] to their trust state. If
|
/// Returns a mapping from the device identifiers of [jid] to their trust state. If
|
||||||
/// there are no devices known for [jid], then an empty map is returned.
|
/// there are no devices known for [jid], then an empty map is returned.
|
||||||
Future<Map<int, BTBVTrustState>> getDevicesTrust(String jid) async {
|
Future<Map<int, BTBVTrustState>> getDevicesTrust(String jid) async {
|
||||||
return _lock.synchronized(() async {
|
final map = <int, BTBVTrustState>{};
|
||||||
final map = <int, BTBVTrustState>{};
|
|
||||||
|
|
||||||
if (!devices.containsKey(jid)) return map;
|
if (!devices.containsKey(jid)) return map;
|
||||||
|
|
||||||
for (final deviceId in devices[jid]!) {
|
for (final deviceId in devices[jid]!) {
|
||||||
map[deviceId] = trustCache[RatchetMapKey(jid, deviceId)]!;
|
map[deviceId] = trustCache[RatchetMapKey(jid, deviceId)]!;
|
||||||
}
|
}
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the trust of [jid]'s device with identifier [deviceId] to [state].
|
/// Sets the trust of [jid]'s device with identifier [deviceId] to [state].
|
||||||
@ -186,76 +169,66 @@ class BlindTrustBeforeVerificationTrustManager extends TrustManager {
|
|||||||
int deviceId,
|
int deviceId,
|
||||||
BTBVTrustState state,
|
BTBVTrustState state,
|
||||||
) async {
|
) async {
|
||||||
await _lock.synchronized(() async {
|
final key = RatchetMapKey(jid, deviceId);
|
||||||
final key = RatchetMapKey(jid, deviceId);
|
trustCache[key] = state;
|
||||||
trustCache[key] = state;
|
|
||||||
|
|
||||||
// Commit the state
|
// Commit the state
|
||||||
await commit(
|
await commit(
|
||||||
BTBVTrustData(
|
BTBVTrustData(
|
||||||
jid,
|
jid,
|
||||||
deviceId,
|
deviceId,
|
||||||
state,
|
state,
|
||||||
enablementCache[key]!,
|
enablementCache[key]!,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> isEnabled(String jid, int deviceId) async {
|
Future<bool> isEnabled(String jid, int deviceId) async {
|
||||||
return _lock.synchronized(() async {
|
final value = enablementCache[RatchetMapKey(jid, deviceId)];
|
||||||
final value = enablementCache[RatchetMapKey(jid, deviceId)];
|
|
||||||
|
|
||||||
if (value == null) return false;
|
if (value == null) return false;
|
||||||
return value;
|
return value;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@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);
|
final key = RatchetMapKey(jid, deviceId);
|
||||||
await _lock.synchronized(() async {
|
enablementCache[key] = enabled;
|
||||||
enablementCache[key] = enabled;
|
|
||||||
|
|
||||||
// Commit the state
|
// Commit the state
|
||||||
await commit(
|
await commit(
|
||||||
BTBVTrustData(
|
BTBVTrustData(
|
||||||
jid,
|
jid,
|
||||||
deviceId,
|
deviceId,
|
||||||
trustCache[key]!,
|
trustCache[key]!,
|
||||||
enabled,
|
enabled,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> removeTrustDecisionsForJid(String jid) async {
|
Future<void> removeTrustDecisionsForJid(String jid) async {
|
||||||
await _lock.synchronized(() async {
|
// Clear the caches
|
||||||
// Clear the caches
|
for (final device in devices[jid]!) {
|
||||||
for (final device in devices[jid]!) {
|
final key = RatchetMapKey(jid, device);
|
||||||
final key = RatchetMapKey(jid, device);
|
trustCache.remove(key);
|
||||||
trustCache.remove(key);
|
enablementCache.remove(key);
|
||||||
enablementCache.remove(key);
|
}
|
||||||
}
|
devices.remove(jid);
|
||||||
devices.remove(jid);
|
|
||||||
|
|
||||||
// Commit the state
|
// Commit the state
|
||||||
await removeTrust(jid);
|
await removeTrust(jid);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> loadTrustData(String jid) async {
|
Future<void> loadTrustData(String jid) async {
|
||||||
await _lock.synchronized(() async {
|
for (final result in await loadData(jid)) {
|
||||||
for (final result in await loadData(jid)) {
|
final key = RatchetMapKey(jid, result.device);
|
||||||
final key = RatchetMapKey(jid, result.device);
|
trustCache[key] = result.state;
|
||||||
trustCache[key] = result.state;
|
enablementCache[key] = result.enabled;
|
||||||
enablementCache[key] = result.enabled;
|
devices.appendOrCreate(jid, result.device);
|
||||||
devices.appendOrCreate(jid, result.device);
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
|
@ -1529,9 +1529,14 @@ void main() {
|
|||||||
expect(bobResult1.error, null);
|
expect(bobResult1.error, null);
|
||||||
|
|
||||||
// Bob should have some trust state
|
// Bob should have some trust state
|
||||||
expect(
|
await bobManager.withTrustManager(
|
||||||
(bobManager.trustManager as TestingTrustManager).devices[aliceJid],
|
bobJid,
|
||||||
await aliceManager.getDeviceId(),
|
(tm) async {
|
||||||
|
expect(
|
||||||
|
(tm as TestingTrustManager).devices[aliceJid],
|
||||||
|
await aliceManager.getDeviceId(),
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user