diff --git a/spec/integ/crypto/crypto.spec.ts b/spec/integ/crypto/crypto.spec.ts index ed3af3b8e8e..9448b84ecc5 100644 --- a/spec/integ/crypto/crypto.spec.ts +++ b/spec/integ/crypto/crypto.spec.ts @@ -1379,7 +1379,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string, }); expect(decryptedEvent.getContent().body).toEqual("42"); - const exported = await aliceClient.exportRoomKeys(); + const exported = await aliceClient.getCrypto()!.exportRoomKeysAsJson(); // start a new client await aliceClient.stopClient(); @@ -1395,7 +1395,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string, keyReceiver = new E2EKeyReceiver(homeserverUrl); syncResponder = new SyncResponder(homeserverUrl); await initCrypto(aliceClient); - await aliceClient.importRoomKeys(exported); + await aliceClient.getCrypto()!.importRoomKeysAsJson(exported); expectAliceKeyQuery({ device_keys: { "@alice:localhost": {} }, failures: {} }); await startClientAndAwaitFirstSync(); diff --git a/spec/unit/rust-crypto/rust-crypto.spec.ts b/spec/unit/rust-crypto/rust-crypto.spec.ts index 75b3decc6c7..9d7fc913bd3 100644 --- a/spec/unit/rust-crypto/rust-crypto.spec.ts +++ b/spec/unit/rust-crypto/rust-crypto.spec.ts @@ -383,7 +383,7 @@ describe("RustCrypto", () => { ); }); - describe(".importRoomKeys and .exportRoomKeys", () => { + describe("importing and exporting room keys", () => { let rustCrypto: RustCrypto; beforeEach( @@ -416,6 +416,29 @@ describe("RustCrypto", () => { expect(aSession).toStrictEqual(exportedKey); }); + + it("should import and export keys as JSON", async () => { + const someRoomKeys = testData.MEGOLM_SESSION_DATA_ARRAY; + let importTotal = 0; + const opt: ImportRoomKeysOpts = { + progressCallback: (stage) => { + importTotal = stage.total ?? 0; + }, + }; + await rustCrypto.importRoomKeysAsJson(JSON.stringify(someRoomKeys), opt); + + expect(importTotal).toBe(someRoomKeys.length); + + const keys: Array = JSON.parse(await rustCrypto.exportRoomKeysAsJson()); + expect(Array.isArray(keys)).toBeTruthy(); + expect(keys.length).toBe(someRoomKeys.length); + + const aSession = someRoomKeys[0]; + + const exportedKey = keys.find((k) => k.session_id == aSession.session_id); + + expect(aSession).toStrictEqual(exportedKey); + }); }); describe("call preprocess methods", () => { diff --git a/src/crypto-api.ts b/src/crypto-api.ts index 1ce64152668..13d94a29599 100644 --- a/src/crypto-api.ts +++ b/src/crypto-api.ts @@ -96,6 +96,17 @@ export interface CryptoApi { */ exportRoomKeys(): Promise; + /** + * Get a JSON list containing all of the room keys + * + * This should be encrypted before returning it to the user. + * + * @returns a promise which resolves to a JSON string + * encoding a list of session export objects, + * each of which is an IMegolmSessionData + */ + exportRoomKeysAsJson(): Promise; + /** * Import a list of room keys previously exported by exportRoomKeys * @@ -105,6 +116,17 @@ export interface CryptoApi { */ importRoomKeys(keys: IMegolmSessionData[], opts?: ImportRoomKeysOpts): Promise; + /** + * Import a JSON string encoding a list of room keys previously + * exported by exportRoomKeysAsJson + * + * @param keys - a JSON string encoding a list of session export + * objects, each of which is an IMegolmSessionData + * @param opts - options object + * @returns a promise which resolves once the keys have been imported + */ + importRoomKeysAsJson(keys: string, opts?: ImportRoomKeysOpts): Promise; + /** * Check if the given user has published cross-signing keys. * @@ -593,7 +615,8 @@ export class DeviceVerificationStatus { /** * Room key import progress report. - * Used when calling {@link CryptoApi#importRoomKeys} as the parameter of + * Used when calling {@link CryptoApi#importRoomKeys} or + * {@link CryptoApi#importRoomKeysAsJson} as the parameter of * the progressCallback. Used to display feedback. */ export interface ImportRoomKeyProgressData { @@ -604,7 +627,8 @@ export interface ImportRoomKeyProgressData { } /** - * Options object for {@link CryptoApi#importRoomKeys}. + * Options object for {@link CryptoApi#importRoomKeys} and + * {@link CryptoApi#importRoomKeysAsJson}. */ export interface ImportRoomKeysOpts { /** Reports ongoing progress of the import process. Can be used for feedback. */ diff --git a/src/crypto/index.ts b/src/crypto/index.ts index 1a0e4f43dae..0f6018b8e15 100644 --- a/src/crypto/index.ts +++ b/src/crypto/index.ts @@ -3142,6 +3142,16 @@ export class Crypto extends TypedEventEmitter { + return JSON.stringify(await this.exportRoomKeys()); + } + /** * Import a list of room keys previously exported by exportRoomKeys * @@ -3184,6 +3194,19 @@ export class Crypto extends TypedEventEmitter { + return await this.importRoomKeys(JSON.parse(keys)); + } + /** * Counts the number of end to end session keys that are waiting to be backed up * @returns Promise which resolves to the number of sessions requiring backup diff --git a/src/rust-crypto/backup.ts b/src/rust-crypto/backup.ts index d7ca7d85a42..0fb1640320b 100644 --- a/src/rust-crypto/backup.ts +++ b/src/rust-crypto/backup.ts @@ -188,7 +188,18 @@ export class RustBackupManager extends TypedEventEmitter { - const jsonKeys = JSON.stringify(keys); + await this.importRoomKeysAsJson(JSON.stringify(keys), opts); + } + + /** + * Import a list of room keys previously exported by exportRoomKeysAsJson + * + * @param keys - a JSON string encoding a list of session export objects, + * each of which is an IMegolmSessionData + * @param opts - options object + * @returns a promise which resolves once the keys have been imported + */ + public async importRoomKeysAsJson(jsonKeys: string, opts?: ImportRoomKeysOpts): Promise { await this.olmMachine.importExportedRoomKeys(jsonKeys, (progress: BigInt, total: BigInt): void => { const importOpt: ImportRoomKeyProgressData = { total: Number(total), diff --git a/src/rust-crypto/rust-crypto.ts b/src/rust-crypto/rust-crypto.ts index 30c27201f9d..ace265b150c 100644 --- a/src/rust-crypto/rust-crypto.ts +++ b/src/rust-crypto/rust-crypto.ts @@ -346,10 +346,18 @@ export class RustCrypto extends TypedEventEmitter { + return await this.olmMachine.exportRoomKeys(() => true); + } + public async importRoomKeys(keys: IMegolmSessionData[], opts?: ImportRoomKeysOpts): Promise { return await this.backupManager.importRoomKeys(keys, opts); } + public async importRoomKeysAsJson(keys: string, opts?: ImportRoomKeysOpts): Promise { + return await this.backupManager.importRoomKeysAsJson(keys, opts); + } + /** * Implementation of {@link CryptoApi.userHasCrossSigningKeys}. */