From 161e19dfb6535081bb49bd992b0a452615f9bd45 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Date: Tue, 23 May 2023 13:01:27 +0100 Subject: [PATCH] Settings panels: avoid exceptions with rust crypto (#10962) * Settings panels: avoid exceptions with rust crypto If we are using rust crypto, `client.crypto` is undefined. We'll need to fix these up better in future, but for now, just return early. * Update tests --- src/components/views/settings/CrossSigningPanel.tsx | 7 +++++-- src/components/views/settings/SecureBackupPanel.tsx | 9 ++++++--- .../components/views/settings/CrossSigningPanel-test.tsx | 4 ++-- .../components/views/settings/SecureBackupPanel-test.tsx | 8 ++++---- test/test-utils/client.ts | 6 +++--- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/components/views/settings/CrossSigningPanel.tsx b/src/components/views/settings/CrossSigningPanel.tsx index 68ec515b542..fdc54dee6ed 100644 --- a/src/components/views/settings/CrossSigningPanel.tsx +++ b/src/components/views/settings/CrossSigningPanel.tsx @@ -90,9 +90,12 @@ export default class CrossSigningPanel extends React.PureComponent<{}, IState> { private async getUpdatedStatus(): Promise { const cli = MatrixClientPeg.get(); + const crypto = cli.crypto; + if (!crypto) return; + const pkCache = cli.getCrossSigningCacheCallbacks(); - const crossSigning = cli.crypto!.crossSigningInfo; - const secretStorage = cli.crypto!.secretStorage; + const crossSigning = crypto.crossSigningInfo; + const secretStorage = cli.secretStorage; const crossSigningPublicKeysOnDevice = Boolean(crossSigning.getId()); const crossSigningPrivateKeysInStorage = Boolean(await crossSigning.isStoredInSecretStorage(secretStorage)); const masterPrivateKeyCached = !!(await pkCache?.getCrossSigningKeyCache?.("master")); diff --git a/src/components/views/settings/SecureBackupPanel.tsx b/src/components/views/settings/SecureBackupPanel.tsx index 874123be574..2f2ecb42f5f 100644 --- a/src/components/views/settings/SecureBackupPanel.tsx +++ b/src/components/views/settings/SecureBackupPanel.tsx @@ -146,14 +146,17 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> { private async getUpdatedDiagnostics(): Promise { const cli = MatrixClientPeg.get(); - const secretStorage = cli.crypto!.secretStorage; + const crypto = cli.crypto; + if (!crypto) return; + + const secretStorage = cli.secretStorage; const backupKeyStored = !!(await cli.isKeyBackupKeyStored()); - const backupKeyFromCache = await cli.crypto!.getSessionBackupPrivateKey(); + const backupKeyFromCache = await crypto.getSessionBackupPrivateKey(); const backupKeyCached = !!backupKeyFromCache; const backupKeyWellFormed = backupKeyFromCache instanceof Uint8Array; const secretStorageKeyInAccount = await secretStorage.hasKey(); - const secretStorageReady = await cli.isSecretStorageReady(); + const secretStorageReady = await crypto.isSecretStorageReady(); if (this.unmounted) return; this.setState({ diff --git a/test/components/views/settings/CrossSigningPanel-test.tsx b/test/components/views/settings/CrossSigningPanel-test.tsx index 7bfce16e1fc..a41c55c48a3 100644 --- a/test/components/views/settings/CrossSigningPanel-test.tsx +++ b/test/components/views/settings/CrossSigningPanel-test.tsx @@ -79,7 +79,7 @@ describe("", () => { expect(screen.getByTestId("summarised-status").innerHTML).toEqual("✅ Cross-signing is ready for use."); expect(screen.getByText("Cross-signing private keys:").parentElement!).toMatchSnapshot(); expect(mockClient.crypto!.crossSigningInfo.isStoredInSecretStorage).toHaveBeenCalledWith( - mockClient.crypto!.secretStorage, + mockClient.secretStorage, ); }); }); @@ -106,7 +106,7 @@ describe("", () => { ); expect(screen.getByText("Cross-signing private keys:").parentElement!).toMatchSnapshot(); expect(mockClient.crypto!.crossSigningInfo.isStoredInSecretStorage).toHaveBeenCalledWith( - mockClient.crypto!.secretStorage, + mockClient.secretStorage, ); }); }); diff --git a/test/components/views/settings/SecureBackupPanel-test.tsx b/test/components/views/settings/SecureBackupPanel-test.tsx index c8ad4790f1b..a59e76ff327 100644 --- a/test/components/views/settings/SecureBackupPanel-test.tsx +++ b/test/components/views/settings/SecureBackupPanel-test.tsx @@ -32,17 +32,17 @@ describe("", () => { ...mockClientMethodsUser(userId), checkKeyBackup: jest.fn(), isKeyBackupKeyStored: jest.fn(), - isSecretStorageReady: jest.fn(), getKeyBackupEnabled: jest.fn(), getKeyBackupVersion: jest.fn().mockReturnValue("1"), isKeyBackupTrusted: jest.fn().mockResolvedValue(true), getClientWellKnown: jest.fn(), deleteKeyBackupVersion: jest.fn(), + secretStorage: { hasKey: jest.fn() }, }); // @ts-ignore allow it client.crypto = { - secretStorage: { hasKey: jest.fn() }, getSessionBackupPrivateKey: jest.fn(), + isSecretStorageReady: jest.fn(), } as unknown as Crypto; const getComponent = () => render(); @@ -62,7 +62,7 @@ describe("", () => { }, }); - mocked(client.crypto!.secretStorage.hasKey).mockClear().mockResolvedValue(false); + mocked(client.secretStorage.hasKey).mockClear().mockResolvedValue(false); client.deleteKeyBackupVersion.mockClear().mockResolvedValue(); client.getKeyBackupVersion.mockClear(); client.isKeyBackupTrusted.mockClear(); @@ -166,7 +166,7 @@ describe("", () => { }); it("resets secret storage", async () => { - mocked(client.crypto!.secretStorage.hasKey).mockClear().mockResolvedValue(true); + mocked(client.secretStorage.hasKey).mockClear().mockResolvedValue(true); getComponent(); // flush checkKeyBackup promise await flushPromises(); diff --git a/test/test-utils/client.ts b/test/test-utils/client.ts index 996682b190d..52a636a2f63 100644 --- a/test/test-utils/client.ts +++ b/test/test-utils/client.ts @@ -66,7 +66,7 @@ export class MockClientWithEventEmitter extends EventEmitter { * ``` */ export const getMockClientWithEventEmitter = ( - mockProperties: Partial, unknown>>, + mockProperties: Partial>, ): MockedObject => { const mock = mocked(new MockClientWithEventEmitter(mockProperties) as unknown as MatrixClient); @@ -143,15 +143,15 @@ export const mockClientMethodsCrypto = (): Partial< Record & PropertyLikeKeys, unknown> > => ({ isCryptoEnabled: jest.fn(), - isSecretStorageReady: jest.fn(), isCrossSigningReady: jest.fn(), isKeyBackupKeyStored: jest.fn(), getCrossSigningCacheCallbacks: jest.fn().mockReturnValue({ getCrossSigningKeyCache: jest.fn() }), getStoredCrossSigningForUser: jest.fn(), checkKeyBackup: jest.fn().mockReturnValue({}), + secretStorage: { hasKey: jest.fn() }, crypto: { + isSecretStorageReady: jest.fn(), getSessionBackupPrivateKey: jest.fn(), - secretStorage: { hasKey: jest.fn() }, crossSigningInfo: { getId: jest.fn(), isStoredInSecretStorage: jest.fn(),