-
-
Notifications
You must be signed in to change notification settings - Fork 590
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
Send one time key count and unused fallback keys for rust-crypto #3215
Send one time key count and unused fallback keys for rust-crypto #3215
Conversation
5651a58
to
051d1e9
Compare
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.
@florianduros thanks for getting this working! it's a great start but there's a few things that need a bit of polish before we can call it done imho.
/** | ||
* Called by the /sync loop whenever there are incoming to-device messages. | ||
* | ||
* The implementation may preprocess the received messages (eg, decrypt them) and return an | ||
* updated list of messages for dispatch to the rest of the system. | ||
* | ||
* Note that, unlike {@link ClientEvent.ToDeviceEvent} events, this is called on the raw to-device | ||
* messages, rather than the results of any decryption attempts. | ||
* | ||
* @param oneTimeKeysCounts - the received one time key counts | ||
* @returns A list of preprocessed to-device messages. | ||
*/ |
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.
These doc-comments are inaccurate: these methods aren't doing anything with received messages, nor returning them.
* @param oneTimeKeysCounts - the received one time key counts | ||
* @returns A list of preprocessed to-device messages. | ||
*/ | ||
preprocessOneTimeKeyCounts(oneTimeKeysCounts: Map<string, number>): Promise<void>; |
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.
preprocess...
is not a good name for these methods. "Preprocess" implies there is still some "processing" to be done after the "preprocessing" takes place. You can just use "process" here.
const currentCount = data.device_one_time_keys_count.signed_curve25519 || 0; | ||
this.syncOpts.crypto.updateOneTimeKeyCount(currentCount); | ||
if (data.device_one_time_keys_count) { | ||
const map = new Map<string, number>(Object.entries(data.device_one_time_keys_count)); |
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 we should leave this conversion into a Map
(or Set
, below) to the cryptoCallbacks
implementation.
this.syncOpts.cryptoCallbacks?.preprocessOneTimeKeyCounts(map); | ||
} | ||
if ( | ||
this.syncOpts.crypto && | ||
(data.device_unused_fallback_key_types || data["org.matrix.msc2732.device_unused_fallback_key_types"]) | ||
) { | ||
if (data.device_unused_fallback_key_types || data["org.matrix.msc2732.device_unused_fallback_key_types"]) { | ||
// The presence of device_unused_fallback_key_types indicates that the | ||
// server supports fallback keys. If there's no unused | ||
// signed_curve25519 fallback key we need a new one. | ||
const unusedFallbackKeys = | ||
data.device_unused_fallback_key_types || data["org.matrix.msc2732.device_unused_fallback_key_types"]; | ||
this.syncOpts.crypto.setNeedsNewFallback( | ||
Array.isArray(unusedFallbackKeys) && !unusedFallbackKeys.includes("signed_curve25519"), | ||
); | ||
this.syncOpts.cryptoCallbacks?.preprocessUnusedFallbackKeys(new Set<string>(unusedFallbackKeys || 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.
It might be easier to combine these two methods into one?
this.syncOpts.cryptoCallbacks?.processKeyCounts(data.device_one_time_keys_count, data.device_unused_fallback_key_types ?? data["org.matrix.msc2732.device_unused_fallback_key_types"]);
if (this.syncOpts.crypto && data.device_one_time_keys_count) { | ||
const currentCount = data.device_one_time_keys_count.signed_curve25519 || 0; | ||
this.syncOpts.crypto.updateOneTimeKeyCount(currentCount); | ||
if (data.device_one_time_keys_count) { | ||
const map = new Map<string, number>(Object.entries(data.device_one_time_keys_count)); | ||
this.syncOpts.cryptoCallbacks?.preprocessOneTimeKeyCounts(map); | ||
} | ||
if ( | ||
this.syncOpts.crypto && | ||
(data.device_unused_fallback_key_types || data["org.matrix.msc2732.device_unused_fallback_key_types"]) | ||
) { | ||
if (data.device_unused_fallback_key_types || data["org.matrix.msc2732.device_unused_fallback_key_types"]) { | ||
// The presence of device_unused_fallback_key_types indicates that the | ||
// server supports fallback keys. If there's no unused | ||
// signed_curve25519 fallback key we need a new one. | ||
const unusedFallbackKeys = | ||
data.device_unused_fallback_key_types || data["org.matrix.msc2732.device_unused_fallback_key_types"]; | ||
this.syncOpts.crypto.setNeedsNewFallback( | ||
Array.isArray(unusedFallbackKeys) && !unusedFallbackKeys.includes("signed_curve25519"), | ||
); | ||
this.syncOpts.cryptoCallbacks?.preprocessUnusedFallbackKeys(new Set<string>(unusedFallbackKeys || 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.
we also need to do this for sliding-sync-sdk.ts
, by the way.
{ | ||
overwriteRoutes: true, | ||
}, |
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.
why do we overwriteRoutes here? it could do with a comment at least.
fetchMock.post( | ||
new URL("/_matrix/client/r0/keys/upload", aliceClient.getHomeserverUrl()).toString(), | ||
listener, | ||
{ | ||
overwriteRoutes: true, | ||
}, | ||
); | ||
fetchMock.post( | ||
new URL("/_matrix/client/v3/keys/upload", aliceClient.getHomeserverUrl()).toString(), | ||
listener, | ||
{ | ||
overwriteRoutes: true, | ||
}, | ||
); |
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 to avoid the repetition here, do for (const path in ["/_matrix/client/r0/keys/upload", "/_matrix/client/v3/keys/upload"])
.
it("should make key upload request after sync", async () => { | ||
let uploadPromise = listenToUpload(); | ||
expectAliceKeyQuery({ device_keys: { "@alice:localhost": {} }, failures: {} }); | ||
await startClientAndAwaitFirstSync(); | ||
|
||
syncResponder.sendOrQueueSyncResponse(getSyncResponse([])); | ||
|
||
await syncPromise(aliceClient); | ||
expect(await uploadPromise).toBeGreaterThan(0); | ||
|
||
uploadPromise = listenToUpload(); | ||
syncResponder.sendOrQueueSyncResponse({ | ||
next_batch: 2, | ||
device_one_time_keys_count: { signed_curve25519: 0 }, | ||
}); | ||
|
||
// Advance local date to 2 minutes | ||
// The old crypto only runs the upload every 60 seconds | ||
jest.setSystemTime(Date.now() + 2 * 60 * 1000); | ||
|
||
await syncPromise(aliceClient); | ||
|
||
expect(await uploadPromise).toBeGreaterThan(0); | ||
}); |
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 could probably do with a test for the fallback keys too.
return { | ||
one_time_key_counts: { | ||
signed_curve25519: keysCount ? 60 : keysCount, | ||
}, | ||
}; |
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 going on here? how did we pick these numbers? why does it depend on keysCount
? add some comments please!
let uploadPromise = listenToUpload(); | ||
expectAliceKeyQuery({ device_keys: { "@alice:localhost": {} }, failures: {} }); | ||
await startClientAndAwaitFirstSync(); | ||
|
||
syncResponder.sendOrQueueSyncResponse(getSyncResponse([])); | ||
|
||
await syncPromise(aliceClient); | ||
expect(await uploadPromise).toBeGreaterThan(0); | ||
|
||
uploadPromise = listenToUpload(); | ||
syncResponder.sendOrQueueSyncResponse({ | ||
next_batch: 2, | ||
device_one_time_keys_count: { signed_curve25519: 0 }, | ||
}); | ||
|
||
// Advance local date to 2 minutes | ||
// The old crypto only runs the upload every 60 seconds | ||
jest.setSystemTime(Date.now() + 2 * 60 * 1000); | ||
|
||
await syncPromise(aliceClient); | ||
|
||
expect(await uploadPromise).toBeGreaterThan(0); |
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 could do with some more comments imho. What is going on, what are we checking for?
* Allow via_servers property in findPredecessor (update to MSC3946) ([\matrix-org#3240](matrix-org#3240)). Contributed by @andybalaam. * Fire `closed` event when IndexedDB closes unexpectedly ([\matrix-org#3218](matrix-org#3218)). * Implement MSC3952: intentional mentions ([\matrix-org#3092](matrix-org#3092)). Fixes element-hq/element-web#24376. * Send one time key count and unused fallback keys for rust-crypto ([\matrix-org#3215](matrix-org#3215)). Fixes element-hq/element-web#24795. Contributed by @florianduros. * Improve `processBeaconEvents` hotpath ([\matrix-org#3200](matrix-org#3200)). * Implement MSC3966: a push rule condition to check if an array contains a value ([\matrix-org#3180](matrix-org#3180)). * indexddb-local-backend - return the current sync to database promise … ([\matrix-org#3222](matrix-org#3222)). Contributed by @texuf. * Revert "Add the call object to Call events" ([\matrix-org#3236](matrix-org#3236)). * Handle group call redaction ([\matrix-org#3231](matrix-org#3231)). Fixes vector-im/voip-internal#128. * Stop doing O(n^2) work to find event's home (`eventShouldLiveIn`) ([\matrix-org#3227](matrix-org#3227)). Contributed by @jryans. * Fix bug where video would not unmute if it started muted ([\matrix-org#3213](matrix-org#3213)). Fixes element-hq/element-call#925. * Fixes to event encryption in the Rust Crypto implementation ([\matrix-org#3202](matrix-org#3202)).
Checklist
Fix element-hq/element-web#24795 (comment)
Here's what your changelog entry will look like:
✨ Features