diff --git a/src/rust-crypto/index.ts b/src/rust-crypto/index.ts index 321c43add52..8440052fd6f 100644 --- a/src/rust-crypto/index.ts +++ b/src/rust-crypto/index.ts @@ -77,14 +77,13 @@ export async function initRustCrypto( // Check if there are any key backup secrets pending processing. There may be multiple secrets to process if several devices have gossiped them. // The `registerReceiveSecretCallback` function will only be triggered for new secrets. If the client is restarted before processing them, the secrets will need to be manually handled. - const pendingValues: string[] = await olmMachine.getSecretsFromInbox("m.megolm_backup.v1"); - pendingValues.forEach((value) => { - rustCrypto.onReceiveSecret("m.megolm_backup.v1", value); - }); + rustCrypto.checkSecrets("m.megolm_backup.v1"); // Register a callback to be notified when a new secret is received, as for now only the key backup secret is supported (the cross signing secrets are handled automatically by the OlmMachine) - await olmMachine.registerReceiveSecretCallback((name: string, value: string) => - rustCrypto.onReceiveSecret(name, value), + await olmMachine.registerReceiveSecretCallback((name: string, _value: string) => + // Instead of directly checking the secret value, we poll the inbox to get all values for that secret type. + // Once we have all the values, we can safely clear the secret inbox. + rustCrypto.checkSecrets(name), ); // Tell the OlmMachine to think about its outgoing requests before we hand control back to the application. diff --git a/src/rust-crypto/rust-crypto.ts b/src/rust-crypto/rust-crypto.ts index fdba73e1c62..9034c54d4ea 100644 --- a/src/rust-crypto/rust-crypto.ts +++ b/src/rust-crypto/rust-crypto.ts @@ -1370,22 +1370,39 @@ export class RustCrypto extends TypedEventEmitter { + private async handleSecretReceived(name: string, value: string): Promise { this.logger.debug(`onReceiveSecret: Received secret ${name}`); if (name === "m.megolm_backup.v1") { const isHandled = await this.backupManager.handleBackupSecretReceived(value); - if (isHandled) { - // The secret is valid and stored, clear the inbox. - // Important to call this after storing the secret as good hygiene. - await this.olmMachine.deleteSecretsFromInbox("m.megolm_backup.v1"); + // XXXX at this point we should probably try to download the backup and import the keys, + // or at least retry for the current decryption failures? + // Maybe add some signaling when a new secret is received, and let clients handle it? + // as it's where the restore from backup APIs are exposed. - // XXXX at this point we should probably try to download the backup and import the keys, - // or at least retry for the current decryption failures? - // Maybe add some signaling when a new secret is received, and let clients handle it? - // as it's where the restore from backup APIs are + return isHandled; + } + return false; + } + + /** + * Called when a new secret is received in the rust secret inbox. + * + * Will poll the secret inbox and handle the secrets received. + * + * @param name - The name of the secret received. + * @returns `true` if the secret has been handled and saved, `false` otherwise. + */ + public async checkSecrets(name: string): Promise { + const pendingValues: string[] = await this.olmMachine.getSecretsFromInbox("m.megolm_backup.v1"); + for (const value of pendingValues) { + if (await this.handleSecretReceived(name, value)) { + break; } } + + // Important to call this after handling the secrets as good hygiene. + await this.olmMachine.deleteSecretsFromInbox(name); } /**