You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-07-31 15:24:23 +03:00
Save the key backup key to 4S during bootstrapCrossSigning
(#4542)
* Save the key backup key to secret storage When setting up secret storage, if we have a key backup key in cache (like we do for the cross signing secrets). * Add test * Get the key directly from the olmMachine saves converting it needlessly into a buffer to turn it back into a base64 string * Overwrite backup keyin storage if different * Fix test * Add integ test * Test failure case for sonar * Unused import * Missed return * Also check active backup version
This commit is contained in:
@ -3121,6 +3121,32 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string,
|
||||
const mskId = await aliceClient.getCrypto()!.getCrossSigningKeyId(CrossSigningKey.Master)!;
|
||||
expect(signatures![aliceClient.getUserId()!][`ed25519:${mskId}`]).toBeDefined();
|
||||
});
|
||||
|
||||
newBackendOnly("should upload existing megolm backup key to a new 4S store", async () => {
|
||||
const backupKeyTo4SPromise = awaitMegolmBackupKeyUpload();
|
||||
|
||||
// we need these to set up the mocks but we don't actually care whether they
|
||||
// resolve because we're not testing those things in this test.
|
||||
awaitCrossSigningKeyUpload("master");
|
||||
awaitCrossSigningKeyUpload("user_signing");
|
||||
awaitCrossSigningKeyUpload("self_signing");
|
||||
awaitSecretStorageKeyStoredInAccountData();
|
||||
|
||||
mockSetupCrossSigningRequests();
|
||||
mockSetupMegolmBackupRequests("1");
|
||||
|
||||
await aliceClient.getCrypto()!.bootstrapCrossSigning({});
|
||||
await aliceClient.getCrypto()!.resetKeyBackup();
|
||||
|
||||
await aliceClient.getCrypto()!.bootstrapSecretStorage({
|
||||
setupNewSecretStorage: true,
|
||||
createSecretStorageKey,
|
||||
setupNewKeyBackup: false,
|
||||
});
|
||||
|
||||
await backupKeyTo4SPromise;
|
||||
expect(accountDataAccumulator.accountDataEvents.get("m.megolm_backup.v1")).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Manage Key Backup", () => {
|
||||
|
@ -727,6 +727,119 @@ describe("RustCrypto", () => {
|
||||
expect(resetKeyBackup.mock.calls).toHaveLength(2);
|
||||
});
|
||||
|
||||
describe("upload existing key backup key to new 4S store", () => {
|
||||
const secretStorageCallbacks = {
|
||||
getSecretStorageKey: async (keys: any, name: string) => {
|
||||
return [[...Object.keys(keys.keys)][0], new Uint8Array(32)];
|
||||
},
|
||||
} as SecretStorageCallbacks;
|
||||
let secretStorage: ServerSideSecretStorageImpl;
|
||||
|
||||
let backupAuthData: any;
|
||||
let backupAlg: string;
|
||||
|
||||
const fetchMock = {
|
||||
authedRequest: jest.fn().mockImplementation((method, path, query, body) => {
|
||||
if (path === "/room_keys/version") {
|
||||
if (method === "POST") {
|
||||
backupAuthData = body["auth_data"];
|
||||
backupAlg = body["algorithm"];
|
||||
return Promise.resolve({ version: "1", algorithm: backupAlg, auth_data: backupAuthData });
|
||||
} else if (method === "GET" && backupAuthData) {
|
||||
return Promise.resolve({ version: "1", algorithm: backupAlg, auth_data: backupAuthData });
|
||||
}
|
||||
}
|
||||
return Promise.resolve({});
|
||||
}),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
backupAuthData = undefined;
|
||||
backupAlg = "";
|
||||
|
||||
secretStorage = new ServerSideSecretStorageImpl(new DummyAccountDataClient(), secretStorageCallbacks);
|
||||
});
|
||||
|
||||
it("bootstrapSecretStorage saves megolm backup key if already cached", async () => {
|
||||
const rustCrypto = await makeTestRustCrypto(
|
||||
fetchMock as unknown as MatrixHttpApi<any>,
|
||||
testData.TEST_USER_ID,
|
||||
undefined,
|
||||
secretStorage,
|
||||
);
|
||||
|
||||
async function createSecretStorageKey() {
|
||||
return {
|
||||
keyInfo: {} as AddSecretStorageKeyOpts,
|
||||
privateKey: new Uint8Array(32),
|
||||
};
|
||||
}
|
||||
|
||||
await rustCrypto.resetKeyBackup();
|
||||
|
||||
const storeSpy = jest.spyOn(secretStorage, "store");
|
||||
|
||||
await rustCrypto.bootstrapSecretStorage({
|
||||
createSecretStorageKey,
|
||||
setupNewSecretStorage: true,
|
||||
setupNewKeyBackup: false,
|
||||
});
|
||||
|
||||
expect(storeSpy).toHaveBeenCalledWith("m.megolm_backup.v1", expect.anything());
|
||||
});
|
||||
|
||||
it("bootstrapSecretStorage doesn't try to save megolm backup key not in cache", async () => {
|
||||
const mockOlmMachine = {
|
||||
isBackupEnabled: jest.fn().mockResolvedValue(false),
|
||||
sign: jest.fn().mockResolvedValue({
|
||||
asJSON: jest.fn().mockReturnValue("{}"),
|
||||
}),
|
||||
saveBackupDecryptionKey: jest.fn(),
|
||||
crossSigningStatus: jest.fn().mockResolvedValue({
|
||||
hasMaster: true,
|
||||
hasSelfSigning: true,
|
||||
hasUserSigning: true,
|
||||
}),
|
||||
exportCrossSigningKeys: jest.fn().mockResolvedValue({
|
||||
masterKey: "sosecret",
|
||||
userSigningKey: "secrets",
|
||||
self_signing_key: "ssshhh",
|
||||
}),
|
||||
getBackupKeys: jest.fn().mockResolvedValue({}),
|
||||
verifyBackup: jest.fn().mockResolvedValue({ trusted: jest.fn().mockReturnValue(false) }),
|
||||
} as unknown as OlmMachine;
|
||||
|
||||
const rustCrypto = new RustCrypto(
|
||||
logger,
|
||||
mockOlmMachine,
|
||||
fetchMock as unknown as MatrixHttpApi<any>,
|
||||
TEST_USER,
|
||||
TEST_DEVICE_ID,
|
||||
secretStorage,
|
||||
{} as CryptoCallbacks,
|
||||
);
|
||||
|
||||
async function createSecretStorageKey() {
|
||||
return {
|
||||
keyInfo: {} as AddSecretStorageKeyOpts,
|
||||
privateKey: new Uint8Array(32),
|
||||
};
|
||||
}
|
||||
|
||||
await rustCrypto.resetKeyBackup();
|
||||
|
||||
const storeSpy = jest.spyOn(secretStorage, "store");
|
||||
|
||||
await rustCrypto.bootstrapSecretStorage({
|
||||
createSecretStorageKey,
|
||||
setupNewSecretStorage: true,
|
||||
setupNewKeyBackup: false,
|
||||
});
|
||||
|
||||
expect(storeSpy).not.toHaveBeenCalledWith("m.megolm_backup.v1", expect.anything());
|
||||
});
|
||||
});
|
||||
|
||||
it("isSecretStorageReady", async () => {
|
||||
const mockSecretStorage = {
|
||||
getDefaultKeyId: jest.fn().mockResolvedValue(null),
|
||||
|
Reference in New Issue
Block a user