You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-07-30 04:23:07 +03:00
Deprecate MatrixClient.{prepare,create}KeyBackupVersion
in favour of new CryptoApi.resetKeyBackup
API (#3689)
* new resetKeyBackup API * add delete backup version test * code review * code review
This commit is contained in:
@ -40,6 +40,7 @@ import { logger } from "../../../src/logger";
|
||||
import {
|
||||
Category,
|
||||
createClient,
|
||||
CryptoEvent,
|
||||
IClaimOTKsResult,
|
||||
IContent,
|
||||
IDownloadKeyResult,
|
||||
@ -61,9 +62,13 @@ import { ISyncResponder, SyncResponder } from "../../test-utils/SyncResponder";
|
||||
import { escapeRegExp } from "../../../src/utils";
|
||||
import { downloadDeviceToJsDevice } from "../../../src/rust-crypto/device-converter";
|
||||
import { flushPromises } from "../../test-utils/flushPromises";
|
||||
import { mockInitialApiRequests, mockSetupCrossSigningRequests } from "../../test-utils/mockEndpoints";
|
||||
import {
|
||||
mockInitialApiRequests,
|
||||
mockSetupCrossSigningRequests,
|
||||
mockSetupMegolmBackupRequests,
|
||||
} from "../../test-utils/mockEndpoints";
|
||||
import { AddSecretStorageKeyOpts, SECRET_STORAGE_ALGORITHM_V1_AES } from "../../../src/secret-storage";
|
||||
import { CryptoCallbacks } from "../../../src/crypto-api";
|
||||
import { CryptoCallbacks, KeyBackupInfo } from "../../../src/crypto-api";
|
||||
import { E2EKeyResponder } from "../../test-utils/E2EKeyResponder";
|
||||
|
||||
afterEach(() => {
|
||||
@ -2197,11 +2202,9 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string,
|
||||
"express:/_matrix/client/v3/user/:userId/account_data/:type(m.secret_storage.*)",
|
||||
(url: string, options: RequestInit) => {
|
||||
const content = JSON.parse(options.body as string);
|
||||
|
||||
if (content.key) {
|
||||
resolve(content.key);
|
||||
}
|
||||
|
||||
return {};
|
||||
},
|
||||
{ overwriteRoutes: true },
|
||||
@ -2228,6 +2231,74 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string,
|
||||
});
|
||||
}
|
||||
|
||||
function awaitMegolmBackupKeyUpload(): Promise<Record<string, {}>> {
|
||||
return new Promise((resolve) => {
|
||||
// Called when the megolm backup key is uploaded
|
||||
fetchMock.put(
|
||||
`express:/_matrix/client/v3/user/:userId/account_data/m.megolm_backup.v1`,
|
||||
(url: string, options: RequestInit) => {
|
||||
const content = JSON.parse(options.body as string);
|
||||
resolve(content.encrypted);
|
||||
return {};
|
||||
},
|
||||
{ overwriteRoutes: true },
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all mocks needed to set up cross-signing, key backup, 4S and then
|
||||
* configure the account to have recovery.
|
||||
*
|
||||
* @param backupVersion - The version of the created backup
|
||||
*/
|
||||
async function bootstrapSecurity(backupVersion: string): Promise<void> {
|
||||
mockSetupCrossSigningRequests();
|
||||
mockSetupMegolmBackupRequests(backupVersion);
|
||||
|
||||
// promise which will resolve when a `KeyBackupStatus` event is emitted with `enabled: true`
|
||||
const backupStatusUpdate = new Promise<void>((resolve) => {
|
||||
aliceClient.on(CryptoEvent.KeyBackupStatus, (enabled) => {
|
||||
if (enabled) {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const setupPromises = [
|
||||
awaitCrossSigningKeyUpload("master"),
|
||||
awaitCrossSigningKeyUpload("user_signing"),
|
||||
awaitCrossSigningKeyUpload("self_signing"),
|
||||
awaitMegolmBackupKeyUpload(),
|
||||
];
|
||||
|
||||
// Before setting up secret-storage, bootstrap cross-signing, so that the client has cross-signing keys.
|
||||
await aliceClient.getCrypto()!.bootstrapCrossSigning({});
|
||||
|
||||
// Now, when we bootstrap secret-storage, the cross-signing keys should be uploaded.
|
||||
const bootstrapPromise = aliceClient.getCrypto()!.bootstrapSecretStorage({
|
||||
setupNewSecretStorage: true,
|
||||
createSecretStorageKey,
|
||||
setupNewKeyBackup: true,
|
||||
});
|
||||
|
||||
// Wait for the key to be uploaded in the account data
|
||||
const secretStorageKey = await awaitSecretStorageKeyStoredInAccountData();
|
||||
|
||||
// Return the newly created key in the sync response
|
||||
sendSyncResponse(secretStorageKey);
|
||||
|
||||
// Wait for the cross signing keys to be uploaded
|
||||
await Promise.all(setupPromises);
|
||||
|
||||
// wait for bootstrapSecretStorage to finished
|
||||
await bootstrapPromise;
|
||||
// Finally ensure backup is working
|
||||
await aliceClient.getCrypto()!.checkKeyBackupAndEnable();
|
||||
|
||||
await backupStatusUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send in the sync response the provided `secretStorageKey` into the account_data field
|
||||
* The key is set for the `m.secret_storage.default_key` and `m.secret_storage.key.${secretStorageKey}` events
|
||||
@ -2385,6 +2456,95 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string,
|
||||
expect(userSigningKey[secretStorageKey]).toBeDefined();
|
||||
expect(selfSigningKey[secretStorageKey]).toBeDefined();
|
||||
});
|
||||
|
||||
oldBackendOnly("should create a new megolm backup", async () => {
|
||||
const backupVersion = "abc";
|
||||
await bootstrapSecurity(backupVersion);
|
||||
|
||||
// Expect a backup to be available and used
|
||||
const activeBackup = await aliceClient.getCrypto()!.getActiveSessionBackupVersion();
|
||||
expect(activeBackup).toStrictEqual(backupVersion);
|
||||
});
|
||||
|
||||
oldBackendOnly("Reset key backup should create a new backup and update 4S", async () => {
|
||||
// First set up 4S and key backup
|
||||
const backupVersion = "1";
|
||||
await bootstrapSecurity(backupVersion);
|
||||
|
||||
const currentVersion = await aliceClient.getCrypto()!.getActiveSessionBackupVersion();
|
||||
const currentBackupKey = await aliceClient.getCrypto()!.getSessionBackupPrivateKey();
|
||||
|
||||
// we will call reset backup, it should delete the existing one, then setup a new one
|
||||
// Let's mock for that
|
||||
|
||||
// Mock delete and replace the GET to return 404 as soon as called
|
||||
const awaitDeleteCalled = new Promise<void>((resolve) => {
|
||||
fetchMock.delete(
|
||||
"express:/_matrix/client/v3/room_keys/version/:version",
|
||||
(url: string, options: RequestInit) => {
|
||||
fetchMock.get(
|
||||
"path:/_matrix/client/v3/room_keys/version",
|
||||
{
|
||||
status: 404,
|
||||
body: { errcode: "M_NOT_FOUND", error: "Account data not found." },
|
||||
},
|
||||
{ overwriteRoutes: true },
|
||||
);
|
||||
resolve();
|
||||
return {};
|
||||
},
|
||||
{ overwriteRoutes: true },
|
||||
);
|
||||
});
|
||||
|
||||
const newVersion = "2";
|
||||
fetchMock.post(
|
||||
"path:/_matrix/client/v3/room_keys/version",
|
||||
(url, request) => {
|
||||
const backupData: KeyBackupInfo = JSON.parse(request.body?.toString() ?? "{}");
|
||||
backupData.version = newVersion;
|
||||
backupData.count = 0;
|
||||
backupData.etag = "zer";
|
||||
|
||||
// update get call with new version
|
||||
fetchMock.get("path:/_matrix/client/v3/room_keys/version", backupData, {
|
||||
overwriteRoutes: true,
|
||||
});
|
||||
return {
|
||||
version: backupVersion,
|
||||
};
|
||||
},
|
||||
{ overwriteRoutes: true },
|
||||
);
|
||||
|
||||
const newBackupStatusUpdate = new Promise<void>((resolve) => {
|
||||
aliceClient.on(CryptoEvent.KeyBackupStatus, (enabled) => {
|
||||
if (enabled) {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const newBackupUploadPromise = awaitMegolmBackupKeyUpload();
|
||||
|
||||
await aliceClient.getCrypto()!.resetKeyBackup();
|
||||
await awaitDeleteCalled;
|
||||
await newBackupStatusUpdate;
|
||||
await newBackupUploadPromise;
|
||||
|
||||
const nextVersion = await aliceClient.getCrypto()!.getActiveSessionBackupVersion();
|
||||
const nextKey = await aliceClient.getCrypto()!.getSessionBackupPrivateKey();
|
||||
|
||||
expect(nextVersion).toBeDefined();
|
||||
expect(nextVersion).not.toEqual(currentVersion);
|
||||
expect(nextKey).not.toEqual(currentBackupKey);
|
||||
|
||||
// Test deletion of the backup
|
||||
await aliceClient.getCrypto()!.deleteKeyBackupVersion(nextVersion!);
|
||||
await aliceClient.getCrypto()!.checkKeyBackupAndEnable();
|
||||
// XXX Legacy crypto does not update 4S when deleting backup; should ensure that rust implem does it.
|
||||
expect(await aliceClient.getCrypto()!.getActiveSessionBackupVersion()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Incoming verification in a DM", () => {
|
||||
|
Reference in New Issue
Block a user