format and some analyze
This commit is contained in:
parent
060a772bfa
commit
4154c7d0eb
|
@ -152,7 +152,8 @@ class CrossSigning {
|
||||||
if (key is CrossSigningKey) {
|
if (key is CrossSigningKey) {
|
||||||
if (key.usage.contains('master')) {
|
if (key.usage.contains('master')) {
|
||||||
// okay, we'll sign our own master key
|
// okay, we'll sign our own master key
|
||||||
final signature = encryption.olmManager.signString(key.signingContent);
|
final signature =
|
||||||
|
encryption.olmManager.signString(key.signingContent);
|
||||||
addSignature(
|
addSignature(
|
||||||
key,
|
key,
|
||||||
client
|
client
|
||||||
|
@ -172,8 +173,8 @@ class CrossSigning {
|
||||||
}
|
}
|
||||||
} else if (key is CrossSigningKey && key.usage.contains('master')) {
|
} else if (key is CrossSigningKey && key.usage.contains('master')) {
|
||||||
// we are signing someone elses master key
|
// we are signing someone elses master key
|
||||||
userSigningKey ??=
|
userSigningKey ??= base64
|
||||||
base64.decode(await encryption.ssss.getCached(USER_SIGNING_KEY) ?? '');
|
.decode(await encryption.ssss.getCached(USER_SIGNING_KEY) ?? '');
|
||||||
if (userSigningKey.isNotEmpty) {
|
if (userSigningKey.isNotEmpty) {
|
||||||
final signature = _sign(key.signingContent, userSigningKey);
|
final signature = _sign(key.signingContent, userSigningKey);
|
||||||
addSignature(key, client.userDeviceKeys[client.userID].userSigningKey,
|
addSignature(key, client.userDeviceKeys[client.userID].userSigningKey,
|
||||||
|
|
|
@ -93,7 +93,11 @@ class Encryption {
|
||||||
if (update.type == 'ephemeral') {
|
if (update.type == 'ephemeral') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (update.eventType.startsWith('m.key.verification.') || (update.eventType == 'm.room.message' && (update.content['content']['msgtype'] is String) && update.content['content']['msgtype'].startsWith('m.key.verification.'))) {
|
if (update.eventType.startsWith('m.key.verification.') ||
|
||||||
|
(update.eventType == 'm.room.message' &&
|
||||||
|
(update.content['content']['msgtype'] is String) &&
|
||||||
|
update.content['content']['msgtype']
|
||||||
|
.startsWith('m.key.verification.'))) {
|
||||||
// "just" key verification, no need to do this in sync
|
// "just" key verification, no need to do this in sync
|
||||||
unawaited(keyVerificationManager.handleEventUpdate(update));
|
unawaited(keyVerificationManager.handleEventUpdate(update));
|
||||||
}
|
}
|
||||||
|
|
|
@ -321,7 +321,8 @@ class KeyManager {
|
||||||
if (!(payload['rooms'] is Map)) {
|
if (!(payload['rooms'] is Map)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final privateKey = base64.decode(await encryption.ssss.getCached(MEGOLM_KEY));
|
final privateKey =
|
||||||
|
base64.decode(await encryption.ssss.getCached(MEGOLM_KEY));
|
||||||
final decryption = olm.PkDecryption();
|
final decryption = olm.PkDecryption();
|
||||||
final info = await getRoomKeysInfo();
|
final info = await getRoomKeysInfo();
|
||||||
String backupPubKey;
|
String backupPubKey;
|
||||||
|
@ -373,7 +374,9 @@ class KeyManager {
|
||||||
if (decrypted != null) {
|
if (decrypted != null) {
|
||||||
decrypted['session_id'] = sessionId;
|
decrypted['session_id'] = sessionId;
|
||||||
decrypted['room_id'] = roomId;
|
decrypted['room_id'] = roomId;
|
||||||
setInboundGroupSession(roomId, sessionId, decrypted['sender_key'], decrypted, forwarded: true);
|
setInboundGroupSession(
|
||||||
|
roomId, sessionId, decrypted['sender_key'], decrypted,
|
||||||
|
forwarded: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -403,7 +406,8 @@ class KeyManager {
|
||||||
/// Request a certain key from another device
|
/// Request a certain key from another device
|
||||||
Future<void> request(Room room, String sessionId, String senderKey) async {
|
Future<void> request(Room room, String sessionId, String senderKey) async {
|
||||||
// let's first check our online key backup store thingy...
|
// let's first check our online key backup store thingy...
|
||||||
var hadPreviously = getInboundGroupSession(room.id, sessionId, senderKey) != null;
|
var hadPreviously =
|
||||||
|
getInboundGroupSession(room.id, sessionId, senderKey) != null;
|
||||||
try {
|
try {
|
||||||
await loadSingleKey(room.id, sessionId);
|
await loadSingleKey(room.id, sessionId);
|
||||||
} catch (err, stacktrace) {
|
} catch (err, stacktrace) {
|
||||||
|
@ -411,7 +415,8 @@ class KeyManager {
|
||||||
print(err.toString());
|
print(err.toString());
|
||||||
print(stacktrace);
|
print(stacktrace);
|
||||||
}
|
}
|
||||||
if (!hadPreviously && getInboundGroupSession(room.id, sessionId, senderKey) != null) {
|
if (!hadPreviously &&
|
||||||
|
getInboundGroupSession(room.id, sessionId, senderKey) != null) {
|
||||||
return; // we managed to load the session from online backup, no need to care about it now
|
return; // we managed to load the session from online backup, no need to care about it now
|
||||||
}
|
}
|
||||||
// while we just send the to-device event to '*', we still need to save the
|
// while we just send the to-device event to '*', we still need to save the
|
||||||
|
|
|
@ -29,7 +29,7 @@ class KeyVerificationManager {
|
||||||
final Map<String, KeyVerification> _requests = {};
|
final Map<String, KeyVerification> _requests = {};
|
||||||
|
|
||||||
Future<void> cleanup() async {
|
Future<void> cleanup() async {
|
||||||
Set<String> entriesToDispose = <String>{};
|
final Set entriesToDispose = <String>{};
|
||||||
for (final entry in _requests.entries) {
|
for (final entry in _requests.entries) {
|
||||||
var dispose = entry.value.canceled ||
|
var dispose = entry.value.canceled ||
|
||||||
entry.value.state == KeyVerificationState.done ||
|
entry.value.state == KeyVerificationState.done ||
|
||||||
|
@ -55,7 +55,8 @@ class KeyVerificationManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> handleToDeviceEvent(ToDeviceEvent event) async {
|
Future<void> handleToDeviceEvent(ToDeviceEvent event) async {
|
||||||
if (!event.type.startsWith('m.key.verification') || client.verificationMethods.isEmpty) {
|
if (!event.type.startsWith('m.key.verification') ||
|
||||||
|
client.verificationMethods.isEmpty) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// we have key verification going on!
|
// we have key verification going on!
|
||||||
|
@ -84,7 +85,9 @@ class KeyVerificationManager {
|
||||||
final type = event['type'].startsWith('m.key.verification.')
|
final type = event['type'].startsWith('m.key.verification.')
|
||||||
? event['type']
|
? event['type']
|
||||||
: event['content']['msgtype'];
|
: event['content']['msgtype'];
|
||||||
if (type == null || !type.startsWith('m.key.verification.') || client.verificationMethods.isEmpty) {
|
if (type == null ||
|
||||||
|
!type.startsWith('m.key.verification.') ||
|
||||||
|
client.verificationMethods.isEmpty) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type == 'm.key.verification.request') {
|
if (type == 'm.key.verification.request') {
|
||||||
|
@ -97,7 +100,7 @@ class KeyVerificationManager {
|
||||||
if (_requests.containsKey(transactionId)) {
|
if (_requests.containsKey(transactionId)) {
|
||||||
final req = _requests[transactionId];
|
final req = _requests[transactionId];
|
||||||
if (event['sender'] != client.userID) {
|
if (event['sender'] != client.userID) {
|
||||||
req.handlePayload(type, event['content'], event['event_id']);
|
await req.handlePayload(type, event['content'], event['event_id']);
|
||||||
} else if (req.userId == client.userID && req.deviceId == null) {
|
} else if (req.userId == client.userID && req.deviceId == null) {
|
||||||
// okay, maybe another of our devices answered
|
// okay, maybe another of our devices answered
|
||||||
await req.handlePayload(type, event['content'], event['event_id']);
|
await req.handlePayload(type, event['content'], event['event_id']);
|
||||||
|
@ -108,12 +111,12 @@ class KeyVerificationManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (event['sender'] != client.userID) {
|
} else if (event['sender'] != client.userID) {
|
||||||
final room =
|
final room = client.getRoomById(update.roomID) ??
|
||||||
client.getRoomById(update.roomID) ?? Room(id: update.roomID, client: client);
|
Room(id: update.roomID, client: client);
|
||||||
final newKeyRequest =
|
final newKeyRequest = KeyVerification(
|
||||||
KeyVerification(encryption: encryption, userId: event['sender'], room: room);
|
encryption: encryption, userId: event['sender'], room: room);
|
||||||
await newKeyRequest
|
await newKeyRequest.handlePayload(
|
||||||
.handlePayload(type, event['content'], event['event_id']);
|
type, event['content'], event['event_id']);
|
||||||
if (newKeyRequest.state != KeyVerificationState.askAccept) {
|
if (newKeyRequest.state != KeyVerificationState.askAccept) {
|
||||||
// something went wrong, let's just dispose the request
|
// something went wrong, let's just dispose the request
|
||||||
newKeyRequest.dispose();
|
newKeyRequest.dispose();
|
||||||
|
|
|
@ -177,7 +177,10 @@ class SSSS {
|
||||||
}
|
}
|
||||||
// check if it is still valid
|
// check if it is still valid
|
||||||
final keys = keyIdsFromType(type);
|
final keys = keyIdsFromType(type);
|
||||||
if (keys.contains(ret.keyId) && client.accountData[type].content['encrypted'][ret.keyId]['ciphertext'] == ret.ciphertext) {
|
if (keys.contains(ret.keyId) &&
|
||||||
|
client.accountData[type].content['encrypted'][ret.keyId]
|
||||||
|
['ciphertext'] ==
|
||||||
|
ret.ciphertext) {
|
||||||
return ret.content;
|
return ret.content;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -200,7 +203,8 @@ class SSSS {
|
||||||
final decrypted = decryptAes(encryptInfo, key, type);
|
final decrypted = decryptAes(encryptInfo, key, type);
|
||||||
if (CACHE_TYPES.contains(type) && client.database != null) {
|
if (CACHE_TYPES.contains(type) && client.database != null) {
|
||||||
// cache the thing
|
// cache the thing
|
||||||
await client.database.storeSSSSCache(client.id, type, keyId, enc['ciphertext'], decrypted);
|
await client.database
|
||||||
|
.storeSSSSCache(client.id, type, keyId, enc['ciphertext'], decrypted);
|
||||||
}
|
}
|
||||||
return decrypted;
|
return decrypted;
|
||||||
}
|
}
|
||||||
|
@ -224,7 +228,8 @@ class SSSS {
|
||||||
);
|
);
|
||||||
if (CACHE_TYPES.contains(type) && client.database != null) {
|
if (CACHE_TYPES.contains(type) && client.database != null) {
|
||||||
// cache the thing
|
// cache the thing
|
||||||
await client.database.storeSSSSCache(client.id, type, keyId, encrypted.ciphertext, secret);
|
await client.database
|
||||||
|
.storeSSSSCache(client.id, type, keyId, encrypted.ciphertext, secret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,9 +357,10 @@ class SSSS {
|
||||||
if (client.database != null) {
|
if (client.database != null) {
|
||||||
final keyId = keyIdFromType(request.type);
|
final keyId = keyIdFromType(request.type);
|
||||||
if (keyId != null) {
|
if (keyId != null) {
|
||||||
final ciphertext = client.accountData[request.type].content['encrypted'][keyId]['ciphertext'];
|
final ciphertext = client.accountData[request.type]
|
||||||
await client.database
|
.content['encrypted'][keyId]['ciphertext'];
|
||||||
.storeSSSSCache(client.id, request.type, keyId, ciphertext, secret);
|
await client.database.storeSSSSCache(
|
||||||
|
client.id, request.type, keyId, ciphertext, secret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,32 +41,32 @@ class KeysQueryResponse {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
masterKeys = json['master_keys'] != null ?
|
masterKeys = json['master_keys'] != null
|
||||||
(json['master_keys'] as Map).map(
|
? (json['master_keys'] as Map).map(
|
||||||
(k, v) => MapEntry(
|
(k, v) => MapEntry(
|
||||||
k,
|
k,
|
||||||
MatrixCrossSigningKey.fromJson(v),
|
MatrixCrossSigningKey.fromJson(v),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
selfSigningKeys = json['self_signing_keys'] != null ?
|
selfSigningKeys = json['self_signing_keys'] != null
|
||||||
(json['self_signing_keys'] as Map).map(
|
? (json['self_signing_keys'] as Map).map(
|
||||||
(k, v) => MapEntry(
|
(k, v) => MapEntry(
|
||||||
k,
|
k,
|
||||||
MatrixCrossSigningKey.fromJson(v),
|
MatrixCrossSigningKey.fromJson(v),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
userSigningKeys = json['user_signing_keys'] != null ?
|
userSigningKeys = json['user_signing_keys'] != null
|
||||||
(json['user_signing_keys'] as Map).map(
|
? (json['user_signing_keys'] as Map).map(
|
||||||
(k, v) => MapEntry(
|
(k, v) => MapEntry(
|
||||||
k,
|
k,
|
||||||
MatrixCrossSigningKey.fromJson(v),
|
MatrixCrossSigningKey.fromJson(v),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
|
|
|
@ -1160,7 +1160,8 @@ class Client {
|
||||||
final deviceId = rawDeviceKeyEntry.key;
|
final deviceId = rawDeviceKeyEntry.key;
|
||||||
|
|
||||||
// Set the new device key for this device
|
// Set the new device key for this device
|
||||||
final entry = DeviceKeys.fromMatrixDeviceKeys(rawDeviceKeyEntry.value, this);
|
final entry =
|
||||||
|
DeviceKeys.fromMatrixDeviceKeys(rawDeviceKeyEntry.value, this);
|
||||||
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!
|
||||||
|
@ -1231,7 +1232,8 @@ class Client {
|
||||||
if (!userDeviceKeys.containsKey(userId)) {
|
if (!userDeviceKeys.containsKey(userId)) {
|
||||||
_userDeviceKeys[userId] = DeviceKeysList(userId);
|
_userDeviceKeys[userId] = DeviceKeysList(userId);
|
||||||
}
|
}
|
||||||
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 aren't handling atm back
|
// add the types we aren't handling atm back
|
||||||
for (final oldEntry in oldKeys.entries) {
|
for (final oldEntry in oldKeys.entries) {
|
||||||
|
@ -1240,8 +1242,8 @@ class Client {
|
||||||
oldEntry.value;
|
oldEntry.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final entry =
|
final entry = CrossSigningKey.fromMatrixCrossSigningKey(
|
||||||
CrossSigningKey.fromMatrixCrossSigningKey(crossSigningKeyListEntry.value, this);
|
crossSigningKeyListEntry.value, this);
|
||||||
if (entry.isValid) {
|
if (entry.isValid) {
|
||||||
final publicKey = entry.publicKey;
|
final publicKey = entry.publicKey;
|
||||||
if (!oldKeys.containsKey(publicKey) ||
|
if (!oldKeys.containsKey(publicKey) ||
|
||||||
|
|
|
@ -60,7 +60,8 @@ class DeviceKeysList {
|
||||||
throw 'Unable to start new room';
|
throw 'Unable to start new room';
|
||||||
}
|
}
|
||||||
final room = client.getRoomById(roomId) ?? Room(id: roomId, client: client);
|
final room = client.getRoomById(roomId) ?? Room(id: roomId, client: client);
|
||||||
final request = KeyVerification(encryption: client.encryption, room: room, userId: userId);
|
final request = KeyVerification(
|
||||||
|
encryption: client.encryption, room: room, userId: userId);
|
||||||
await request.start();
|
await request.start();
|
||||||
// no need to add to the request client object. As we are doing a room
|
// 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
|
// verification request that'll happen automatically once we know the transaction id
|
||||||
|
@ -224,7 +225,9 @@ abstract class SignedKey {
|
||||||
|
|
||||||
Future<void> setVerified(bool newVerified, [bool sign = true]) {
|
Future<void> setVerified(bool newVerified, [bool sign = true]) {
|
||||||
_verified = newVerified;
|
_verified = newVerified;
|
||||||
if (sign && client.encryptionEnabled && client.encryption.crossSigning.signable([this])) {
|
if (sign &&
|
||||||
|
client.encryptionEnabled &&
|
||||||
|
client.encryption.crossSigning.signable([this])) {
|
||||||
// sign the key!
|
// sign the key!
|
||||||
client.encryption.crossSigning.sign([this]);
|
client.encryption.crossSigning.sign([this]);
|
||||||
}
|
}
|
||||||
|
@ -266,13 +269,16 @@ class CrossSigningKey extends SignedKey {
|
||||||
newBlocked, client.id, userId, publicKey);
|
newBlocked, client.id, userId, publicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
CrossSigningKey.fromMatrixCrossSigningKey(MatrixCrossSigningKey k, Client cl) {
|
CrossSigningKey.fromMatrixCrossSigningKey(
|
||||||
|
MatrixCrossSigningKey k, Client cl) {
|
||||||
client = cl;
|
client = cl;
|
||||||
content = Map<String, dynamic>.from(k.toJson());
|
content = Map<String, dynamic>.from(k.toJson());
|
||||||
userId = k.userId;
|
userId = k.userId;
|
||||||
identifier = k.publicKey;
|
identifier = k.publicKey;
|
||||||
usage = content['usage'].cast<String>();
|
usage = content['usage'].cast<String>();
|
||||||
keys = content['keys'] != null ? Map<String, String>.from(content['keys']) : null;
|
keys = content['keys'] != null
|
||||||
|
? Map<String, String>.from(content['keys'])
|
||||||
|
: null;
|
||||||
signatures = content['signatures'] != null
|
signatures = content['signatures'] != null
|
||||||
? Map<String, dynamic>.from(content['signatures'])
|
? Map<String, dynamic>.from(content['signatures'])
|
||||||
: null;
|
: null;
|
||||||
|
@ -397,8 +403,8 @@ class DeviceKeys extends SignedKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyVerification startVerification() {
|
KeyVerification startVerification() {
|
||||||
final request =
|
final request = KeyVerification(
|
||||||
KeyVerification(encryption: client.encryption, userId: userId, deviceId: deviceId);
|
encryption: client.encryption, userId: userId, deviceId: deviceId);
|
||||||
|
|
||||||
request.start();
|
request.start();
|
||||||
client.encryption.keyVerificationManager.addRequest(request);
|
client.encryption.keyVerificationManager.addRequest(request);
|
||||||
|
|
|
@ -42,15 +42,10 @@ void main() {
|
||||||
},
|
},
|
||||||
'unsigned': {'device_display_name': "Alice's mobile phone"},
|
'unsigned': {'device_display_name': "Alice's mobile phone"},
|
||||||
};
|
};
|
||||||
var rawListJson = <String, dynamic>{
|
|
||||||
'user_id': '@alice:example.com',
|
|
||||||
'outdated': true,
|
|
||||||
'device_keys': {'JLAFKJWSCS': rawJson},
|
|
||||||
};
|
|
||||||
|
|
||||||
final key = DeviceKeys.fromJson(rawJson, null);
|
final key = DeviceKeys.fromJson(rawJson, null);
|
||||||
key.setVerified(false, false);
|
await key.setVerified(false, false);
|
||||||
key.setBlocked(true);
|
await key.setBlocked(true);
|
||||||
expect(json.encode(key.toJson()), json.encode(rawJson));
|
expect(json.encode(key.toJson()), json.encode(rawJson));
|
||||||
expect(key.directVerified, false);
|
expect(key.directVerified, false);
|
||||||
expect(key.blocked, true);
|
expect(key.blocked, true);
|
||||||
|
|
Loading…
Reference in a new issue