format
This commit is contained in:
parent
29721f00a8
commit
c9a0c5302a
|
@ -1664,7 +1664,8 @@ class Client {
|
||||||
if (entry.isValid) {
|
if (entry.isValid) {
|
||||||
// is this a new key or the same one as an old one?
|
// is this a new key or the same one as an old one?
|
||||||
// better store an update - the signatures might have changed!
|
// better store an update - the signatures might have changed!
|
||||||
if (!oldKeys.containsKey(deviceId) || oldKeys[deviceId].ed25519Key == entry.ed25519Key) {
|
if (!oldKeys.containsKey(deviceId) ||
|
||||||
|
oldKeys[deviceId].ed25519Key == entry.ed25519Key) {
|
||||||
if (oldKeys.containsKey(deviceId)) {
|
if (oldKeys.containsKey(deviceId)) {
|
||||||
// be sure to save the verified status
|
// be sure to save the verified status
|
||||||
entry.setDirectVerified(oldKeys[deviceId].directVerified);
|
entry.setDirectVerified(oldKeys[deviceId].directVerified);
|
||||||
|
@ -1681,7 +1682,8 @@ class Client {
|
||||||
// This shouldn't ever happen. The same device ID has gotten
|
// This shouldn't ever happen. The same device ID has gotten
|
||||||
// a new public key. So we ignore the update. TODO: ask krille
|
// a new public key. So we ignore the update. TODO: ask krille
|
||||||
// if we should instead use the new key with unknown verified / blocked status
|
// if we should instead use the new key with unknown verified / blocked status
|
||||||
_userDeviceKeys[userId].deviceKeys[deviceId] = oldKeys[deviceId];
|
_userDeviceKeys[userId].deviceKeys[deviceId] =
|
||||||
|
oldKeys[deviceId];
|
||||||
}
|
}
|
||||||
if (database != null) {
|
if (database != null) {
|
||||||
dbActions.add(() => database.storeUserDeviceKey(
|
dbActions.add(() => database.storeUserDeviceKey(
|
||||||
|
@ -1713,24 +1715,33 @@ class Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// next we parse and persist the cross signing keys
|
// next we parse and persist the cross signing keys
|
||||||
for (final keyType in ['master_keys', 'self_signing_keys', 'user_signing_keys']) {
|
for (final keyType in [
|
||||||
|
'master_keys',
|
||||||
|
'self_signing_keys',
|
||||||
|
'user_signing_keys'
|
||||||
|
]) {
|
||||||
if (!(response[keyType] is Map)) {
|
if (!(response[keyType] is Map)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (final rawDeviceKeyListEntry in response[keyType].entries) {
|
for (final rawDeviceKeyListEntry in response[keyType].entries) {
|
||||||
final String userId = rawDeviceKeyListEntry.key;
|
final String userId = rawDeviceKeyListEntry.key;
|
||||||
final oldKeys = Map<String, CrossSigningKey>.from(_userDeviceKeys[userId].crossSigningKeys);
|
final oldKeys = Map<String, CrossSigningKey>.from(
|
||||||
|
_userDeviceKeys[userId].crossSigningKeys);
|
||||||
_userDeviceKeys[userId].crossSigningKeys = {};
|
_userDeviceKeys[userId].crossSigningKeys = {};
|
||||||
// add the types we arne't handling atm back
|
// add the types we arne't handling atm back
|
||||||
for (final oldEntry in oldKeys.entries) {
|
for (final oldEntry in oldKeys.entries) {
|
||||||
if (!oldEntry.value.usage.contains(keyType.substring(0, keyType.length - '_keys'.length))) {
|
if (!oldEntry.value.usage.contains(
|
||||||
_userDeviceKeys[userId].crossSigningKeys[oldEntry.key] = oldEntry.value;
|
keyType.substring(0, keyType.length - '_keys'.length))) {
|
||||||
|
_userDeviceKeys[userId].crossSigningKeys[oldEntry.key] =
|
||||||
|
oldEntry.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final entry = CrossSigningKey.fromJson(rawDeviceKeyListEntry.value, this);
|
final entry =
|
||||||
|
CrossSigningKey.fromJson(rawDeviceKeyListEntry.value, this);
|
||||||
if (entry.isValid) {
|
if (entry.isValid) {
|
||||||
final publicKey = entry.publicKey;
|
final publicKey = entry.publicKey;
|
||||||
if (!oldKeys.containsKey(publicKey) || oldKeys[publicKey].ed25519Key == entry.ed25519Key) {
|
if (!oldKeys.containsKey(publicKey) ||
|
||||||
|
oldKeys[publicKey].ed25519Key == entry.ed25519Key) {
|
||||||
if (oldKeys.containsKey(publicKey)) {
|
if (oldKeys.containsKey(publicKey)) {
|
||||||
// be sure to save the verification status
|
// be sure to save the verification status
|
||||||
entry.setDirectVerified(oldKeys[publicKey].directVerified);
|
entry.setDirectVerified(oldKeys[publicKey].directVerified);
|
||||||
|
@ -1742,34 +1753,37 @@ class Client {
|
||||||
// This shouldn't ever happen. The same device ID has gotten
|
// This shouldn't ever happen. The same device ID has gotten
|
||||||
// a new public key. So we ignore the update. TODO: ask krille
|
// a new public key. So we ignore the update. TODO: ask krille
|
||||||
// if we should instead use the new key with unknown verified / blocked status
|
// if we should instead use the new key with unknown verified / blocked status
|
||||||
_userDeviceKeys[userId].crossSigningKeys[publicKey] = oldKeys[publicKey];
|
_userDeviceKeys[userId].crossSigningKeys[publicKey] =
|
||||||
|
oldKeys[publicKey];
|
||||||
}
|
}
|
||||||
if (database != null) {
|
if (database != null) {
|
||||||
dbActions.add(() => database.storeUserCrossSigningKey(
|
dbActions.add(() => database.storeUserCrossSigningKey(
|
||||||
id,
|
id,
|
||||||
userId,
|
userId,
|
||||||
publicKey,
|
publicKey,
|
||||||
json.encode(entry.toJson()),
|
json.encode(entry.toJson()),
|
||||||
entry.directVerified,
|
entry.directVerified,
|
||||||
entry.blocked,
|
entry.blocked,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// delete old/unused entries
|
// delete old/unused entries
|
||||||
if (database != null) {
|
if (database != null) {
|
||||||
for (final oldCrossSigningKeyEntry in oldKeys.entries) {
|
for (final oldCrossSigningKeyEntry in oldKeys.entries) {
|
||||||
final publicKey = oldCrossSigningKeyEntry.key;
|
final publicKey = oldCrossSigningKeyEntry.key;
|
||||||
if (!_userDeviceKeys[userId].crossSigningKeys.containsKey(publicKey)) {
|
if (!_userDeviceKeys[userId]
|
||||||
|
.crossSigningKeys
|
||||||
|
.containsKey(publicKey)) {
|
||||||
// we need to remove an old key
|
// we need to remove an old key
|
||||||
dbActions.add(
|
dbActions.add(() => database.removeUserCrossSigningKey(
|
||||||
() => database.removeUserCrossSigningKey(id, userId, publicKey));
|
id, userId, publicKey));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_userDeviceKeys[userId].outdated = false;
|
_userDeviceKeys[userId].outdated = false;
|
||||||
if (database != null) {
|
if (database != null) {
|
||||||
dbActions
|
dbActions.add(
|
||||||
.add(() => database.storeUserDeviceKeysInfo(id, userId, false));
|
() => database.storeUserDeviceKeysInfo(id, userId, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,8 @@ class Database extends _$Database {
|
||||||
await m.createTable(userCrossSigningKeys);
|
await m.createTable(userCrossSigningKeys);
|
||||||
await m.createIndex(userCrossSigningKeysIndex);
|
await m.createIndex(userCrossSigningKeysIndex);
|
||||||
// mark all keys as outdated so that the cross signing keys will be fetched
|
// mark all keys as outdated so that the cross signing keys will be fetched
|
||||||
await m.issueCustomQuery('UPDATE user_device_keys SET outdated = true');
|
await m.issueCustomQuery(
|
||||||
|
'UPDATE user_device_keys SET outdated = true');
|
||||||
from++;
|
from++;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -59,7 +60,8 @@ class Database extends _$Database {
|
||||||
return res.first;
|
return res.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, sdk.DeviceKeysList>> getUserDeviceKeys(sdk.Client client) async {
|
Future<Map<String, sdk.DeviceKeysList>> getUserDeviceKeys(
|
||||||
|
sdk.Client client) async {
|
||||||
final deviceKeys = await getAllUserDeviceKeys(client.id).get();
|
final deviceKeys = await getAllUserDeviceKeys(client.id).get();
|
||||||
if (deviceKeys.isEmpty) {
|
if (deviceKeys.isEmpty) {
|
||||||
return {};
|
return {};
|
||||||
|
@ -68,10 +70,11 @@ class Database extends _$Database {
|
||||||
final crossSigningKeys = await getAllUserCrossSigningKeys(client.id).get();
|
final crossSigningKeys = await getAllUserCrossSigningKeys(client.id).get();
|
||||||
final res = <String, sdk.DeviceKeysList>{};
|
final res = <String, sdk.DeviceKeysList>{};
|
||||||
for (final entry in deviceKeys) {
|
for (final entry in deviceKeys) {
|
||||||
res[entry.userId] = sdk.DeviceKeysList.fromDb(entry,
|
res[entry.userId] = sdk.DeviceKeysList.fromDb(
|
||||||
deviceKeysKeys.where((k) => k.userId == entry.userId).toList(),
|
entry,
|
||||||
crossSigningKeys.where((k) => k.userId == entry.userId).toList(),
|
deviceKeysKeys.where((k) => k.userId == entry.userId).toList(),
|
||||||
client);
|
crossSigningKeys.where((k) => k.userId == entry.userId).toList(),
|
||||||
|
client);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,8 @@ import 'package:canonical_json/canonical_json.dart';
|
||||||
import 'package:olm/olm.dart' as olm;
|
import 'package:olm/olm.dart' as olm;
|
||||||
|
|
||||||
import '../client.dart';
|
import '../client.dart';
|
||||||
import '../database/database.dart' show DbUserDeviceKey, DbUserDeviceKeysKey, DbUserCrossSigningKey;
|
import '../database/database.dart'
|
||||||
|
show DbUserDeviceKey, DbUserDeviceKeysKey, DbUserCrossSigningKey;
|
||||||
import '../event.dart';
|
import '../event.dart';
|
||||||
import 'key_verification.dart';
|
import 'key_verification.dart';
|
||||||
|
|
||||||
|
@ -14,7 +15,11 @@ class DeviceKeysList {
|
||||||
Map<String, DeviceKeys> deviceKeys = {};
|
Map<String, DeviceKeys> deviceKeys = {};
|
||||||
Map<String, CrossSigningKey> crossSigningKeys = {};
|
Map<String, CrossSigningKey> crossSigningKeys = {};
|
||||||
|
|
||||||
DeviceKeysList.fromDb(DbUserDeviceKey dbEntry, List<DbUserDeviceKeysKey> childEntries, List<DbUserCrossSigningKey> crossSigningEntries, Client cl) {
|
DeviceKeysList.fromDb(
|
||||||
|
DbUserDeviceKey dbEntry,
|
||||||
|
List<DbUserDeviceKeysKey> childEntries,
|
||||||
|
List<DbUserCrossSigningKey> crossSigningEntries,
|
||||||
|
Client cl) {
|
||||||
client = cl;
|
client = cl;
|
||||||
userId = dbEntry.userId;
|
userId = dbEntry.userId;
|
||||||
outdated = dbEntry.outdated;
|
outdated = dbEntry.outdated;
|
||||||
|
@ -93,7 +98,9 @@ abstract class _SignedKey {
|
||||||
try {
|
try {
|
||||||
return hasValidSignatureChain();
|
return hasValidSignatureChain();
|
||||||
} catch (err, stacktrace) {
|
} catch (err, stacktrace) {
|
||||||
print('[Cross Signing] Error during trying to determine signature chain: ' + err.toString());
|
print(
|
||||||
|
'[Cross Signing] Error during trying to determine signature chain: ' +
|
||||||
|
err.toString());
|
||||||
print(stacktrace);
|
print(stacktrace);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -134,7 +141,8 @@ abstract class _SignedKey {
|
||||||
visited.add(setKey);
|
visited.add(setKey);
|
||||||
for (final signatureEntries in signatures.entries) {
|
for (final signatureEntries in signatures.entries) {
|
||||||
final otherUserId = signatureEntries.key;
|
final otherUserId = signatureEntries.key;
|
||||||
if (!(signatureEntries.value is Map) || !client.userDeviceKeys.containsKey(otherUserId)) {
|
if (!(signatureEntries.value is Map) ||
|
||||||
|
!client.userDeviceKeys.containsKey(otherUserId)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (final signatureEntry in signatureEntries.value.entries) {
|
for (final signatureEntry in signatureEntries.value.entries) {
|
||||||
|
@ -147,7 +155,8 @@ abstract class _SignedKey {
|
||||||
_SignedKey key;
|
_SignedKey key;
|
||||||
if (client.userDeviceKeys[otherUserId].deviceKeys.containsKey(keyId)) {
|
if (client.userDeviceKeys[otherUserId].deviceKeys.containsKey(keyId)) {
|
||||||
key = client.userDeviceKeys[otherUserId].deviceKeys[keyId];
|
key = client.userDeviceKeys[otherUserId].deviceKeys[keyId];
|
||||||
} else if (client.userDeviceKeys[otherUserId].crossSigningKeys.containsKey(keyId)) {
|
} else if (client.userDeviceKeys[otherUserId].crossSigningKeys
|
||||||
|
.containsKey(keyId)) {
|
||||||
key = client.userDeviceKeys[otherUserId].crossSigningKeys[keyId];
|
key = client.userDeviceKeys[otherUserId].crossSigningKeys[keyId];
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
|
@ -157,7 +166,9 @@ abstract class _SignedKey {
|
||||||
}
|
}
|
||||||
var haveValidSignature = false;
|
var haveValidSignature = false;
|
||||||
var gotSignatureFromCache = false;
|
var gotSignatureFromCache = false;
|
||||||
if (validSignatures != null && validSignatures.containsKey(otherUserId) && validSignatures[otherUserId].containsKey(fullKeyId)) {
|
if (validSignatures != null &&
|
||||||
|
validSignatures.containsKey(otherUserId) &&
|
||||||
|
validSignatures[otherUserId].containsKey(fullKeyId)) {
|
||||||
if (validSignatures[otherUserId][fullKeyId] == true) {
|
if (validSignatures[otherUserId][fullKeyId] == true) {
|
||||||
haveValidSignature = true;
|
haveValidSignature = true;
|
||||||
gotSignatureFromCache = true;
|
gotSignatureFromCache = true;
|
||||||
|
@ -209,16 +220,19 @@ class CrossSigningKey extends _SignedKey {
|
||||||
String get publicKey => identifier;
|
String get publicKey => identifier;
|
||||||
List<String> usage;
|
List<String> usage;
|
||||||
|
|
||||||
bool get isValid => userId != null && publicKey != null && keys != null && ed25519Key != null;
|
bool get isValid =>
|
||||||
|
userId != null && publicKey != null && keys != null && ed25519Key != null;
|
||||||
|
|
||||||
Future<void> setVerified(bool newVerified) {
|
Future<void> setVerified(bool newVerified) {
|
||||||
_verified = newVerified;
|
_verified = newVerified;
|
||||||
return client.database?.setVerifiedUserCrossSigningKey(newVerified, client.id, userId, publicKey);
|
return client.database?.setVerifiedUserCrossSigningKey(
|
||||||
|
newVerified, client.id, userId, publicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setBlocked(bool newBlocked) {
|
Future<void> setBlocked(bool newBlocked) {
|
||||||
blocked = newBlocked;
|
blocked = newBlocked;
|
||||||
return client.database?.setBlockedUserCrossSigningKey(newBlocked, client.id, userId, publicKey);
|
return client.database?.setBlockedUserCrossSigningKey(
|
||||||
|
newBlocked, client.id, userId, publicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
CrossSigningKey.fromDb(DbUserCrossSigningKey dbEntry, Client cl) {
|
CrossSigningKey.fromDb(DbUserCrossSigningKey dbEntry, Client cl) {
|
||||||
|
@ -229,7 +243,9 @@ class CrossSigningKey extends _SignedKey {
|
||||||
identifier = dbEntry.publicKey;
|
identifier = dbEntry.publicKey;
|
||||||
usage = json['usage'].cast<String>();
|
usage = json['usage'].cast<String>();
|
||||||
keys = json['keys'] != null ? Map<String, String>.from(json['keys']) : null;
|
keys = json['keys'] != null ? Map<String, String>.from(json['keys']) : null;
|
||||||
signatures = json['signatures'] != null ? Map<String, dynamic>.from(json['signatures']) : null;
|
signatures = json['signatures'] != null
|
||||||
|
? Map<String, dynamic>.from(json['signatures'])
|
||||||
|
: null;
|
||||||
_verified = dbEntry.verified;
|
_verified = dbEntry.verified;
|
||||||
blocked = dbEntry.blocked;
|
blocked = dbEntry.blocked;
|
||||||
}
|
}
|
||||||
|
|
|
@ -291,7 +291,8 @@ class KeyVerification {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> verifyKeys(Map<String, String> keys, Future<bool> Function(String, dynamic) verifier) async {
|
Future<void> verifyKeys(Map<String, String> keys,
|
||||||
|
Future<bool> Function(String, dynamic) verifier) async {
|
||||||
final verifiedDevices = <String>[];
|
final verifiedDevices = <String>[];
|
||||||
|
|
||||||
if (!client.userDeviceKeys.containsKey(userId)) {
|
if (!client.userDeviceKeys.containsKey(userId)) {
|
||||||
|
@ -310,9 +311,11 @@ class KeyVerification {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
verifiedDevices.add(verifyDeviceId);
|
verifiedDevices.add(verifyDeviceId);
|
||||||
} else if (client.userDeviceKeys[userId].crossSigningKeys.containsKey(verifyDeviceId)) {
|
} else if (client.userDeviceKeys[userId].crossSigningKeys
|
||||||
|
.containsKey(verifyDeviceId)) {
|
||||||
// this is a cross signing key!
|
// this is a cross signing key!
|
||||||
if (!(await verifier(keyInfo, client.userDeviceKeys[userId].crossSigningKeys[verifyDeviceId]))) {
|
if (!(await verifier(keyInfo,
|
||||||
|
client.userDeviceKeys[userId].crossSigningKeys[verifyDeviceId]))) {
|
||||||
await cancel('m.key_mismatch');
|
await cancel('m.key_mismatch');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -321,10 +324,14 @@ class KeyVerification {
|
||||||
}
|
}
|
||||||
// okay, we reached this far, so all the devices are verified!
|
// okay, we reached this far, so all the devices are verified!
|
||||||
for (final verifyDeviceId in verifiedDevices) {
|
for (final verifyDeviceId in verifiedDevices) {
|
||||||
if (client.userDeviceKeys[userId].deviceKeys.containsKey(verifyDeviceId)) {
|
if (client.userDeviceKeys[userId].deviceKeys
|
||||||
await client.userDeviceKeys[userId].deviceKeys[verifyDeviceId].setVerified(true);
|
.containsKey(verifyDeviceId)) {
|
||||||
} else if (client.userDeviceKeys[userId].crossSigningKeys.containsKey(verifyDeviceId)) {
|
await client.userDeviceKeys[userId].deviceKeys[verifyDeviceId]
|
||||||
await client.userDeviceKeys[userId].crossSigningKeys[verifyDeviceId].setVerified(true);
|
.setVerified(true);
|
||||||
|
} else if (client.userDeviceKeys[userId].crossSigningKeys
|
||||||
|
.containsKey(verifyDeviceId)) {
|
||||||
|
await client.userDeviceKeys[userId].crossSigningKeys[verifyDeviceId]
|
||||||
|
.setVerified(true);
|
||||||
// TODO: sign the other persons master key
|
// TODO: sign the other persons master key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -708,9 +715,13 @@ class _KeyVerificationMethodSas extends _KeyVerificationMethod {
|
||||||
}
|
}
|
||||||
await request.verifyKeys(mac, (String mac, dynamic device) async {
|
await request.verifyKeys(mac, (String mac, dynamic device) async {
|
||||||
if (device is DeviceKeys) {
|
if (device is DeviceKeys) {
|
||||||
return mac == _calculateMac(device.ed25519Key, baseInfo + 'ed25519:' + device.deviceId);
|
return mac ==
|
||||||
|
_calculateMac(
|
||||||
|
device.ed25519Key, baseInfo + 'ed25519:' + device.deviceId);
|
||||||
} else if (device is CrossSigningKey) {
|
} else if (device is CrossSigningKey) {
|
||||||
return mac == _calculateMac(device.ed25519Key, baseInfo + 'ed25519:' + device.publicKey);
|
return mac ==
|
||||||
|
_calculateMac(
|
||||||
|
device.ed25519Key, baseInfo + 'ed25519:' + device.publicKey);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
|
@ -65,8 +65,7 @@ void main() {
|
||||||
final key = DeviceKeys.fromJson(rawJson, null);
|
final key = DeviceKeys.fromJson(rawJson, null);
|
||||||
rawJson.remove('verified');
|
rawJson.remove('verified');
|
||||||
rawJson.remove('blocked');
|
rawJson.remove('blocked');
|
||||||
expect(json.encode(key.toJson()),
|
expect(json.encode(key.toJson()), json.encode(rawJson));
|
||||||
json.encode(rawJson));
|
|
||||||
expect(key.verified, false);
|
expect(key.verified, false);
|
||||||
expect(key.blocked, true);
|
expect(key.blocked, true);
|
||||||
expect(json.encode(DeviceKeysList.fromJson(rawListJson, null).toJson()),
|
expect(json.encode(DeviceKeysList.fromJson(rawListJson, null).toJson()),
|
||||||
|
|
Loading…
Reference in New Issue