fix: Deduplicate key OTK uploads
We do the key upload asynchronously without awaiting it. This means we may do multiple syncs before the key upload finishes. So we may generate more keys than we should. To fix that prevent multiple key uploads from running at once. This may lead to outdated key uploads in some cases if we miss an OTK being used in sync. However, the next sync will still tell us about that so in the worst case this might delay key uploads by 30s (with the default sync timeout), which for normal usage should be completely acceptable.
This commit is contained in:
parent
583be5ece7
commit
6a28ab05d0
|
|
@ -28,6 +28,7 @@ import 'package:matrix/encryption/utils/json_signature_check_extension.dart';
|
||||||
import 'package:matrix/encryption/utils/olm_session.dart';
|
import 'package:matrix/encryption/utils/olm_session.dart';
|
||||||
import 'package:matrix/matrix.dart';
|
import 'package:matrix/matrix.dart';
|
||||||
import 'package:matrix/msc_extensions/msc_3814_dehydrated_devices/api.dart';
|
import 'package:matrix/msc_extensions/msc_3814_dehydrated_devices/api.dart';
|
||||||
|
import 'package:matrix/src/utils/run_benchmarked.dart';
|
||||||
import 'package:matrix/src/utils/run_in_root.dart';
|
import 'package:matrix/src/utils/run_in_root.dart';
|
||||||
|
|
||||||
class OlmManager {
|
class OlmManager {
|
||||||
|
|
@ -326,43 +327,50 @@ class OlmManager {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final _otkUpdateDedup = AsyncCache<void>.ephemeral();
|
||||||
|
|
||||||
Future<void> handleDeviceOneTimeKeysCount(
|
Future<void> handleDeviceOneTimeKeysCount(
|
||||||
Map<String, int>? countJson, List<String>? unusedFallbackKeyTypes) async {
|
Map<String, int>? countJson, List<String>? unusedFallbackKeyTypes) async {
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final haveFallbackKeys = encryption.isMinOlmVersion(3, 2, 0);
|
|
||||||
// Check if there are at least half of max_number_of_one_time_keys left on the server
|
|
||||||
// and generate and upload more if not.
|
|
||||||
|
|
||||||
// If the server did not send us a count, assume it is 0
|
await _otkUpdateDedup.fetch(() =>
|
||||||
final keyCount = countJson?.tryGet<int>('signed_curve25519') ?? 0;
|
runBenchmarked('handleOtkUpdate', () async {
|
||||||
|
final haveFallbackKeys = encryption.isMinOlmVersion(3, 2, 0);
|
||||||
|
// Check if there are at least half of max_number_of_one_time_keys left on the server
|
||||||
|
// and generate and upload more if not.
|
||||||
|
|
||||||
// If the server does not support fallback keys, it will not tell us about them.
|
// If the server did not send us a count, assume it is 0
|
||||||
// If the server supports them but has no key, upload a new one.
|
final keyCount = countJson?.tryGet<int>('signed_curve25519') ?? 0;
|
||||||
var unusedFallbackKey = true;
|
|
||||||
if (unusedFallbackKeyTypes?.contains('signed_curve25519') == false) {
|
|
||||||
unusedFallbackKey = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// fixup accidental too many uploads. We delete only one of them so that the server has time to update the counts and because we will get rate limited anyway.
|
// If the server does not support fallback keys, it will not tell us about them.
|
||||||
if (keyCount > _olmAccount!.max_number_of_one_time_keys()) {
|
// If the server supports them but has no key, upload a new one.
|
||||||
final requestingKeysFrom = {
|
var unusedFallbackKey = true;
|
||||||
client.userID!: {ourDeviceId!: 'signed_curve25519'}
|
if (unusedFallbackKeyTypes?.contains('signed_curve25519') == false) {
|
||||||
};
|
unusedFallbackKey = false;
|
||||||
await client.claimKeys(requestingKeysFrom, timeout: 10000);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Only upload keys if they are less than half of the max or we have no unused fallback key
|
// fixup accidental too many uploads. We delete only one of them so that the server has time to update the counts and because we will get rate limited anyway.
|
||||||
if (keyCount < (_olmAccount!.max_number_of_one_time_keys() / 2) ||
|
if (keyCount > _olmAccount!.max_number_of_one_time_keys()) {
|
||||||
!unusedFallbackKey) {
|
final requestingKeysFrom = {
|
||||||
await uploadKeys(
|
client.userID!: {ourDeviceId!: 'signed_curve25519'}
|
||||||
oldKeyCount: keyCount < (_olmAccount!.max_number_of_one_time_keys() / 2)
|
};
|
||||||
? keyCount
|
await client.claimKeys(requestingKeysFrom, timeout: 10000);
|
||||||
: null,
|
}
|
||||||
unusedFallbackKey: haveFallbackKeys ? unusedFallbackKey : null,
|
|
||||||
);
|
// Only upload keys if they are less than half of the max or we have no unused fallback key
|
||||||
}
|
if (keyCount < (_olmAccount!.max_number_of_one_time_keys() / 2) ||
|
||||||
|
!unusedFallbackKey) {
|
||||||
|
await uploadKeys(
|
||||||
|
oldKeyCount:
|
||||||
|
keyCount < (_olmAccount!.max_number_of_one_time_keys() / 2)
|
||||||
|
? keyCount
|
||||||
|
: null,
|
||||||
|
unusedFallbackKey: haveFallbackKeys ? unusedFallbackKey : null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> storeOlmSession(OlmSession session) async {
|
Future<void> storeOlmSession(OlmSession session) async {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue