Skip to content

Commit a9e7a46

Browse files
authored
Upload device keys during initCrypto (#2872)
Rather than waiting for the application to call `.startClient`, upload the device keys during `initCrypto()`. Element-R is going to approach this slightly differently (it wants to manage the decision on key uploads itself), so this lays some groundwork by collecting the libolm-specific bits together.
1 parent 4a7365f commit a9e7a46

File tree

5 files changed

+47
-18
lines changed

5 files changed

+47
-18
lines changed

spec/integ/matrix-client-crypto.spec.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,7 @@ type OlmPayload = ReturnType<Session["encrypt"]>;
5353

5454
async function bobUploadsDeviceKeys(): Promise<void> {
5555
bobTestClient.expectDeviceKeyUpload();
56-
await Promise.all([
57-
bobTestClient.client.uploadKeys(),
58-
bobTestClient.httpBackend.flushAllExpected(),
59-
]);
56+
await bobTestClient.httpBackend.flushAllExpected();
6057
expect(Object.keys(bobTestClient.deviceKeys!).length).not.toEqual(0);
6158
}
6259

@@ -383,6 +380,14 @@ describe("MatrixClient crypto", () => {
383380

384381
it("Bob uploads device keys", bobUploadsDeviceKeys);
385382

383+
it("handles failures to upload device keys", async () => {
384+
// since device keys are uploaded asynchronously, there's not really much to do here other than fail the
385+
// upload.
386+
bobTestClient.httpBackend.when("POST", "/keys/upload")
387+
.fail(0, new Error("bleh"));
388+
await bobTestClient.httpBackend.flushAllExpected();
389+
});
390+
386391
it("Ali downloads Bobs device keys", async () => {
387392
await bobUploadsDeviceKeys();
388393
await aliDownloadsKeys();

spec/integ/matrix-client-methods.spec.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,12 @@ describe("MatrixClient", function() {
511511
}
512512

513513
beforeEach(function() {
514-
return client!.initCrypto();
514+
// running initCrypto should trigger a key upload
515+
httpBackend!.when("POST", "/keys/upload").respond(200, {});
516+
return Promise.all([
517+
client!.initCrypto(),
518+
httpBackend!.flush("/keys/upload", 1),
519+
]);
515520
});
516521

517522
afterEach(() => {
@@ -1371,6 +1376,13 @@ describe("MatrixClient", function() {
13711376
await prom;
13721377
});
13731378
});
1379+
1380+
describe("uploadKeys", () => {
1381+
// uploadKeys() is a no-op nowadays, so there's not much to test here.
1382+
it("should complete successfully", async () => {
1383+
await client!.uploadKeys();
1384+
});
1385+
});
13741386
});
13751387

13761388
function withThreadId(event: MatrixEvent, newThreadId: string): MatrixEvent {

spec/unit/crypto.spec.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -995,7 +995,13 @@ describe("Crypto", function() {
995995
});
996996

997997
client = new TestClient("@alice:example.org", "aliceweb");
998-
await client.client.initCrypto();
998+
999+
// running initCrypto should trigger a key upload
1000+
client.httpBackend.when("POST", "/keys/upload").respond(200, {});
1001+
await Promise.all([
1002+
client.client.initCrypto(),
1003+
client.httpBackend.flush("/keys/upload", 1),
1004+
]);
9991005

10001006
encryptedPayload = {
10011007
algorithm: "m.olm.v1.curve25519-aes-sha2",

spec/unit/crypto/backup.spec.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ function makeTestClient(cryptoStore: CryptoStore) {
135135
const scheduler = makeTestScheduler();
136136
const store = new StubStore();
137137

138-
return new MatrixClient({
138+
const client = new MatrixClient({
139139
baseUrl: "https://my.home.server",
140140
idBaseUrl: "https://identity.server",
141141
accessToken: "my.access.token",
@@ -147,6 +147,10 @@ function makeTestClient(cryptoStore: CryptoStore) {
147147
cryptoStore: cryptoStore,
148148
cryptoCallbacks: { getCrossSigningKey, saveCrossSigningKeys },
149149
});
150+
151+
// initialising the crypto library will trigger a key upload request, which we can stub out
152+
client.uploadKeysRequest = jest.fn();
153+
return client;
150154
}
151155

152156
describe("MegolmBackup", function() {
@@ -509,6 +513,8 @@ describe("MegolmBackup", function() {
509513
deviceId: "device",
510514
cryptoStore: cryptoStore,
511515
});
516+
// initialising the crypto library will trigger a key upload request, which we can stub out
517+
client.uploadKeysRequest = jest.fn();
512518

513519
megolmDecryption = new MegolmDecryption({
514520
userId: '@user:id',
@@ -724,6 +730,9 @@ describe("MegolmBackup", function() {
724730
deviceId: "device",
725731
cryptoStore,
726732
});
733+
// initialising the crypto library will trigger a key upload request, which we can stub out
734+
client.uploadKeysRequest = jest.fn();
735+
727736
await client.initCrypto();
728737

729738
cryptoStore.countSessionsNeedingBackup = jest.fn().mockReturnValue(6);

src/client.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,10 +1210,6 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
12101210
this.store.storeUser(new User(userId));
12111211
}
12121212

1213-
if (this.crypto) {
1214-
this.crypto.uploadDeviceKeys();
1215-
}
1216-
12171213
// periodically poll for turn servers if we support voip
12181214
if (this.canSupportVoip) {
12191215
this.checkTurnServersIntervalID = setInterval(() => {
@@ -1864,6 +1860,12 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
18641860
// if crypto initialisation was successful, tell it to attach its event handlers.
18651861
crypto.registerEventHandlers(this as Parameters<Crypto["registerEventHandlers"]>[0]);
18661862
this.crypto = crypto;
1863+
1864+
// upload our keys in the background
1865+
this.crypto.uploadDeviceKeys().catch((e) => {
1866+
// TODO: throwing away this error is a really bad idea.
1867+
logger.error("Error uploading device keys", e);
1868+
});
18671869
}
18681870

18691871
/**
@@ -1895,15 +1897,10 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
18951897
}
18961898

18971899
/**
1898-
* Upload the device keys to the homeserver.
1899-
* @return {Promise<void>} A promise that will resolve when the keys are uploaded.
1900+
* @deprecated Does nothing.
19001901
*/
19011902
public async uploadKeys(): Promise<void> {
1902-
if (!this.crypto) {
1903-
throw new Error("End-to-end encryption disabled");
1904-
}
1905-
1906-
await this.crypto.uploadDeviceKeys();
1903+
logger.warn("MatrixClient.uploadKeys is deprecated");
19071904
}
19081905

19091906
/**

0 commit comments

Comments
 (0)