diff --git a/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx b/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx index 7c6e2a10e1f..c9414b28b5d 100644 --- a/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx +++ b/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx @@ -11,7 +11,7 @@ import React, { createRef } from "react"; import FileSaver from "file-saver"; import { logger } from "matrix-js-sdk/src/logger"; import { AuthDict, CrossSigningKeys, MatrixError, UIAFlow, UIAResponse } from "matrix-js-sdk/src/matrix"; -import { GeneratedSecretStorageKey, KeyBackupInfo } from "matrix-js-sdk/src/crypto-api"; +import { GeneratedSecretStorageKey } from "matrix-js-sdk/src/crypto-api"; import classNames from "classnames"; import CheckmarkIcon from "@vector-im/compound-design-tokens/assets/web/icons/check"; @@ -70,16 +70,6 @@ interface IState { downloaded: boolean; setPassphrase: boolean; - /** Information on the current key backup version, as returned by the server. - * - * `null` could mean any of: - * * we haven't yet requested the data from the server. - * * we were unable to reach the server. - * * the server returned key backup version data we didn't understand or was malformed. - * * there is actually no backup on the server. - */ - backupInfo: KeyBackupInfo | null; - // does the server offer a UI auth flow with just m.login.password // for /keys/device_signing/upload? canUploadKeysWithPasswordOnly: boolean | null; @@ -131,15 +121,17 @@ export default class CreateSecretStorageDialog extends React.PureComponent { - try { - const cli = MatrixClientPeg.safeGet(); - const backupInfo = await cli.getKeyBackupVersion(); - this.setState({ - phase: Phase.ChooseKeyPassphrase, - backupInfo, - }); - } catch (e) { - console.error("Error fetching backup data from server", e); - this.setState({ phase: Phase.LoadError }); - } + private initExtension(keyFromCustomisations: Uint8Array): void { + logger.log("CryptoSetupExtension: Created key via extension, jumping to bootstrap step"); + this.recoveryKey = { + privateKey: keyFromCustomisations, + }; + this.bootstrapSecretStorage(); } private async queryKeyUploadAuth(): Promise { @@ -296,16 +263,28 @@ export default class CreateSecretStorageDialog extends React.PureComponent => { + const cli = MatrixClientPeg.safeGet(); + const crypto = cli.getCrypto()!; + const { forceReset } = this.props; + + let backupInfo; + // First, we try to get the keybackup info + if (!forceReset) { + try { + this.setState({ phase: Phase.Loading }); + backupInfo = await cli.getKeyBackupVersion(); + } catch (e) { + logger.error("Error fetching backup data from server", e); + this.setState({ phase: Phase.LoadError }); + return; + } + } + this.setState({ phase: Phase.Storing, error: undefined, }); - const cli = MatrixClientPeg.safeGet(); - const crypto = cli.getCrypto()!; - - const { forceReset } = this.props; - try { if (forceReset) { logger.log("Forcing secret storage reset"); @@ -327,7 +306,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent this.recoveryKey!, - setupNewKeyBackup: !this.state.backupInfo, + setupNewKeyBackup: !backupInfo, }); } await initialiseDehydration(true); @@ -346,8 +325,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent { - this.setState({ phase: Phase.Loading }); - this.fetchBackupInfo(); + this.bootstrapSecretStorage(); }; private onShowKeyContinueClick = (): void => { 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 c652fc1dfef..b9d05141481 100644 --- a/test/unit-tests/components/views/dialogs/security/CreateSecretStorageDialog-test.tsx +++ b/test/unit-tests/components/views/dialogs/security/CreateSecretStorageDialog-test.tsx @@ -12,9 +12,8 @@ import React from "react"; import { mocked, MockedObject } from "jest-mock"; import { MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix"; import { sleep } from "matrix-js-sdk/src/utils"; -import { waitFor } from "@testing-library/dom"; -import { filterConsole, flushPromises, stubClient } from "../../../../../test-utils"; +import { filterConsole, stubClient } from "../../../../../test-utils"; import CreateSecretStorageDialog from "../../../../../../src/async-components/views/dialogs/security/CreateSecretStorageDialog"; describe("CreateSecretStorageDialog", () => { @@ -41,13 +40,6 @@ describe("CreateSecretStorageDialog", () => { return render(); } - it("shows a loading spinner initially", async () => { - const { container } = renderComponent(); - expect(screen.getByTestId("spinner")).toBeDefined(); - expect(container).toMatchSnapshot(); - await flushPromises(); - }); - it("handles the happy path", async () => { const result = renderComponent(); await result.findByText( @@ -81,13 +73,6 @@ describe("CreateSecretStorageDialog", () => { await screen.findByText("Unable to set up secret storage"); }); - it("when there is an error fetching the backup version handles the error sensibly", async () => { - mockClient.getKeyBackupVersion.mockRejectedValue(new Error("error")); - renderComponent(); - - await waitFor(() => expect(screen.queryByText("Unable to query secret storage status")).not.toBeNull()); - }); - describe("when there is an error fetching the backup version", () => { filterConsole("Error fetching backup data from server"); @@ -97,9 +82,19 @@ describe("CreateSecretStorageDialog", () => { }); const result = renderComponent(); + // We go though the dialog until we have to get the key backup + await userEvent.click(result.getByRole("button", { name: "Continue" })); + await userEvent.click(screen.getByRole("button", { name: "Copy" })); + await userEvent.click(screen.getByRole("button", { name: "Continue" })); + // XXX the error message is... misleading. await screen.findByText("Unable to query secret storage status"); expect(result.container).toMatchSnapshot(); + + // Now we can get the backup and we retry + mockClient.getKeyBackupVersion.mockRestore(); + await userEvent.click(screen.getByRole("button", { name: "Retry" })); + await screen.findByText("Your keys are now being backed up from this device."); }); }); });