Skip to content

Commit

Permalink
Add AsJson forms of the key import/export methods (matrix-org#4057)
Browse files Browse the repository at this point in the history
  • Loading branch information
andybalaam authored Feb 8, 2024
1 parent f4a796c commit 1b7695c
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 6 deletions.
4 changes: 2 additions & 2 deletions spec/integ/crypto/crypto.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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();

Expand Down
25 changes: 24 additions & 1 deletion spec/unit/rust-crypto/rust-crypto.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ describe("RustCrypto", () => {
);
});

describe(".importRoomKeys and .exportRoomKeys", () => {
describe("importing and exporting room keys", () => {
let rustCrypto: RustCrypto;

beforeEach(
Expand Down Expand Up @@ -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<IMegolmSessionData> = 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", () => {
Expand Down
28 changes: 26 additions & 2 deletions src/crypto-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,17 @@ export interface CryptoApi {
*/
exportRoomKeys(): Promise<IMegolmSessionData[]>;

/**
* 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<string>;

/**
* Import a list of room keys previously exported by exportRoomKeys
*
Expand All @@ -105,6 +116,17 @@ export interface CryptoApi {
*/
importRoomKeys(keys: IMegolmSessionData[], opts?: ImportRoomKeysOpts): Promise<void>;

/**
* 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<void>;

/**
* Check if the given user has published cross-signing keys.
*
Expand Down Expand Up @@ -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 {
Expand All @@ -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. */
Expand Down
23 changes: 23 additions & 0 deletions src/crypto/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3142,6 +3142,16 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
return exportedSessions;
}

/**
* Get a JSON list containing all of the room keys
*
* @returns a JSON string encoding a list of session
* export objects, each of which is an IMegolmSessionData
*/
public async exportRoomKeysAsJson(): Promise<string> {
return JSON.stringify(await this.exportRoomKeys());
}

/**
* Import a list of room keys previously exported by exportRoomKeys
*
Expand Down Expand Up @@ -3184,6 +3194,19 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
).then();
}

/**
* 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
*/
public async importRoomKeysAsJson(keys: string, opts?: ImportRoomKeysOpts): Promise<void> {
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
Expand Down
13 changes: 12 additions & 1 deletion src/rust-crypto/backup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,18 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
* @returns a promise which resolves once the keys have been imported
*/
public async importRoomKeys(keys: IMegolmSessionData[], opts?: ImportRoomKeysOpts): Promise<void> {
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<void> {
await this.olmMachine.importExportedRoomKeys(jsonKeys, (progress: BigInt, total: BigInt): void => {
const importOpt: ImportRoomKeyProgressData = {
total: Number(total),
Expand Down
8 changes: 8 additions & 0 deletions src/rust-crypto/rust-crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,10 +346,18 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, RustCryptoEv
return JSON.parse(raw);
}

public async exportRoomKeysAsJson(): Promise<string> {
return await this.olmMachine.exportRoomKeys(() => true);
}

public async importRoomKeys(keys: IMegolmSessionData[], opts?: ImportRoomKeysOpts): Promise<void> {
return await this.backupManager.importRoomKeys(keys, opts);
}

public async importRoomKeysAsJson(keys: string, opts?: ImportRoomKeysOpts): Promise<void> {
return await this.backupManager.importRoomKeysAsJson(keys, opts);
}

/**
* Implementation of {@link CryptoApi.userHasCrossSigningKeys}.
*/
Expand Down

0 comments on commit 1b7695c

Please sign in to comment.