Skip to content

Fix RustCrypto.resetEncryption failure #4772

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 1, 2025

Conversation

florianduros
Copy link
Contributor

@florianduros florianduros commented Mar 31, 2025

Regression due to #4742

When RustCrypto.resetEncryption is called, CrossSigningIdentity.resetCrossSigning raises this error:

Uncaught (in promise) Error: No keys specified and no default key present
    store secret-storage.ts:525
    exportCrossSigningKeysToStorage CrossSigningIdentity.ts:184
    resetCrossSigning CrossSigningIdentity.ts:154
    bootstrapCrossSigning CrossSigningIdentity.ts:46
    resetEncryption rust-crypto.ts:1473
    onClick ResetIdentityPanel.tsx:92
    React 23
    getOrCreateStaticRoot Modal.tsx:109
    reRender Modal.tsx:415
    createDialog Modal.tsx:316
    MatrixChat MatrixChat.tsx:781
    invokeCallback dispatcher.ts:115
secret-storage.ts:525:22

The 4S is not completely deleted and we try to export keys that has been deleted. Due to of missing await on this.deleteSecretStorage() in

public async resetEncryption(authUploadDeviceSigningKeys: UIAuthCallback<void>): Promise<void> {
this.logger.debug("resetEncryption: resetting encryption");
// Delete the dehydrated device, since any existing one will be signed
// by the wrong cross-signing key
this.dehydratedDeviceManager.delete();
// Disable backup, and delete all the backups from the server
await this.backupManager.deleteAllKeyBackupVersions();
this.deleteSecretStorage();
// Reset the cross-signing keys
await this.crossSigningIdentity.bootstrapCrossSigning({
setupNewCrossSigning: true,
authUploadDeviceSigningKeys,
});
// Create a new key backup
await this.resetKeyBackup();
this.logger.debug("resetEncryption: ended");
}

The secretStorage object is mocked in the test, the mock making it synchronous so the test didn't catch the race.

Copy link
Member

@andybalaam andybalaam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, one request 👍

@@ -1466,6 +1466,7 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
await this.backupManager.deleteAllKeyBackupVersions();

this.deleteSecretStorage();
await this.deleteSecretStorage();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update the test so this would be caught by it please?

Copy link
Contributor Author

@florianduros florianduros Apr 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is difficult because we are using a mocked SecretStorage which is way faster than the real execution. Meaning that even by adding jest.fn().mockResolvedValue(undefined) to store or setDefaultKeyId, the test passes. Also I don't think that adding manual latency is a good thing neither.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I'd prefer the change to mockResolvedValue for async methods, even if it doesn't make the test fail. Personally I would add a small delay that makes the test fail but I definitely won't insist on that.

I'll tick the PR and you can use your judgement. Thank you!

@florianduros florianduros enabled auto-merge April 1, 2025 12:55
@florianduros florianduros added this pull request to the merge queue Apr 1, 2025
Merged via the queue into develop with commit 5976083 Apr 1, 2025
30 checks passed
@florianduros florianduros deleted the florianduros/fix-reset-encryption branch April 1, 2025 13:14
Comment on lines 1468 to +1469
this.deleteSecretStorage();
await this.deleteSecretStorage();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@florianduros: Why do we need to do this.deleteSecretStorage() and await this.deleteSecretStorage(); ?

Copy link
Contributor Author

@florianduros florianduros Apr 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, an error during the rebase. Good spot, I'll fix it tomorrow

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in #4789

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants