fix: Remove potential race conditions and database issues with OTK upload

This commit is contained in:
Sorunome 2020-09-10 12:17:38 +02:00
parent b5ac500136
commit 2c7ae759f8
No known key found for this signature in database
GPG key ID: B19471D07FC9BE9C
2 changed files with 63 additions and 52 deletions

View file

@ -68,7 +68,7 @@ class Encryption {
} }
void handleDeviceOneTimeKeysCount(Map<String, int> countJson) { void handleDeviceOneTimeKeysCount(Map<String, int> countJson) {
olmManager.handleDeviceOneTimeKeysCount(countJson); Zone.root.run(() => olmManager.handleDeviceOneTimeKeysCount(countJson));
} }
void onSync() { void onSync() {

View file

@ -130,6 +130,8 @@ class OlmManager {
return isValid; return isValid;
} }
bool _uploadKeysLock = false;
/// Generates new one time keys, signs everything and upload it to the server. /// Generates new one time keys, signs everything and upload it to the server.
Future<bool> uploadKeys( Future<bool> uploadKeys(
{bool uploadDeviceKeys = false, int oldKeyCount = 0}) async { {bool uploadDeviceKeys = false, int oldKeyCount = 0}) async {
@ -137,62 +139,71 @@ class OlmManager {
return true; return true;
} }
// generate one-time keys if (_uploadKeysLock) {
// we generate 2/3rds of max, so that other keys people may still have can return false;
// still be used
final oneTimeKeysCount =
(_olmAccount.max_number_of_one_time_keys() * 2 / 3).floor() -
oldKeyCount;
_olmAccount.generate_one_time_keys(oneTimeKeysCount);
final Map<String, dynamic> oneTimeKeys =
json.decode(_olmAccount.one_time_keys());
// now sign all the one-time keys
final signedOneTimeKeys = <String, dynamic>{};
for (final entry in oneTimeKeys['curve25519'].entries) {
final key = entry.key;
final value = entry.value;
signedOneTimeKeys['signed_curve25519:$key'] = <String, dynamic>{};
signedOneTimeKeys['signed_curve25519:$key'] = signJson({
'key': value,
});
} }
_uploadKeysLock = true;
// and now generate the payload to upload try {
final keysContent = <String, dynamic>{ // generate one-time keys
if (uploadDeviceKeys) // we generate 2/3rds of max, so that other keys people may still have can
'device_keys': { // still be used
'user_id': client.userID, final oneTimeKeysCount =
'device_id': client.deviceID, (_olmAccount.max_number_of_one_time_keys() * 2 / 3).floor() -
'algorithms': [ oldKeyCount;
'm.olm.v1.curve25519-aes-sha2', _olmAccount.generate_one_time_keys(oneTimeKeysCount);
'm.megolm.v1.aes-sha2' final Map<String, dynamic> oneTimeKeys =
], json.decode(_olmAccount.one_time_keys());
'keys': <String, dynamic>{},
}, // now sign all the one-time keys
}; final signedOneTimeKeys = <String, dynamic>{};
if (uploadDeviceKeys) { for (final entry in oneTimeKeys['curve25519'].entries) {
final Map<String, dynamic> keys = final key = entry.key;
json.decode(_olmAccount.identity_keys());
for (final entry in keys.entries) {
final algorithm = entry.key;
final value = entry.value; final value = entry.value;
keysContent['device_keys']['keys']['$algorithm:${client.deviceID}'] = signedOneTimeKeys['signed_curve25519:$key'] = <String, dynamic>{};
value; signedOneTimeKeys['signed_curve25519:$key'] = signJson({
'key': value,
});
} }
keysContent['device_keys'] =
signJson(keysContent['device_keys'] as Map<String, dynamic>);
}
final response = await client.uploadDeviceKeys( // and now generate the payload to upload
deviceKeys: uploadDeviceKeys final keysContent = <String, dynamic>{
? MatrixDeviceKeys.fromJson(keysContent['device_keys']) if (uploadDeviceKeys)
: null, 'device_keys': {
oneTimeKeys: signedOneTimeKeys, 'user_id': client.userID,
); 'device_id': client.deviceID,
_olmAccount.mark_keys_as_published(); 'algorithms': [
await client.database?.updateClientKeys(pickledOlmAccount, client.id); 'm.olm.v1.curve25519-aes-sha2',
return response['signed_curve25519'] == oneTimeKeysCount; 'm.megolm.v1.aes-sha2'
],
'keys': <String, dynamic>{},
},
};
if (uploadDeviceKeys) {
final Map<String, dynamic> keys =
json.decode(_olmAccount.identity_keys());
for (final entry in keys.entries) {
final algorithm = entry.key;
final value = entry.value;
keysContent['device_keys']['keys']['$algorithm:${client.deviceID}'] =
value;
}
keysContent['device_keys'] =
signJson(keysContent['device_keys'] as Map<String, dynamic>);
}
final response = await client.uploadDeviceKeys(
deviceKeys: uploadDeviceKeys
? MatrixDeviceKeys.fromJson(keysContent['device_keys'])
: null,
oneTimeKeys: signedOneTimeKeys,
);
_olmAccount.mark_keys_as_published();
await client.database?.updateClientKeys(pickledOlmAccount, client.id);
return response['signed_curve25519'] == oneTimeKeysCount;
} finally {
_uploadKeysLock = false;
}
} }
void handleDeviceOneTimeKeysCount(Map<String, int> countJson) { void handleDeviceOneTimeKeysCount(Map<String, int> countJson) {