David Baker 980b922348
Enable key backup by default (#28691)
* Factor out crypto setup process into a store

To make components pure and avoid react 18 dev mode problems due
to components making requests when mounted.

* fix test

* test for the store

* Add comment

* Enable key backup by default

When we set up cross signing, so the key backup key will be stored locally along with the cross signing keys until the user sets up recovery (4s). This will mean that a user can restore their backup if they log in on a new device as long as they verify with the one they registered on.

Replaces https://github.com/element-hq/element-web/pull/28267

* Fix test

* Prompt user to set up 4S on logout

* Fix test

* Add playwright test for key backup by default

* Fix imports

* This isn't unexpected anymore

* Update doc

* Fix docs and function name on renderSetupBackupDialog()

* Use checkKeyBackupAndEnable

* Docs for setup encryption toast

* Also test the toast appears

* Update mock for the method we use now

* Okay fine I guess we need both

* Swap here too

* Fix comment & doc comments
2024-12-17 14:50:48 +00:00

87 lines
3.6 KiB
TypeScript

/*
Copyright 2024 New Vector Ltd.
Copyright 2023 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import React from "react";
import { mocked, MockedObject } from "jest-mock";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { CryptoApi, KeyBackupInfo } from "matrix-js-sdk/src/crypto-api";
import { fireEvent, render, RenderResult, screen } from "jest-matrix-react";
import { filterConsole, getMockClientWithEventEmitter, mockClientMethodsCrypto } from "../../../../test-utils";
import LogoutDialog from "../../../../../src/components/views/dialogs/LogoutDialog";
describe("LogoutDialog", () => {
let mockClient: MockedObject<MatrixClient>;
let mockCrypto: MockedObject<CryptoApi>;
beforeEach(() => {
mockClient = getMockClientWithEventEmitter({
...mockClientMethodsCrypto(),
});
mockCrypto = mocked(mockClient.getCrypto()!);
Object.assign(mockCrypto, {
getActiveSessionBackupVersion: jest.fn().mockResolvedValue(null),
});
});
function renderComponent(props: Partial<React.ComponentProps<typeof LogoutDialog>> = {}): RenderResult {
const onFinished = jest.fn();
return render(<LogoutDialog onFinished={onFinished} {...props} />);
}
it("shows a regular dialog when crypto is disabled", async () => {
mocked(mockClient.getCrypto).mockReturnValue(undefined);
const rendered = renderComponent();
await rendered.findByText("Are you sure you want to sign out?");
expect(rendered.container).toMatchSnapshot();
});
it("shows a regular dialog if backups and recovery are working", async () => {
mockCrypto.getActiveSessionBackupVersion.mockResolvedValue("1");
mockCrypto.isSecretStorageReady.mockResolvedValue(true);
const rendered = renderComponent();
await rendered.findByText("Are you sure you want to sign out?");
});
it("prompts user to set up recovery if backups are enabled but recovery isn't", async () => {
mockCrypto.getActiveSessionBackupVersion.mockResolvedValue("1");
mockCrypto.isSecretStorageReady.mockResolvedValue(false);
const rendered = renderComponent();
await rendered.findByText("You'll lose access to your encrypted messages");
});
it("Prompts user to connect backup if there is a backup on the server", async () => {
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 () => {
mockCrypto.getKeyBackupInfo.mockResolvedValue(null);
const rendered = renderComponent();
await rendered.findByText("Start using Key Backup");
expect(rendered.container).toMatchSnapshot();
fireEvent.click(await screen.findByRole("button", { name: "Manually export keys" }));
await expect(screen.findByRole("heading", { name: "Export room keys" })).resolves.toBeInTheDocument();
});
describe("when there is an error fetching backups", () => {
filterConsole("Unable to fetch key backup status");
it("prompts user to set up backup", async () => {
mockCrypto.getKeyBackupInfo.mockImplementation(async () => {
throw new Error("beep");
});
const rendered = renderComponent();
await rendered.findByText("Start using Key Backup");
});
});
});