diff --git a/spec/integ/crypto/megolm-backup.spec.ts b/spec/integ/crypto/megolm-backup.spec.ts index adc04678d75..05b5ff27b60 100644 --- a/spec/integ/crypto/megolm-backup.spec.ts +++ b/spec/integ/crypto/megolm-backup.spec.ts @@ -22,7 +22,6 @@ import { Mocked } from "jest-mock"; import { createClient, Crypto, - CryptoEvent, encodeBase64, ICreateClientOpts, IEvent, @@ -45,7 +44,7 @@ import * as testData from "../../test-utils/test-data"; import { KeyBackupInfo, KeyBackupSession } from "../../../src/crypto-api/keybackup"; import { flushPromises } from "../../test-utils/flushPromises"; import { defer, IDeferred } from "../../../src/utils"; -import { decodeRecoveryKey, DecryptionFailureCode } from "../../../src/crypto-api"; +import { decodeRecoveryKey, DecryptionFailureCode, CryptoEvent } from "../../../src/crypto-api"; import { KeyBackup } from "../../../src/rust-crypto/backup.ts"; const ROOM_ID = testData.TEST_ROOM_ID; @@ -969,6 +968,40 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("megolm-keys backup (%s)", (backe expect(backupStatus).toStrictEqual(testData.SIGNED_BACKUP_DATA.version); }); + newBackendOnly("getKeyBackupInfo() should not return a backup if the active backup has been deleted", async () => { + // 404 means that there is no active backup + fetchMock.get("express:/_matrix/client/v3/room_keys/version", 404); + fetchMock.delete(`express:/_matrix/client/v3/room_keys/version/${testData.SIGNED_BACKUP_DATA.version}`, {}); + + aliceClient = await initTestClient(); + const aliceCrypto = aliceClient.getCrypto()!; + await aliceClient.startClient(); + + // tell Alice to trust the dummy device that signed the backup + await waitForDeviceList(); + await aliceCrypto.setDeviceVerified(testData.TEST_USER_ID, testData.TEST_DEVICE_ID); + await aliceCrypto.checkKeyBackupAndEnable(); + + // At this point there is no backup + expect(await aliceCrypto.getKeyBackupInfo()).toBeNull(); + + // Return now the backup + fetchMock.get("express:/_matrix/client/v3/room_keys/version", testData.SIGNED_BACKUP_DATA, { + overwriteRoutes: true, + }); + + expect(await aliceCrypto.getKeyBackupInfo()).toStrictEqual(testData.SIGNED_BACKUP_DATA); + + // Delete the backup and we are expecting the key backup to be disabled + const keyBackupStatus = defer(); + aliceClient.once(CryptoEvent.KeyBackupStatus, (enabled) => keyBackupStatus.resolve(enabled)); + await aliceCrypto.deleteKeyBackupVersion(testData.SIGNED_BACKUP_DATA.version!); + expect(await keyBackupStatus.promise).toBe(false); + + // The backup info should not be available anymore + expect(await aliceCrypto.getKeyBackupInfo()).toBeNull(); + }); + describe("isKeyBackupTrusted", () => { it("does not trust a backup signed by an untrusted device", async () => { aliceClient = await initTestClient(); diff --git a/src/rust-crypto/backup.ts b/src/rust-crypto/backup.ts index 18a3f7c679d..886277cbbc6 100644 --- a/src/rust-crypto/backup.ts +++ b/src/rust-crypto/backup.ts @@ -583,6 +583,11 @@ export class RustBackupManager extends TypedEventEmitter(Method.Delete, path, undefined, undefined, { prefix: ClientPrefix.V3, }); + // If the backup we are deleting is the active one, we need to disable the key backup and to have the local properties reset + if (this.activeBackupVersion === version) { + await this.disableKeyBackup(); + this.serverBackupInfo = null; + } } /**