/*
* Famedly Matrix SDK
* Copyright (C) 2020, 2021 Famedly GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
import 'dart:convert';
import 'package:canonical_json/canonical_json.dart';
import 'package:matrix/matrix.dart';
import 'package:olm/olm.dart' as olm;
import '../../encryption.dart';
import '../client.dart';
import '../event.dart';
import '../room.dart';
import '../user.dart';
enum UserVerifiedStatus { verified, unknown, unknownDevice }
class DeviceKeysList {
Client client;
String userId;
bool outdated = true;
Map deviceKeys = {};
Map crossSigningKeys = {};
SignableKey getKey(String id) {
if (deviceKeys.containsKey(id)) {
return deviceKeys[id];
}
if (crossSigningKeys.containsKey(id)) {
return crossSigningKeys[id];
}
return null;
}
CrossSigningKey getCrossSigningKey(String type) => crossSigningKeys.values
.firstWhere((k) => k.usage.contains(type), orElse: () => null);
CrossSigningKey get masterKey => getCrossSigningKey('master');
CrossSigningKey get selfSigningKey => getCrossSigningKey('self_signing');
CrossSigningKey get userSigningKey => getCrossSigningKey('user_signing');
UserVerifiedStatus get verified {
if (masterKey == null) {
return UserVerifiedStatus.unknown;
}
if (masterKey.verified) {
for (final key in deviceKeys.values) {
if (!key.verified) {
return UserVerifiedStatus.unknownDevice;
}
}
return UserVerifiedStatus.verified;
} else {
for (final key in deviceKeys.values) {
if (!key.verified) {
return UserVerifiedStatus.unknown;
}
}
return UserVerifiedStatus.verified;
}
}
Future startVerification() async {
if (userId != client.userID) {
// in-room verification with someone else
final roomId =
await User(userId, room: Room(client: client)).startDirectChat();
if (roomId == null) {
throw Exception('Unable to start new room');
}
final room =
client.getRoomById(roomId) ?? Room(id: roomId, client: client);
final request = KeyVerification(
encryption: client.encryption, room: room, userId: userId);
await request.start();
// no need to add to the request client object. As we are doing a room
// verification request that'll happen automatically once we know the transaction id
return request;
} else {
// broadcast self-verification
final request = KeyVerification(
encryption: client.encryption, userId: userId, deviceId: '*');
await request.start();
client.encryption.keyVerificationManager.addRequest(request);
return request;
}
}
DeviceKeysList.fromDbJson(
Map dbEntry,
List