diff --git a/lib/src/omemo/sessionmanager.dart b/lib/src/omemo/sessionmanager.dart index ab4fb4a..278fb75 100644 --- a/lib/src/omemo/sessionmanager.dart +++ b/lib/src/omemo/sessionmanager.dart @@ -254,6 +254,9 @@ class OmemoSessionManager { if (plaintext != null) { // Only encrypt to devices that are trusted if (!(await _trustManager.isTrusted(jid, deviceId))) continue; + + // Onyl encrypt to devices that are enabled + if (!(await _trustManager.isEnabled(jid, deviceId))) continue; } final ratchetKey = RatchetMapKey(jid, deviceId); diff --git a/lib/src/trust/always.dart b/lib/src/trust/always.dart index 45e08dd..f929fc8 100644 --- a/lib/src/trust/always.dart +++ b/lib/src/trust/always.dart @@ -11,4 +11,10 @@ class AlwaysTrustingTrustManager extends TrustManager { @override Future onNewSession(String jid, int deviceId) async {} + + @override + Future isEnabled(String jid, int deviceId) async => true; + + @override + Future setEnabled(String jid, int deviceId, bool enabled) async {} } diff --git a/lib/src/trust/base.dart b/lib/src/trust/base.dart index c4f1605..8277e96 100644 --- a/lib/src/trust/base.dart +++ b/lib/src/trust/base.dart @@ -8,4 +8,12 @@ abstract class TrustManager { /// Called by the OmemoSessionManager when a new session has been built. Should set /// a default trust state to [jid]'s device with identifier [deviceId]. Future onNewSession(String jid, int deviceId); + + /// Return true if the device with id [deviceId] of Jid [jid] should be used for encryption. + /// If not, return false. + Future isEnabled(String jid, int deviceId); + + /// Mark the device with id [deviceId] of Jid [jid] as enabled if [enabled] is true or as disabled + /// if [enabled] is false. + Future setEnabled(String jid, int deviceId, bool enabled); } diff --git a/lib/src/trust/btbv.dart b/lib/src/trust/btbv.dart index 1aac4b5..dfbf672 100644 --- a/lib/src/trust/btbv.dart +++ b/lib/src/trust/btbv.dart @@ -18,13 +18,18 @@ enum BTBVTrustState { abstract class BlindTrustBeforeVerificationTrustManager extends TrustManager { BlindTrustBeforeVerificationTrustManager() : trustCache = {}, + enablementCache = {}, devices = {}, _lock = Lock(); - /// The cache for Mapping a RatchetMapKey to its trust state + /// The cache for mapping a RatchetMapKey to its trust state @protected final Map trustCache; + /// The cache for mapping a RatchetMapKey to whether it is enabled or not + @protected + final Map enablementCache; + /// Mapping of Jids to their device identifiers @protected final Map> devices; @@ -74,10 +79,13 @@ abstract class BlindTrustBeforeVerificationTrustManager extends TrustManager { @override Future onNewSession(String jid, int deviceId) async { await _lock.synchronized(() async { + final key = RatchetMapKey(jid, deviceId); if (_hasAtLeastOneVerifiedDevice(jid)) { - trustCache[RatchetMapKey(jid, deviceId)] = BTBVTrustState.notTrusted; + trustCache[key] = BTBVTrustState.notTrusted; + enablementCache[key] = false; } else { - trustCache[RatchetMapKey(jid, deviceId)] = BTBVTrustState.blindTrust; + trustCache[key] = BTBVTrustState.blindTrust; + enablementCache[key] = true; } if (devices.containsKey(jid)) { @@ -85,7 +93,7 @@ abstract class BlindTrustBeforeVerificationTrustManager extends TrustManager { } else { devices[jid] = List.from([deviceId]); } - + // Commit the state await commitState(); }); @@ -114,6 +122,26 @@ abstract class BlindTrustBeforeVerificationTrustManager extends TrustManager { }); } + @override + Future isEnabled(String jid, int deviceId) async { + return _lock.synchronized(() async { + final value = enablementCache[RatchetMapKey(jid, deviceId)]; + + if (value == null) return false; + return value; + }); + } + + @override + Future setEnabled(String jid, int deviceId, bool enabled) async { + await _lock.synchronized(() async { + enablementCache[RatchetMapKey(jid, deviceId)] = enabled; + }); + + // 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 diff --git a/lib/src/trust/never.dart b/lib/src/trust/never.dart index ec02bb6..d706734 100644 --- a/lib/src/trust/never.dart +++ b/lib/src/trust/never.dart @@ -11,4 +11,10 @@ class NeverTrustingTrustManager extends TrustManager { @override Future onNewSession(String jid, int deviceId) async {} + + @override + Future isEnabled(String jid, int deviceId) async => true; + + @override + Future setEnabled(String jid, int deviceId, bool enabled) async {} } diff --git a/test/trust_test.dart b/test/trust_test.dart index 968af83..c8b764f 100644 --- a/test/trust_test.dart +++ b/test/trust_test.dart @@ -12,6 +12,7 @@ void main() { // Caroline starts a chat a device from Alice await btbv.onNewSession(aliceJid, 1); expect(await btbv.isTrusted(aliceJid, 1), true); + expect(await btbv.isEnabled(aliceJid, 1), true); // Caroline meets with Alice and verifies her fingerprint await btbv.setDeviceTrust(aliceJid, 1, BTBVTrustState.verified); @@ -21,6 +22,7 @@ void main() { await btbv.onNewSession(aliceJid, 2); expect(await btbv.isTrusted(aliceJid, 2), false); expect(btbv.getDeviceTrust(aliceJid, 2), BTBVTrustState.notTrusted); + expect(await btbv.isEnabled(aliceJid, 2), false); // Caronline starts a chat with Bob but since they live far apart, Caroline cannot // verify his fingerprint. @@ -32,5 +34,7 @@ void main() { expect(await btbv.isTrusted(bobJid, 4), true); expect(btbv.getDeviceTrust(bobJid, 3), BTBVTrustState.blindTrust); expect(btbv.getDeviceTrust(bobJid, 4), BTBVTrustState.blindTrust); + expect(await btbv.isEnabled(bobJid, 3), true); + expect(await btbv.isEnabled(bobJid, 4), true); }); }