fix: validate account_data values instead of checking them in syncUpdates

This commit is contained in:
td 2023-12-20 21:10:31 +05:30
parent 6b66451d70
commit dc411c9b14
No known key found for this signature in database
GPG Key ID: 62A30523D4D6CE28
3 changed files with 44 additions and 48 deletions

View File

@ -248,15 +248,16 @@ class SSSS {
}() }()
.firstWhere((keyId) => getKey(keyId) == null); .firstWhere((keyId) => getKey(keyId) == null);
final accountDataType = EventTypes.secretStorageKey(keyId); final accountDataTypeKeyId = EventTypes.secretStorageKey(keyId);
// noooow we set the account data // noooow we set the account data
final waitForAccountData = client.onSync.stream.firstWhere((syncUpdate) =>
syncUpdate.accountData != null &&
syncUpdate.accountData!
.any((accountData) => accountData.type == accountDataType));
await client.setAccountData( await client.setAccountData(
client.userID!, accountDataType, content.toJson()); client.userID!, accountDataTypeKeyId, content.toJson());
await waitForAccountData;
while (!client.accountData.containsKey(accountDataTypeKeyId)) {
Logs().v('Waiting accountData to have $accountDataTypeKeyId');
await client.oneShotSync();
}
final key = open(keyId); final key = open(keyId);
await key.setPrivateKey(privateKey); await key.setPrivateKey(privateKey);
@ -327,7 +328,7 @@ class SSSS {
} }
final enc = encryptedContent.tryGetMap<String, Object?>(keyId); final enc = encryptedContent.tryGetMap<String, Object?>(keyId);
if (enc == null) { if (enc == null) {
throw Exception('Wrong / unknown key'); throw Exception('Wrong / unknown key: $type, $keyId');
} }
final ciphertext = enc.tryGet<String>('ciphertext'); final ciphertext = enc.tryGet<String>('ciphertext');
final iv = enc.tryGet<String>('iv'); final iv = enc.tryGet<String>('iv');
@ -750,6 +751,14 @@ class OpenSSSS {
throw Exception('SSSS not unlocked'); throw Exception('SSSS not unlocked');
} }
await ssss.store(type, secret, keyId, privateKey, add: add); await ssss.store(type, secret, keyId, privateKey, add: add);
while (!ssss.client.accountData.containsKey(type) ||
!(ssss.client.accountData[type]!.content
.tryGetMap<String, Object?>('encrypted')!
.containsKey(keyId)) ||
await getStored(type) != secret) {
Logs().d('Wait for secret of $type to match in accountdata');
await ssss.client.oneShotSync();
}
} }
Future<void> validateAndStripOtherKeys(String type, String secret) async { Future<void> validateAndStripOtherKeys(String type, String secret) async {

View File

@ -90,6 +90,8 @@ class Bootstrap {
// cache the secret analyzing so that we don't drop stuff a different client sets during bootstrapping // cache the secret analyzing so that we don't drop stuff a different client sets during bootstrapping
Map<String, Set<String>>? _secretsCache; Map<String, Set<String>>? _secretsCache;
/// returns ssss from accountdata, eg: m.megolm_backup.v1, or your m.cross_signing stuff
Map<String, Set<String>> analyzeSecrets() { Map<String, Set<String>> analyzeSecrets() {
final secretsCache = _secretsCache; final secretsCache = _secretsCache;
if (secretsCache != null) { if (secretsCache != null) {
@ -292,12 +294,12 @@ class Bootstrap {
} }
// alright, we re-encrypted all the secrets. We delete the dead weight only *after* we set our key to the default key // alright, we re-encrypted all the secrets. We delete the dead weight only *after* we set our key to the default key
} }
final updatedAccountData = client.onSync.stream.firstWhere((syncUpdate) =>
syncUpdate.accountData != null &&
syncUpdate.accountData!.any((accountData) =>
accountData.type == EventTypes.SecretStorageDefaultKey));
await encryption.ssss.setDefaultKeyId(newSsssKey!.keyId); await encryption.ssss.setDefaultKeyId(newSsssKey!.keyId);
await updatedAccountData; while (encryption.ssss.defaultKeyId != newSsssKey!.keyId) {
Logs().v(
'Waiting accountData to have the correct m.secret_storage.default_key');
await client.oneShotSync();
}
if (oldSsssKeys != null) { if (oldSsssKeys != null) {
for (final entry in secretMap!.entries) { for (final entry in secretMap!.entries) {
Logs().v('Validate and stripe other keys ${entry.key}...'); Logs().v('Validate and stripe other keys ${entry.key}...');
@ -479,33 +481,23 @@ class Bootstrap {
)); ));
Logs().v('Device signing keys have been uploaded.'); Logs().v('Device signing keys have been uploaded.');
// aaaand set the SSSS secrets // aaaand set the SSSS secrets
final futures = <Future<void>>[];
if (masterKey != null) { if (masterKey != null) {
futures.add( while (!(masterKey.publicKey != null &&
client.onSync.stream
.firstWhere((syncUpdate) =>
masterKey?.publicKey != null &&
client.userDeviceKeys[client.userID]?.masterKey?.ed25519Key == client.userDeviceKeys[client.userID]?.masterKey?.ed25519Key ==
masterKey?.publicKey) masterKey.publicKey)) {
.then((_) => Logs().v('New Master Key was created')), Logs().v('Waiting for master to be created');
); await client.oneShotSync();
} }
}
if (newSsssKey != null) {
final storeFutures = <Future<void>>[];
for (final entry in secretsToStore.entries) { for (final entry in secretsToStore.entries) {
futures.add( storeFutures.add(newSsssKey!.store(entry.key, entry.value));
client.onSync.stream
.firstWhere((syncUpdate) =>
syncUpdate.accountData != null &&
syncUpdate.accountData!
.any((accountData) => accountData.type == entry.key))
.then((_) =>
Logs().v('New Key with type ${entry.key} was created')),
);
Logs().v('Store new SSSS key ${entry.key}...');
await newSsssKey?.store(entry.key, entry.value);
} }
Logs().v( Logs().v('Store new SSSS key entries...');
'Wait for MasterKey and ${secretsToStore.entries.length} keys to be created'); await Future.wait(storeFutures);
await Future.wait<void>(futures); }
final keysToSign = <SignableKey>[]; final keysToSign = <SignableKey>[];
if (masterKey != null) { if (masterKey != null) {
if (client.userDeviceKeys[client.userID]?.masterKey?.ed25519Key != if (client.userDeviceKeys[client.userID]?.masterKey?.ed25519Key !=
@ -581,14 +573,6 @@ class Bootstrap {
); );
Logs().v('Store the secret...'); Logs().v('Store the secret...');
await newSsssKey?.store(megolmKey, base64.encode(privKey)); await newSsssKey?.store(megolmKey, base64.encode(privKey));
Logs().v('Wait for secret to come down sync');
if (!await encryption.keyManager.isCached()) {
await client.onSync.stream.firstWhere((syncUpdate) =>
syncUpdate.accountData != null &&
syncUpdate.accountData!
.any((accountData) => accountData.type == megolmKey));
}
Logs().v( Logs().v(
'And finally set all megolm keys as needing to be uploaded again...'); 'And finally set all megolm keys as needing to be uploaded again...');

View File

@ -107,9 +107,12 @@ void main() {
await handle.unlock(recoveryKey: ssssKey); await handle.unlock(recoveryKey: ssssKey);
expect(handle.isUnlocked, true); expect(handle.isUnlocked, true);
FakeMatrixApi.calledEndpoints.clear(); FakeMatrixApi.calledEndpoints.clear();
await handle.store('best animal', 'foxies');
// alright, since we don't properly sync we will manually have to update // OpenSSSS store waits for accountdata to be updated before returning
// account_data for this test // but we can't update that before the below endpoint is not hit.
await handle.ssss
.store('best animal', 'foxies', handle.keyId, handle.privateKey!);
final content = FakeMatrixApi final content = FakeMatrixApi
.calledEndpoints[ .calledEndpoints[
'/client/v3/user/%40test%3AfakeServer.notExisting/account_data/best%20animal']! '/client/v3/user/%40test%3AfakeServer.notExisting/account_data/best%20animal']!