Merge pull request #1584 from famedly/td/fixAwaitSecrets
fix: validate account_data values instead of checking them in syncUpdates
This commit is contained in:
commit
067a61ed18
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
client.userDeviceKeys[client.userID]?.masterKey?.ed25519Key ==
|
||||||
.firstWhere((syncUpdate) =>
|
masterKey.publicKey)) {
|
||||||
masterKey?.publicKey != null &&
|
Logs().v('Waiting for master to be created');
|
||||||
client.userDeviceKeys[client.userID]?.masterKey?.ed25519Key ==
|
await client.oneShotSync();
|
||||||
masterKey?.publicKey)
|
}
|
||||||
.then((_) => Logs().v('New Master Key was created')),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
for (final entry in secretsToStore.entries) {
|
if (newSsssKey != null) {
|
||||||
futures.add(
|
final storeFutures = <Future<void>>[];
|
||||||
client.onSync.stream
|
for (final entry in secretsToStore.entries) {
|
||||||
.firstWhere((syncUpdate) =>
|
storeFutures.add(newSsssKey!.store(entry.key, entry.value));
|
||||||
syncUpdate.accountData != null &&
|
}
|
||||||
syncUpdate.accountData!
|
Logs().v('Store new SSSS key entries...');
|
||||||
.any((accountData) => accountData.type == entry.key))
|
await Future.wait(storeFutures);
|
||||||
.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(
|
|
||||||
'Wait for MasterKey and ${secretsToStore.entries.length} keys to be created');
|
|
||||||
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...');
|
||||||
|
|
|
||||||
|
|
@ -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']!
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue