Remove Secure Backup, Cross-signing and Cryptography sections in Security & Privacy user settings (#29088)
* feat(security tab)!: remove secure backup panel BREAKING CHANGE: the key storage user interaction are moved into the Encryption tab. The debugging information are moved into the devtools. * feat(security tab)!: remove cross signing section BREAKING CHANGE: the cryptographic identity can be reseted in the Encryption tab. The debugging information are moved into the devtools * feat(security tab)!: remove cryptography section BREAKING CHANGE: this section can be found in the Advanced section of the encryption tab. * test(security tab): update snapshot * chore(security tab): remove unused component and function * chore(security tab): update i18n * test(e2e): remove `backups.spec.ts`
This commit is contained in:
@@ -1,133 +0,0 @@
|
||||
/*
|
||||
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 OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { render, screen } from "jest-matrix-react";
|
||||
import { type Mocked, mocked } from "jest-mock";
|
||||
import { type MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import CrossSigningPanel from "../../../../../src/components/views/settings/CrossSigningPanel";
|
||||
import {
|
||||
flushPromises,
|
||||
getMockClientWithEventEmitter,
|
||||
mockClientMethodsCrypto,
|
||||
mockClientMethodsUser,
|
||||
} from "../../../../test-utils";
|
||||
import Modal from "../../../../../src/Modal";
|
||||
import ConfirmDestroyCrossSigningDialog from "../../../../../src/components/views/dialogs/security/ConfirmDestroyCrossSigningDialog";
|
||||
|
||||
describe("<CrossSigningPanel />", () => {
|
||||
const userId = "@alice:server.org";
|
||||
let mockClient: Mocked<MatrixClient>;
|
||||
const getComponent = () => render(<CrossSigningPanel />);
|
||||
|
||||
beforeEach(() => {
|
||||
mockClient = getMockClientWithEventEmitter({
|
||||
...mockClientMethodsUser(userId),
|
||||
...mockClientMethodsCrypto(),
|
||||
doesServerSupportUnstableFeature: jest.fn(),
|
||||
});
|
||||
|
||||
mockClient.doesServerSupportUnstableFeature.mockResolvedValue(true);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("should render a spinner while loading", () => {
|
||||
getComponent();
|
||||
|
||||
expect(screen.getByRole("progressbar")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should render when homeserver does not support cross-signing", async () => {
|
||||
mockClient.doesServerSupportUnstableFeature.mockResolvedValue(false);
|
||||
|
||||
getComponent();
|
||||
await flushPromises();
|
||||
|
||||
expect(screen.getByText("Your homeserver does not support cross-signing.")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("when cross signing is ready", () => {
|
||||
it("should render when keys are not backed up", async () => {
|
||||
getComponent();
|
||||
await flushPromises();
|
||||
|
||||
expect(screen.getByTestId("summarised-status").innerHTML).toEqual(
|
||||
"⚠️ Cross-signing is ready but keys are not backed up.",
|
||||
);
|
||||
expect(screen.getByText("Cross-signing private keys:").parentElement!).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should render when keys are backed up", async () => {
|
||||
mocked(mockClient.getCrypto()!.getCrossSigningStatus).mockResolvedValue({
|
||||
publicKeysOnDevice: true,
|
||||
privateKeysInSecretStorage: true,
|
||||
privateKeysCachedLocally: {
|
||||
masterKey: true,
|
||||
selfSigningKey: true,
|
||||
userSigningKey: true,
|
||||
},
|
||||
});
|
||||
getComponent();
|
||||
await flushPromises();
|
||||
|
||||
expect(screen.getByTestId("summarised-status").innerHTML).toEqual("✅ Cross-signing is ready for use.");
|
||||
expect(screen.getByText("Cross-signing private keys:").parentElement!).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should allow reset of cross-signing", async () => {
|
||||
mockClient.getCrypto()!.bootstrapCrossSigning = jest.fn().mockResolvedValue(undefined);
|
||||
getComponent();
|
||||
await flushPromises();
|
||||
|
||||
const modalSpy = jest.spyOn(Modal, "createDialog");
|
||||
|
||||
screen.getByRole("button", { name: "Reset" }).click();
|
||||
expect(modalSpy).toHaveBeenCalledWith(ConfirmDestroyCrossSigningDialog, expect.any(Object));
|
||||
modalSpy.mock.lastCall![1]!.onFinished(true);
|
||||
expect(mockClient.getCrypto()!.bootstrapCrossSigning).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ setupNewCrossSigning: true }),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when cross signing is not ready", () => {
|
||||
beforeEach(() => {
|
||||
mocked(mockClient.getCrypto()!.isCrossSigningReady).mockResolvedValue(false);
|
||||
});
|
||||
|
||||
it("should render when keys are not backed up", async () => {
|
||||
getComponent();
|
||||
await flushPromises();
|
||||
|
||||
expect(screen.getByTestId("summarised-status").innerHTML).toEqual("Cross-signing is not set up.");
|
||||
});
|
||||
|
||||
it("should render when keys are backed up", async () => {
|
||||
mocked(mockClient.getCrypto()!.getCrossSigningStatus).mockResolvedValue({
|
||||
publicKeysOnDevice: true,
|
||||
privateKeysInSecretStorage: true,
|
||||
privateKeysCachedLocally: {
|
||||
masterKey: true,
|
||||
selfSigningKey: true,
|
||||
userSigningKey: true,
|
||||
},
|
||||
});
|
||||
getComponent();
|
||||
await flushPromises();
|
||||
|
||||
expect(screen.getByTestId("summarised-status").innerHTML).toEqual(
|
||||
"Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.",
|
||||
);
|
||||
expect(screen.getByText("Cross-signing private keys:").parentElement!).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { render, waitFor, screen, fireEvent } from "jest-matrix-react";
|
||||
import { type MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { mocked } from "jest-mock";
|
||||
|
||||
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
|
||||
import * as TestUtils from "../../../../test-utils";
|
||||
import CryptographyPanel from "../../../../../src/components/views/settings/CryptographyPanel";
|
||||
import { withClientContextRenderOptions } from "../../../../test-utils";
|
||||
|
||||
describe("CryptographyPanel", () => {
|
||||
it("shows the session ID and key", async () => {
|
||||
const sessionId = "ABCDEFGHIJ";
|
||||
const sessionKey = "AbCDeFghIJK7L/m4nOPqRSTUVW4xyzaBCDef6gHIJkl";
|
||||
const sessionKeyFormatted = "<strong>AbCD eFgh IJK7 L/m4 nOPq RSTU VW4x yzaB CDef 6gHI Jkl</strong>";
|
||||
|
||||
TestUtils.stubClient();
|
||||
const client: MatrixClient = MatrixClientPeg.safeGet();
|
||||
client.deviceId = sessionId;
|
||||
|
||||
mocked(client.getCrypto()!.getOwnDeviceKeys).mockResolvedValue({ ed25519: sessionKey, curve25519: "1234" });
|
||||
|
||||
// When we render the CryptographyPanel
|
||||
const rendered = render(<CryptographyPanel />, withClientContextRenderOptions(client));
|
||||
|
||||
// Then it displays info about the user's session
|
||||
const codes = rendered.container.querySelectorAll("code");
|
||||
expect(codes.length).toEqual(2);
|
||||
expect(codes[0].innerHTML).toEqual(sessionId);
|
||||
|
||||
// Initially a placeholder
|
||||
expect(codes[1].innerHTML).toEqual("<strong>...</strong>");
|
||||
|
||||
// Then the actual key
|
||||
await waitFor(() => expect(codes[1].innerHTML).toEqual(sessionKeyFormatted));
|
||||
});
|
||||
|
||||
it("handles errors fetching session key", async () => {
|
||||
const sessionId = "ABCDEFGHIJ";
|
||||
|
||||
TestUtils.stubClient();
|
||||
const client: MatrixClient = MatrixClientPeg.safeGet();
|
||||
client.deviceId = sessionId;
|
||||
|
||||
mocked(client.getCrypto()!.getOwnDeviceKeys).mockRejectedValue(new Error("bleh"));
|
||||
|
||||
// When we render the CryptographyPanel
|
||||
const rendered = render(<CryptographyPanel />, withClientContextRenderOptions(client));
|
||||
|
||||
// Then it displays info about the user's session
|
||||
const codes = rendered.container.querySelectorAll("code");
|
||||
|
||||
// Initially a placeholder
|
||||
expect(codes[1].innerHTML).toEqual("<strong>...</strong>");
|
||||
|
||||
// Then "not supported key
|
||||
await waitFor(() => expect(codes[1].innerHTML).toEqual("<strong><not supported></strong>"));
|
||||
});
|
||||
|
||||
it("should open the export e2e keys dialog on click", async () => {
|
||||
const sessionId = "ABCDEFGHIJ";
|
||||
const sessionKey = "AbCDeFghIJK7L/m4nOPqRSTUVW4xyzaBCDef6gHIJkl";
|
||||
|
||||
TestUtils.stubClient();
|
||||
const client: MatrixClient = MatrixClientPeg.safeGet();
|
||||
client.deviceId = sessionId;
|
||||
|
||||
mocked(client.getCrypto()!.getOwnDeviceKeys).mockResolvedValue({ ed25519: sessionKey, curve25519: "1234" });
|
||||
|
||||
render(<CryptographyPanel />, withClientContextRenderOptions(client));
|
||||
fireEvent.click(await screen.findByRole("button", { name: "Export E2E room keys" }));
|
||||
await expect(screen.findByRole("heading", { name: "Export room keys" })).resolves.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should open the import e2e keys dialog on click", async () => {
|
||||
const sessionId = "ABCDEFGHIJ";
|
||||
const sessionKey = "AbCDeFghIJK7L/m4nOPqRSTUVW4xyzaBCDef6gHIJkl";
|
||||
|
||||
TestUtils.stubClient();
|
||||
const client: MatrixClient = MatrixClientPeg.safeGet();
|
||||
client.deviceId = sessionId;
|
||||
|
||||
mocked(client.getCrypto()!.getOwnDeviceKeys).mockResolvedValue({ ed25519: sessionKey, curve25519: "1234" });
|
||||
|
||||
render(<CryptographyPanel />, withClientContextRenderOptions(client));
|
||||
fireEvent.click(await screen.findByRole("button", { name: "Import E2E room keys" }));
|
||||
await expect(screen.findByRole("heading", { name: "Import room keys" })).resolves.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
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 OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { fireEvent, render, screen, within } from "jest-matrix-react";
|
||||
import { mocked } from "jest-mock";
|
||||
|
||||
import {
|
||||
flushPromises,
|
||||
getMockClientWithEventEmitter,
|
||||
mockClientMethodsCrypto,
|
||||
mockClientMethodsUser,
|
||||
} from "../../../../test-utils";
|
||||
import SecureBackupPanel from "../../../../../src/components/views/settings/SecureBackupPanel";
|
||||
import { accessSecretStorage } from "../../../../../src/SecurityManager";
|
||||
|
||||
jest.mock("../../../../../src/SecurityManager", () => ({
|
||||
accessSecretStorage: jest.fn(),
|
||||
}));
|
||||
|
||||
describe("<SecureBackupPanel />", () => {
|
||||
const userId = "@alice:server.org";
|
||||
const client = getMockClientWithEventEmitter({
|
||||
...mockClientMethodsUser(userId),
|
||||
...mockClientMethodsCrypto(),
|
||||
getClientWellKnown: jest.fn(),
|
||||
});
|
||||
|
||||
const getComponent = () => render(<SecureBackupPanel />);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(client.getCrypto()!, "getKeyBackupInfo").mockResolvedValue({
|
||||
version: "1",
|
||||
algorithm: "test",
|
||||
auth_data: {
|
||||
public_key: "1234",
|
||||
},
|
||||
});
|
||||
Object.assign(client.getCrypto()!, {
|
||||
isKeyBackupTrusted: jest.fn().mockResolvedValue({
|
||||
trusted: false,
|
||||
matchesDecryptionKey: false,
|
||||
}),
|
||||
getActiveSessionBackupVersion: jest.fn().mockResolvedValue(null),
|
||||
deleteKeyBackupVersion: jest.fn().mockResolvedValue(undefined),
|
||||
});
|
||||
|
||||
mocked(client.secretStorage.hasKey).mockClear().mockResolvedValue(false);
|
||||
|
||||
mocked(accessSecretStorage).mockClear().mockResolvedValue();
|
||||
});
|
||||
|
||||
it("displays a loader while checking keybackup", async () => {
|
||||
getComponent();
|
||||
expect(screen.getByRole("progressbar")).toBeInTheDocument();
|
||||
await flushPromises();
|
||||
expect(screen.queryByRole("progressbar")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("handles error fetching backup", async () => {
|
||||
// getKeyBackupInfo can fail for various reasons
|
||||
jest.spyOn(client.getCrypto()!, "getKeyBackupInfo").mockImplementation(async () => {
|
||||
throw new Error("beep beep");
|
||||
});
|
||||
const renderResult = getComponent();
|
||||
await renderResult.findByText("Unable to load key backup status");
|
||||
expect(renderResult.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("handles absence of backup", async () => {
|
||||
jest.spyOn(client.getCrypto()!, "getKeyBackupInfo").mockResolvedValue(null);
|
||||
getComponent();
|
||||
// flush getKeyBackupInfo promise
|
||||
await flushPromises();
|
||||
expect(screen.getByText("Back up your keys before signing out to avoid losing them.")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("suggests connecting session to key backup when backup exists", async () => {
|
||||
const { container } = getComponent();
|
||||
// flush checkKeyBackup promise
|
||||
await flushPromises();
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("displays when session is connected to key backup", async () => {
|
||||
mocked(client.getCrypto()!).getActiveSessionBackupVersion.mockResolvedValue("1");
|
||||
getComponent();
|
||||
// flush checkKeyBackup promise
|
||||
await flushPromises();
|
||||
|
||||
expect(screen.getByText("✅ This session is backing up your keys.")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("asks for confirmation before deleting a backup", async () => {
|
||||
getComponent();
|
||||
// flush checkKeyBackup promise
|
||||
await flushPromises();
|
||||
|
||||
fireEvent.click(screen.getByText("Delete Backup"));
|
||||
|
||||
const dialog = await screen.findByRole("dialog");
|
||||
|
||||
expect(
|
||||
within(dialog).getByText(
|
||||
"Are you sure? You will lose your encrypted messages if your keys are not backed up properly.",
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(within(dialog).getByText("Cancel"));
|
||||
|
||||
expect(client.getCrypto()!.deleteKeyBackupVersion).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("deletes backup after confirmation", async () => {
|
||||
jest.spyOn(client.getCrypto()!, "getKeyBackupInfo")
|
||||
.mockResolvedValueOnce({
|
||||
version: "1",
|
||||
algorithm: "test",
|
||||
auth_data: {
|
||||
public_key: "1234",
|
||||
},
|
||||
})
|
||||
.mockResolvedValue(null);
|
||||
getComponent();
|
||||
|
||||
fireEvent.click(await screen.findByText("Delete Backup"));
|
||||
|
||||
const dialog = await screen.findByRole("dialog");
|
||||
|
||||
expect(
|
||||
within(dialog).getByText(
|
||||
"Are you sure? You will lose your encrypted messages if your keys are not backed up properly.",
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(within(dialog).getByTestId("dialog-primary-button"));
|
||||
|
||||
expect(client.getCrypto()!.deleteKeyBackupVersion).toHaveBeenCalledWith("1");
|
||||
|
||||
// delete request
|
||||
await flushPromises();
|
||||
// refresh backup info
|
||||
await flushPromises();
|
||||
});
|
||||
|
||||
it("resets secret storage", async () => {
|
||||
mocked(client.secretStorage.hasKey).mockClear().mockResolvedValue(true);
|
||||
getComponent();
|
||||
// flush checkKeyBackup promise
|
||||
await flushPromises();
|
||||
|
||||
jest.spyOn(client.getCrypto()!, "getKeyBackupInfo").mockClear();
|
||||
mocked(client.getCrypto()!).isKeyBackupTrusted.mockClear();
|
||||
|
||||
fireEvent.click(screen.getByText("Reset"));
|
||||
|
||||
// enter loading state
|
||||
expect(accessSecretStorage).toHaveBeenCalled();
|
||||
await flushPromises();
|
||||
|
||||
// backup status refreshed
|
||||
expect(client.getCrypto()!.getKeyBackupInfo).toHaveBeenCalled();
|
||||
expect(client.getCrypto()!.isKeyBackupTrusted).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -1,40 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<CrossSigningPanel /> when cross signing is not ready should render when keys are backed up 1`] = `
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Cross-signing private keys:
|
||||
</th>
|
||||
<td>
|
||||
in secret storage
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
|
||||
exports[`<CrossSigningPanel /> when cross signing is ready should render when keys are backed up 1`] = `
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Cross-signing private keys:
|
||||
</th>
|
||||
<td>
|
||||
in secret storage
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
|
||||
exports[`<CrossSigningPanel /> when cross signing is ready should render when keys are not backed up 1`] = `
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Cross-signing private keys:
|
||||
</th>
|
||||
<td>
|
||||
not found in storage
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
@@ -1,190 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<SecureBackupPanel /> handles error fetching backup 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_text"
|
||||
>
|
||||
Back up your encryption keys with your account data in case you lose access to your sessions. Your keys will be secured with a unique Recovery Key.
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_text"
|
||||
>
|
||||
Unable to load key backup status
|
||||
</div>
|
||||
<details>
|
||||
<summary
|
||||
class="mx_SecureBackupPanel_advanced"
|
||||
>
|
||||
Advanced
|
||||
</summary>
|
||||
<table
|
||||
class="mx_SecureBackupPanel_statusList"
|
||||
>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Backup key stored:
|
||||
</th>
|
||||
<td>
|
||||
not stored
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Backup key cached:
|
||||
</th>
|
||||
<td>
|
||||
not found locally
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Secret storage public key:
|
||||
</th>
|
||||
<td>
|
||||
not found
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Secret storage:
|
||||
</th>
|
||||
<td>
|
||||
not ready
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</details>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<SecureBackupPanel /> suggests connecting session to key backup when backup exists 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_text"
|
||||
>
|
||||
Back up your encryption keys with your account data in case you lose access to your sessions. Your keys will be secured with a unique Recovery Key.
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_text"
|
||||
>
|
||||
<span>
|
||||
This session is
|
||||
<strong>
|
||||
not backing up your keys
|
||||
</strong>
|
||||
, but you do have an existing backup you can restore from and add to going forward.
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_text"
|
||||
>
|
||||
Connect this session to key backup before signing out to avoid losing any keys that may only be on this session.
|
||||
</div>
|
||||
<details>
|
||||
<summary
|
||||
class="mx_SecureBackupPanel_advanced"
|
||||
>
|
||||
Advanced
|
||||
</summary>
|
||||
<table
|
||||
class="mx_SecureBackupPanel_statusList"
|
||||
>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Backup key stored:
|
||||
</th>
|
||||
<td>
|
||||
not stored
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Backup key cached:
|
||||
</th>
|
||||
<td>
|
||||
not found locally
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Secret storage public key:
|
||||
</th>
|
||||
<td>
|
||||
not found
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Secret storage:
|
||||
</th>
|
||||
<td>
|
||||
not ready
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Latest backup version on server:
|
||||
</th>
|
||||
<td>
|
||||
1
|
||||
(
|
||||
Algorithm:
|
||||
|
||||
<code>
|
||||
test
|
||||
</code>
|
||||
)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Active backup version:
|
||||
</th>
|
||||
<td>
|
||||
None
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div />
|
||||
</details>
|
||||
<div
|
||||
class="mx_SecureBackupPanel_buttonRow"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Connect this session to Key Backup
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger_outline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Delete Backup
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -120,90 +120,6 @@ exports[`<SecurityUserSettingsTab /> renders security section 1`] = `
|
||||
<div
|
||||
class="mx_SettingsSection_subSections"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Secure Backup
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_content"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsection_text"
|
||||
>
|
||||
Back up your encryption keys with your account data in case you lose access to your sessions. Your keys will be secured with a unique Recovery Key.
|
||||
</div>
|
||||
<div
|
||||
class="mx_Spinner"
|
||||
>
|
||||
<div
|
||||
aria-label="Loading…"
|
||||
class="mx_Spinner_icon"
|
||||
data-testid="spinner"
|
||||
role="progressbar"
|
||||
style="width: 32px; height: 32px;"
|
||||
/>
|
||||
</div>
|
||||
<details>
|
||||
<summary
|
||||
class="mx_SecureBackupPanel_advanced"
|
||||
>
|
||||
Advanced
|
||||
</summary>
|
||||
<table
|
||||
class="mx_SecureBackupPanel_statusList"
|
||||
>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Backup key stored:
|
||||
</th>
|
||||
<td>
|
||||
not stored
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Backup key cached:
|
||||
</th>
|
||||
<td>
|
||||
not found locally
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Secret storage public key:
|
||||
</th>
|
||||
<td>
|
||||
not found
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Secret storage:
|
||||
</th>
|
||||
<td>
|
||||
not ready
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
>
|
||||
@@ -240,203 +156,6 @@ exports[`<SecurityUserSettingsTab /> renders security section 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Cross-signing
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_content"
|
||||
>
|
||||
<div
|
||||
class="mx_Spinner"
|
||||
>
|
||||
<div
|
||||
aria-label="Loading…"
|
||||
class="mx_Spinner_icon"
|
||||
data-testid="spinner"
|
||||
role="progressbar"
|
||||
style="width: 32px; height: 32px;"
|
||||
/>
|
||||
</div>
|
||||
<details>
|
||||
<summary
|
||||
class="mx_CrossSigningPanel_advanced"
|
||||
>
|
||||
Advanced
|
||||
</summary>
|
||||
<table
|
||||
class="mx_CrossSigningPanel_statusList"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Cross-signing public keys:
|
||||
</th>
|
||||
<td>
|
||||
not found
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Cross-signing private keys:
|
||||
</th>
|
||||
<td>
|
||||
not found in storage
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Master private key:
|
||||
</th>
|
||||
<td>
|
||||
not found locally
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Self signing private key:
|
||||
</th>
|
||||
<td>
|
||||
not found locally
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
User signing private key:
|
||||
</th>
|
||||
<td>
|
||||
not found locally
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Homeserver feature support:
|
||||
</th>
|
||||
<td>
|
||||
not found
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsectionHeading"
|
||||
>
|
||||
<h3
|
||||
class="mx_Heading_h4 mx_SettingsSubsectionHeading_heading"
|
||||
>
|
||||
Cryptography
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsSubsection_content"
|
||||
>
|
||||
<div
|
||||
class="mx_SettingsSubsection_text"
|
||||
>
|
||||
<table
|
||||
class="mx_CryptographyPanel_sessionInfo"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Session ID:
|
||||
</th>
|
||||
<td>
|
||||
<code />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th
|
||||
scope="row"
|
||||
>
|
||||
Session key:
|
||||
</th>
|
||||
<td>
|
||||
<code>
|
||||
<strong>
|
||||
...
|
||||
</strong>
|
||||
</code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div
|
||||
class="mx_CryptographyPanel_importExportButtons"
|
||||
>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Export E2E room keys
|
||||
</div>
|
||||
<div
|
||||
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Import E2E room keys
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_SettingsFlag"
|
||||
>
|
||||
<label
|
||||
class="mx_SettingsFlag_label"
|
||||
for="mx_SettingsFlag_vY7Q4uEh9K38"
|
||||
>
|
||||
<span
|
||||
class="mx_SettingsFlag_labelText"
|
||||
>
|
||||
Only send messages to verified users
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
aria-checked="false"
|
||||
aria-disabled="false"
|
||||
aria-label="Only send messages to verified users"
|
||||
class="mx_AccessibleButton mx_ToggleSwitch mx_ToggleSwitch_enabled"
|
||||
id="mx_SettingsFlag_vY7Q4uEh9K38"
|
||||
role="switch"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="mx_ToggleSwitch_ball"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user