From a352809a01c94f64ea62709214285d8fa1f5632e Mon Sep 17 00:00:00 2001 From: Krille Date: Tue, 4 Feb 2025 12:33:21 +0100 Subject: [PATCH] feat: (BREAKING) Make share keys with logic configurable --- lib/src/client.dart | 26 ++++++++++++++++++++++++-- lib/src/utils/device_keys_list.dart | 12 +++++++++++- test/device_keys_list_test.dart | 24 +++++++++++++++++++++--- 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/lib/src/client.dart b/lib/src/client.dart index 3caa2dab..e27bf246 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -90,7 +90,7 @@ class Client extends MatrixApi { final bool mxidLocalPartFallback; - bool shareKeysWithUnverifiedDevices; + ShareKeysWith shareKeysWith; Future Function(Client client)? onSoftLogout; @@ -219,7 +219,7 @@ class Client extends MatrixApi { Duration defaultNetworkRequestTimeout = const Duration(seconds: 35), this.sendTimelineEventTimeout = const Duration(minutes: 1), this.customImageResizer, - this.shareKeysWithUnverifiedDevices = true, + this.shareKeysWith = ShareKeysWith.crossVerifiedIfEnabled, this.enableDehydratedDevices = false, this.receiptsPublicByDefault = true, @@ -4082,3 +4082,25 @@ enum InitState { /// Initialization has been completed with an error. error, } + +/// Sets the security level with which devices keys should be shared with +enum ShareKeysWith { + /// Keys are shared with all devices if they are not explicitely blocked + all, + + /// Once a user has enabled cross signing, keys are no longer shared with + /// devices which are not cross verified by the cross signing keys of this + /// user. This does not require that the user needs to be verified. + crossVerifiedIfEnabled, + + /// Keys are only shared with cross verified devices. If a user has not + /// enabled cross signing, then all devices must be verified manually first. + /// This does not require that the user needs to be verified. + crossVerified, + + /// Keys are only shared with direct verified devices. So either the device + /// or the user must be manually verified first, before keys are shared. By + /// using cross signing, it is enough to verify the user and then the user + /// can verify their devices. + directlyVerifiedOnly, +} diff --git a/lib/src/utils/device_keys_list.dart b/lib/src/utils/device_keys_list.dart index c4f3cb09..cdc704dc 100644 --- a/lib/src/utils/device_keys_list.dart +++ b/lib/src/utils/device_keys_list.dart @@ -163,7 +163,17 @@ abstract class SignableKey extends MatrixSignableKey { if (identifier == null || ed25519Key == null) return false; - return client.shareKeysWithUnverifiedDevices || verified; + switch (client.shareKeysWith) { + case ShareKeysWith.all: + return true; + case ShareKeysWith.crossVerifiedIfEnabled: + if (client.userDeviceKeys[userId]?.masterKey == null) return true; + return hasValidSignatureChain(verifiedByTheirMasterKey: true); + case ShareKeysWith.crossVerified: + return hasValidSignatureChain(verifiedByTheirMasterKey: true); + case ShareKeysWith.directlyVerifiedOnly: + return directVerified; + } } void setDirectVerified(bool isVerified) { diff --git a/test/device_keys_list_test.dart b/test/device_keys_list_test.dart index b6932136..ff3549af 100644 --- a/test/device_keys_list_test.dart +++ b/test/device_keys_list_test.dart @@ -150,11 +150,29 @@ void main() { }, client, ); - expect(client.shareKeysWithUnverifiedDevices, true); + + client.shareKeysWith = ShareKeysWith.all; expect(key.encryptToDevice, true); - client.shareKeysWithUnverifiedDevices = false; + + client.shareKeysWith = ShareKeysWith.directlyVerifiedOnly; expect(key.encryptToDevice, false); - client.shareKeysWithUnverifiedDevices = true; + await key.setVerified(true); + expect(key.encryptToDevice, true); + await key.setVerified(false); + + client.shareKeysWith = ShareKeysWith.crossVerified; + expect(key.encryptToDevice, true); + + client.shareKeysWith = ShareKeysWith.crossVerified; + // Disable cross signing for this user manually so encryptToDevice should return `false` + final dropUserDeviceKeys = client.userDeviceKeys.remove(key.userId); + expect(key.encryptToDevice, false); + // But crossVerifiedIfEnabled should return `true` now: + client.shareKeysWith = ShareKeysWith.crossVerifiedIfEnabled; + expect(key.encryptToDevice, true); + + client.userDeviceKeys[key.userId] = dropUserDeviceKeys!; + client.shareKeysWith = ShareKeysWith.all; final masterKey = client.userDeviceKeys[client.userID]!.masterKey!; masterKey.setDirectVerified(true); // we need to populate the ssss cache to be able to test signing easily