Skip to content

Commit

Permalink
Merge pull request #2018 from famedly/krille/make-share-keys-with-con…
Browse files Browse the repository at this point in the history
…figurable

feat: (BREAKING) Make share keys with logic configurable
  • Loading branch information
td-famedly authored Feb 5, 2025
2 parents 24a0cfb + a352809 commit a3d33ee
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 6 deletions.
26 changes: 24 additions & 2 deletions lib/src/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class Client extends MatrixApi {

final bool mxidLocalPartFallback;

bool shareKeysWithUnverifiedDevices;
ShareKeysWith shareKeysWith;

Future<void> Function(Client client)? onSoftLogout;

Expand Down Expand Up @@ -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,

Expand Down Expand Up @@ -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,
}
12 changes: 11 additions & 1 deletion lib/src/utils/device_keys_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
24 changes: 21 additions & 3 deletions test/device_keys_list_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit a3d33ee

Please sign in to comment.