diff --git a/src/DeviceListener.ts b/src/DeviceListener.ts index 02e26729d26..a03ba64e21d 100644 --- a/src/DeviceListener.ts +++ b/src/DeviceListener.ts @@ -229,12 +229,14 @@ export default class DeviceListener { private async getKeyBackupInfo(): Promise { if (!this.client) return null; const now = new Date().getTime(); + const crypto = this.client.getCrypto(); if ( - !this.keyBackupInfo || - !this.keyBackupFetchedAt || - this.keyBackupFetchedAt < now - KEY_BACKUP_POLL_INTERVAL + crypto && + (!this.keyBackupInfo || + !this.keyBackupFetchedAt || + this.keyBackupFetchedAt < now - KEY_BACKUP_POLL_INTERVAL) ) { - this.keyBackupInfo = await this.client.getKeyBackupVersion(); + this.keyBackupInfo = await crypto.getKeyBackupInfo(); this.keyBackupFetchedAt = now; } return this.keyBackupInfo; diff --git a/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx b/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx index 1e87b5b8260..13ec7fcc915 100644 --- a/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx +++ b/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx @@ -277,7 +277,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent { } else { // otherwise check the server to see if there's a new one try { - newVersionInfo = await cli.getKeyBackupVersion(); + newVersionInfo = (await cli.getCrypto()?.getKeyBackupInfo()) || null; if (newVersionInfo !== null) haveNewVersion = true; } catch (e) { logger.error("Saw key backup error but failed to check backup version!", e); diff --git a/src/components/views/dialogs/LogoutDialog.tsx b/src/components/views/dialogs/LogoutDialog.tsx index 51dc664fb4d..a3f13cf3577 100644 --- a/src/components/views/dialogs/LogoutDialog.tsx +++ b/src/components/views/dialogs/LogoutDialog.tsx @@ -111,7 +111,7 @@ export default class LogoutDialog extends React.Component { } // backup is not active. see if there is a backup version on the server we ought to back up to. - const backupInfo = await client.getKeyBackupVersion(); + const backupInfo = await crypto.getKeyBackupInfo(); this.setState({ backupStatus: backupInfo ? BackupStatus.SERVER_BACKUP_BUT_DISABLED : BackupStatus.NO_BACKUP }); } diff --git a/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx b/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx index 4d29c1cfa34..c3e26167b3b 100644 --- a/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx +++ b/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx @@ -265,7 +265,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent { this.getUpdatedDiagnostics(); try { const cli = MatrixClientPeg.safeGet(); - const backupInfo = await cli.getKeyBackupVersion(); + const backupInfo = (await cli.getCrypto()?.getKeyBackupInfo()) || null; const backupTrustInfo = backupInfo ? await cli.getCrypto()?.isKeyBackupTrusted(backupInfo) : undefined; const activeBackupVersion = (await cli.getCrypto()?.getActiveSessionBackupVersion()) ?? null; diff --git a/src/stores/SetupEncryptionStore.ts b/src/stores/SetupEncryptionStore.ts index 6b67bcfc492..d69237be402 100644 --- a/src/stores/SetupEncryptionStore.ts +++ b/src/stores/SetupEncryptionStore.ts @@ -128,7 +128,7 @@ export class SetupEncryptionStore extends EventEmitter { this.emit("update"); try { const cli = MatrixClientPeg.safeGet(); - const backupInfo = await cli.getKeyBackupVersion(); + const backupInfo = (await cli.getCrypto()?.getKeyBackupInfo()) || null; this.backupInfo = backupInfo; this.emit("update"); diff --git a/test/test-utils/client.ts b/test/test-utils/client.ts index 0a5798d8a1a..cdda0e982a2 100644 --- a/test/test-utils/client.ts +++ b/test/test-utils/client.ts @@ -143,7 +143,6 @@ export const mockClientMethodsCrypto = (): Partial< > => ({ isKeyBackupKeyStored: jest.fn(), getCrossSigningCacheCallbacks: jest.fn().mockReturnValue({ getCrossSigningKeyCache: jest.fn() }), - getKeyBackupVersion: jest.fn().mockResolvedValue(null), secretStorage: { hasKey: jest.fn() }, getCrypto: jest.fn().mockReturnValue({ getUserDeviceInfo: jest.fn(), @@ -162,6 +161,7 @@ export const mockClientMethodsCrypto = (): Partial< getVersion: jest.fn().mockReturnValue("Version 0"), getOwnDeviceKeys: jest.fn().mockReturnValue(new Promise(() => {})), getCrossSigningKeyId: jest.fn(), + getKeyBackupInfo: jest.fn().mockResolvedValue(null), }), }); diff --git a/test/test-utils/test-utils.ts b/test/test-utils/test-utils.ts index 0e608b14266..7f5921f2763 100644 --- a/test/test-utils/test-utils.ts +++ b/test/test-utils/test-utils.ts @@ -99,7 +99,6 @@ export function createTestClient(): MatrixClient { getDevices: jest.fn().mockResolvedValue({ devices: [{ device_id: "ABCDEFGHI" }] }), getSessionId: jest.fn().mockReturnValue("iaszphgvfku"), credentials: { userId: "@userId:matrix.org" }, - getKeyBackupVersion: jest.fn(), secretStorage: { get: jest.fn(), @@ -131,6 +130,7 @@ export function createTestClient(): MatrixClient { createRecoveryKeyFromPassphrase: jest.fn().mockResolvedValue({}), bootstrapSecretStorage: jest.fn(), isDehydrationSupported: jest.fn().mockResolvedValue(false), + getKeyBackupInfo: jest.fn().mockResolvedValue(null), }), getPushActionsForEvent: jest.fn(), diff --git a/test/unit-tests/DeviceListener-test.ts b/test/unit-tests/DeviceListener-test.ts index 0862c6b385c..0289e447d38 100644 --- a/test/unit-tests/DeviceListener-test.ts +++ b/test/unit-tests/DeviceListener-test.ts @@ -95,12 +95,12 @@ describe("DeviceListener", () => { }, }), getSessionBackupPrivateKey: jest.fn(), + getKeyBackupInfo: jest.fn().mockResolvedValue(null), } as unknown as Mocked; mockClient = getMockClientWithEventEmitter({ isGuest: jest.fn(), getUserId: jest.fn().mockReturnValue(userId), getSafeUserId: jest.fn().mockReturnValue(userId), - getKeyBackupVersion: jest.fn().mockResolvedValue(undefined), getRooms: jest.fn().mockReturnValue([]), isVersionSupported: jest.fn().mockResolvedValue(true), isInitialSyncComplete: jest.fn().mockReturnValue(true), @@ -354,7 +354,7 @@ describe("DeviceListener", () => { it("shows set up encryption toast when user has a key backup available", async () => { // non falsy response - mockClient!.getKeyBackupVersion.mockResolvedValue({} as unknown as KeyBackupInfo); + mockCrypto.getKeyBackupInfo.mockResolvedValue({} as unknown as KeyBackupInfo); await createAndStart(); expect(SetupEncryptionToast.showToast).toHaveBeenCalledWith( @@ -673,7 +673,7 @@ describe("DeviceListener", () => { describe("When Room Key Backup is not enabled", () => { beforeEach(() => { // no backup - mockClient.getKeyBackupVersion.mockResolvedValue(null); + mockCrypto.getKeyBackupInfo.mockResolvedValue(null); }); it("Should report recovery state as Enabled", async () => { @@ -722,7 +722,7 @@ describe("DeviceListener", () => { }); // no backup - mockClient.getKeyBackupVersion.mockResolvedValue(null); + mockCrypto.getKeyBackupInfo.mockResolvedValue(null); await createAndStart(); @@ -872,7 +872,7 @@ describe("DeviceListener", () => { describe("When Room Key Backup is enabled", () => { beforeEach(() => { // backup enabled - just need a mock object - mockClient.getKeyBackupVersion.mockResolvedValue({} as KeyBackupInfo); + mockCrypto.getKeyBackupInfo.mockResolvedValue({} as KeyBackupInfo); }); const testCases = [ diff --git a/test/unit-tests/components/views/dialogs/LogoutDialog-test.tsx b/test/unit-tests/components/views/dialogs/LogoutDialog-test.tsx index 03db42fba7d..57a8b5ec8b5 100644 --- a/test/unit-tests/components/views/dialogs/LogoutDialog-test.tsx +++ b/test/unit-tests/components/views/dialogs/LogoutDialog-test.tsx @@ -22,7 +22,6 @@ describe("LogoutDialog", () => { beforeEach(() => { mockClient = getMockClientWithEventEmitter({ ...mockClientMethodsCrypto(), - getKeyBackupVersion: jest.fn(), }); mockCrypto = mocked(mockClient.getCrypto()!); @@ -50,14 +49,14 @@ describe("LogoutDialog", () => { }); it("Prompts user to connect backup if there is a backup on the server", async () => { - mockClient.getKeyBackupVersion.mockResolvedValue({} as KeyBackupInfo); + mockCrypto.getKeyBackupInfo.mockResolvedValue({} as KeyBackupInfo); const rendered = renderComponent(); await rendered.findByText("Connect this session to Key Backup"); expect(rendered.container).toMatchSnapshot(); }); it("Prompts user to set up backup if there is no backup on the server", async () => { - mockClient.getKeyBackupVersion.mockResolvedValue(null); + mockCrypto.getKeyBackupInfo.mockResolvedValue(null); const rendered = renderComponent(); await rendered.findByText("Start using Key Backup"); expect(rendered.container).toMatchSnapshot(); @@ -66,7 +65,7 @@ describe("LogoutDialog", () => { describe("when there is an error fetching backups", () => { filterConsole("Unable to fetch key backup status"); it("prompts user to set up backup", async () => { - mockClient.getKeyBackupVersion.mockImplementation(async () => { + mockCrypto.getKeyBackupInfo.mockImplementation(async () => { throw new Error("beep"); }); const rendered = renderComponent(); diff --git a/test/unit-tests/components/views/dialogs/security/CreateSecretStorageDialog-test.tsx b/test/unit-tests/components/views/dialogs/security/CreateSecretStorageDialog-test.tsx index b9d05141481..0e86dd73f39 100644 --- a/test/unit-tests/components/views/dialogs/security/CreateSecretStorageDialog-test.tsx +++ b/test/unit-tests/components/views/dialogs/security/CreateSecretStorageDialog-test.tsx @@ -77,7 +77,7 @@ describe("CreateSecretStorageDialog", () => { filterConsole("Error fetching backup data from server"); it("shows an error", async () => { - mockClient.getKeyBackupVersion.mockImplementation(async () => { + jest.spyOn(mockClient.getCrypto()!, "getKeyBackupInfo").mockImplementation(async () => { throw new Error("bleh bleh"); }); @@ -92,7 +92,7 @@ describe("CreateSecretStorageDialog", () => { expect(result.container).toMatchSnapshot(); // Now we can get the backup and we retry - mockClient.getKeyBackupVersion.mockRestore(); + jest.spyOn(mockClient.getCrypto()!, "getKeyBackupInfo").mockRestore(); await userEvent.click(screen.getByRole("button", { name: "Retry" })); await screen.findByText("Your keys are now being backed up from this device."); }); diff --git a/test/unit-tests/components/views/settings/SecureBackupPanel-test.tsx b/test/unit-tests/components/views/settings/SecureBackupPanel-test.tsx index f2aa15f3556..63490bf9150 100644 --- a/test/unit-tests/components/views/settings/SecureBackupPanel-test.tsx +++ b/test/unit-tests/components/views/settings/SecureBackupPanel-test.tsx @@ -28,14 +28,13 @@ describe("", () => { const client = getMockClientWithEventEmitter({ ...mockClientMethodsUser(userId), ...mockClientMethodsCrypto(), - getKeyBackupVersion: jest.fn().mockReturnValue("1"), getClientWellKnown: jest.fn(), }); const getComponent = () => render(); beforeEach(() => { - client.getKeyBackupVersion.mockResolvedValue({ + jest.spyOn(client.getCrypto()!, "getKeyBackupInfo").mockResolvedValue({ version: "1", algorithm: "test", auth_data: { @@ -52,7 +51,6 @@ describe("", () => { }); mocked(client.secretStorage.hasKey).mockClear().mockResolvedValue(false); - client.getKeyBackupVersion.mockClear(); mocked(accessSecretStorage).mockClear().mockResolvedValue(); }); @@ -65,8 +63,8 @@ describe("", () => { }); it("handles error fetching backup", async () => { - // getKeyBackupVersion can fail for various reasons - client.getKeyBackupVersion.mockImplementation(async () => { + // getKeyBackupInfo can fail for various reasons + jest.spyOn(client.getCrypto()!, "getKeyBackupInfo").mockImplementation(async () => { throw new Error("beep beep"); }); const renderResult = getComponent(); @@ -75,9 +73,9 @@ describe("", () => { }); it("handles absence of backup", async () => { - client.getKeyBackupVersion.mockResolvedValue(null); + jest.spyOn(client.getCrypto()!, "getKeyBackupInfo").mockResolvedValue(null); getComponent(); - // flush getKeyBackupVersion promise + // flush getKeyBackupInfo promise await flushPromises(); expect(screen.getByText("Back up your keys before signing out to avoid losing them.")).toBeInTheDocument(); }); @@ -120,7 +118,7 @@ describe("", () => { }); it("deletes backup after confirmation", async () => { - client.getKeyBackupVersion + jest.spyOn(client.getCrypto()!, "getKeyBackupInfo") .mockResolvedValueOnce({ version: "1", algorithm: "test", @@ -157,7 +155,7 @@ describe("", () => { // flush checkKeyBackup promise await flushPromises(); - client.getKeyBackupVersion.mockClear(); + jest.spyOn(client.getCrypto()!, "getKeyBackupInfo").mockClear(); mocked(client.getCrypto()!).isKeyBackupTrusted.mockClear(); fireEvent.click(screen.getByText("Reset")); @@ -167,7 +165,7 @@ describe("", () => { await flushPromises(); // backup status refreshed - expect(client.getKeyBackupVersion).toHaveBeenCalled(); + expect(client.getCrypto()!.getKeyBackupInfo).toHaveBeenCalled(); expect(client.getCrypto()!.isKeyBackupTrusted).toHaveBeenCalled(); }); }); diff --git a/test/unit-tests/components/views/settings/tabs/user/SecurityUserSettingsTab-test.tsx b/test/unit-tests/components/views/settings/tabs/user/SecurityUserSettingsTab-test.tsx index 0ee882767bb..27403919b6c 100644 --- a/test/unit-tests/components/views/settings/tabs/user/SecurityUserSettingsTab-test.tsx +++ b/test/unit-tests/components/views/settings/tabs/user/SecurityUserSettingsTab-test.tsx @@ -34,7 +34,6 @@ describe("", () => { ...mockClientMethodsCrypto(), getRooms: jest.fn().mockReturnValue([]), getIgnoredUsers: jest.fn(), - getKeyBackupVersion: jest.fn(), }); const sdkContext = new SdkContextClass();