-
-
Notifications
You must be signed in to change notification settings - Fork 600
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
Element-R: Refactor per-session key backup download #3929
Element-R: Refactor per-session key backup download #3929
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was halfway through review when I saw Rich's comments come in, so I'll defer to him
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is broadly sensible, though I haven't yet managed to follow all the logic through from start to finish. I've made a bunch of suggestions to make it easier to follow: please could you try them, and generally make sure that everything is consistent, and then I'll take another check on the logic here.
|
||
/** | ||
* Creates a new backup decryptor for the given private key. | ||
* @param decryptionKey - The private key to use for decryption. | ||
*/ | ||
public createBackupDecryptor(decryptionKey: RustSdkCryptoJs.BackupDecryptionKey): BackupDecryptor { | ||
return new RustBackupDecryptor(decryptionKey); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the point of this? why not inline it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It abstracts the implem RustBackupDecryptor
from BackupDecryptor
, also make it easier to test. just have to mock that instead of mocking somehow the constructor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can mock entire classes with something like https://jestjs.io/docs/es6-class-mocks#mocking-non-default-class-exports, which might be better if you can be bothered. Otherwise this is ok for now.
src/rust-crypto/rust-crypto.ts
Outdated
@@ -82,7 +81,7 @@ interface ISignableObject { | |||
unsigned?: object; | |||
} | |||
|
|||
const KEY_BACKUP_CHECK_RATE_LIMIT = 5000; // ms | |||
const KEY_BACKUP_BACKOFF = 5000; // ms |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggest moving this into PerSessionKeyBackupDownloader
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still think we should move this. It feels odd that we have to keep this const here and pass in an extra parameter to PerSessionKeyBackupDownloader
.
(just make it the default value for backOffDuration
?)
* | ||
* The PerSessionKeyBackupDownloader is resistant to backup configuration changes: it will automatically resume querying when | ||
* the backup is configured correctly. | ||
* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again can this be a lint thing? why do that manually as untold convention
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe, I don't know.
CONFIGURATION_ERROR = "CONFIGURATION_ERROR", | ||
} | ||
|
||
/** Helper type for requested session*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can give more helpful documentation here:
/** Helper type for requested session*/ | |
/** Details of a megolm session whose key we are trying to fetch. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking much clearer and easier to follow now; I think generally it looks good. Still quite a few things which could be cleaned up but will leave it up to you how many you do.
I'd particularly like to get rid of forceCheck
if possible: I think it's an area of significant confusion.
Also I think pauseLoop
is very badly named.
src/rust-crypto/rust-crypto.ts
Outdated
@@ -82,7 +81,7 @@ interface ISignableObject { | |||
unsigned?: object; | |||
} | |||
|
|||
const KEY_BACKUP_CHECK_RATE_LIMIT = 5000; // ms | |||
const KEY_BACKUP_BACKOFF = 5000; // ms |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still think we should move this. It feels odd that we have to keep this const here and pass in an extra parameter to PerSessionKeyBackupDownloader
.
(just make it the default value for backOffDuration
?)
private async getBackupDecryptionKey(): Promise<RustSdkCryptoJs.BackupKeys | null> { | ||
try { | ||
return await this.olmMachine.getBackupKeys(); | ||
} catch (e) { | ||
return null; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think this should be inlined
const configuration = await this.getOrCreateBackupConfiguration(); | ||
if (!configuration) { | ||
// Backup is not configured correctly, so stop the loop. | ||
this.downloadLoopRunning = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is redundant FWIW: the finally
below` will handle it.
Likewise the other one on line 298.
Fixes element-hq/element-web#26535
Fixes element-hq/element-web#26312
Refactoring for the code that is downloading keys from backup per session when a decryption error occurs.
Will fix cache/4S server desync as well as partial history decryption problems
Note for reviewer:
Previously when a decryption error was encountered (in
EventDecryptor
) a call was made tostartQueryKeyBackupRateLimited
. This method was querying the backup and importing the key on success.This mechanism was too limited, because if the call was made before the backup was set up it would fail and it was never retried later on (unless the app is refreshed). It was also always trying to use the decryption key that is in cache even if it's not valid any more.
The current implementation would fail to properly request a lot of sessions, and was probably saved by
key_requesting
that is going on in parallel.This has been refactored by adding a new Object dedicated to per session downloads:
The
PerSessionKeyBackupDownloader
will queue up all requests to backup and process them one by one. It is resistant to invalid configurations (not trusted, no decryption key) and resistant to configuration changes. It will automatically resume querying when the backup is configured correctly.Checklist
This change is marked as an internal change (Task), so will not be included in the changelog.