Merge branch 'krille/share-keys-with-unknown-devices' into 'main'

feat: Calc encryption health state and allow key sharing with unknown devices

Closes #307

See merge request famedly/company/frontend/famedlysdk!1072
This commit is contained in:
Krille Fear 2022-07-09 07:50:32 +00:00
commit 2a280cec98
5 changed files with 48 additions and 8 deletions

View File

@ -83,6 +83,8 @@ class Client extends MatrixApi {
final bool mxidLocalPartFallback;
bool shareKeysWithUnverifiedDevices;
// For CommandsClientExtension
final Map<String, FutureOr<String?> Function(CommandArgs)> commands = {};
final Filter syncFilter;
@ -167,6 +169,7 @@ class Client extends MatrixApi {
Filter? syncFilter,
this.sendTimelineEventTimeout = const Duration(minutes: 1),
this.customImageResizer,
this.shareKeysWithUnverifiedDevices = true,
}) : syncFilter = syncFilter ??
Filter(
room: RoomFilter(

View File

@ -852,6 +852,26 @@ class Room {
return eventId;
}
/// Calculates how secure the communication is. When all devices are blocked or
/// verified, then this returns [EncryptionHealthState.allVerified]. When at
/// least one device is not verified, then it returns
/// [EncryptionHealthState.unverifiedDevices]. Apps should display this health
/// state next to the input text field to inform the user about the current
/// encryption security level.
Future<EncryptionHealthState> calcEncryptionHealthState() async {
final users = await requestParticipants();
users.removeWhere((u) =>
!{Membership.invite, Membership.join}.contains(u.membership) ||
!client.userDeviceKeys.containsKey(u.id));
if (users.any((u) =>
client.userDeviceKeys[u.id]!.verified != UserVerifiedStatus.verified)) {
return EncryptionHealthState.unverifiedDevices;
}
return EncryptionHealthState.allVerified;
}
Future<String?> _sendContent(
String type,
Map<String, dynamic> content, {
@ -1977,3 +1997,8 @@ class Room {
@override
bool operator ==(dynamic other) => (other is Room && other.id == id);
}
enum EncryptionHealthState {
allVerified,
unverifiedDevices,
}

View File

@ -151,13 +151,13 @@ abstract class SignableKey extends MatrixSignableKey {
bool get blocked => _blocked ?? false;
set blocked(bool b) => _blocked = b;
bool get encryptToDevice =>
!(blocked) &&
identifier != null &&
ed25519Key != null &&
(client.userDeviceKeys[userId]?.masterKey?.verified ?? false
? verified
: true);
bool get encryptToDevice {
if (blocked) return false;
if (identifier == null || ed25519Key == null) return false;
return client.shareKeysWithUnverifiedDevices || verified;
}
void setDirectVerified(bool v) {
_verified = v;

View File

@ -156,6 +156,11 @@ void main() {
},
},
}, client);
expect(client.shareKeysWithUnverifiedDevices, true);
expect(key.encryptToDevice, true);
client.shareKeysWithUnverifiedDevices = false;
expect(key.encryptToDevice, false);
client.shareKeysWithUnverifiedDevices = true;
final masterKey = client.userDeviceKeys[client.userID]!.masterKey!;
masterKey.setDirectVerified(true);
// we need to populate the ssss cache to be able to test signing easily
@ -175,7 +180,7 @@ void main() {
expect(
client.userDeviceKeys[client.userID]?.deviceKeys['UNSIGNEDDEVICE']
?.encryptToDevice,
false);
true);
expect(masterKey.verified, true);
await masterKey.setBlocked(true);

View File

@ -349,6 +349,13 @@ void main() {
expect(user.room.id, '!localpart:server.abc');
});
test('calcEncryptionHealthState', () async {
expect(
await room.calcEncryptionHealthState(),
EncryptionHealthState.unverifiedDevices,
);
});
test('getEventByID', () async {
final event = await room.getEventById('1234');
expect(event?.eventId, '143273582443PhrSn:example.org');