Move session manager out of beta (#10968)

* remove old device manager

* undo type fix for cypress crypto

* update test case
This commit is contained in:
Kerry 2023-05-26 13:58:28 +12:00 committed by GitHub
parent e326526c10
commit 530197bfcd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 450 additions and 1673 deletions

View file

@ -173,7 +173,7 @@ describe("<MatrixChat />", () => {
expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({
action: Action.ViewUserSettings,
initialTabId: UserTab.Security,
initialTabId: UserTab.SessionManager,
});
});
});

View file

@ -117,10 +117,7 @@ describe("<UserSettingsDialog />", () => {
expect(getByTestId(`settings-tab-${UserTab.Voice}`)).toBeTruthy();
});
it("renders session manager tab when enabled", () => {
mockSettingsStore.getValue.mockImplementation((settingName): any => {
return settingName === "feature_new_device_manager";
});
it("renders session manager tab", () => {
const { getByTestId } = render(getComponent());
expect(getByTestId(`settings-tab-${UserTab.SessionManager}`)).toBeTruthy();
});
@ -153,28 +150,15 @@ describe("<UserSettingsDialog />", () => {
expect(queryByTestId(`settings-tab-${UserTab.Mjolnir}`)).toBeFalsy();
expect(mockSettingsStore.watchSetting.mock.calls[0][0]).toEqual("feature_mjolnir");
expect(mockSettingsStore.watchSetting.mock.calls[1][0]).toEqual("feature_new_device_manager");
// call the watch setting callback
watchSettingCallbacks["feature_mjolnir"]("feature_mjolnir", "", SettingLevel.ACCOUNT, true, true);
// tab is rendered now
expect(queryByTestId(`settings-tab-${UserTab.Mjolnir}`)).toBeTruthy();
// call the watch setting callback
watchSettingCallbacks["feature_new_device_manager"](
"feature_new_device_manager",
"",
SettingLevel.ACCOUNT,
true,
true,
);
// tab is rendered now
expect(queryByTestId(`settings-tab-${UserTab.SessionManager}`)).toBeTruthy();
unmount();
// unwatches settings on unmount
expect(mockSettingsStore.unwatchSetting).toHaveBeenCalledWith("mock-watcher-id-feature_mjolnir");
expect(mockSettingsStore.unwatchSetting).toHaveBeenCalledWith("mock-watcher-id-feature_new_device_manager");
});
});

View file

@ -128,6 +128,24 @@ NodeList [
Security & Privacy
</span>
</li>,
<li
aria-controls="mx_tabpanel_USER_SESSION_MANAGER_TAB"
aria-selected="false"
class="mx_AccessibleButton mx_TabbedView_tabLabel"
data-testid="settings-tab-USER_SESSION_MANAGER_TAB"
role="tab"
tabindex="-1"
>
<span
class="mx_TabbedView_maskedIcon mx_UserSettingsDialog_sessionsIcon"
/>
<span
class="mx_TabbedView_tabLabel_text"
id="mx_tabpanel_USER_SESSION_MANAGER_TAB_label"
>
Sessions
</span>
</li>,
<li
aria-controls="mx_tabpanel_USER_LABS_TAB"
aria-selected="false"

View file

@ -1,246 +0,0 @@
/*
Copyright 2022 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import { act, fireEvent, render } from "@testing-library/react";
import { DeviceInfo } from "matrix-js-sdk/src/crypto/deviceinfo";
import { sleep } from "matrix-js-sdk/src/utils";
import { PUSHER_DEVICE_ID, PUSHER_ENABLED } from "matrix-js-sdk/src/@types/event";
import DevicesPanel from "../../../../src/components/views/settings/DevicesPanel";
import { flushPromises, getMockClientWithEventEmitter, mkPusher, mockClientMethodsUser } from "../../../test-utils";
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
describe("<DevicesPanel />", () => {
const userId = "@alice:server.org";
// the local device
const ownDevice = { device_id: "device_1" };
// a device which we have verified via cross-signing
const verifiedDevice = { device_id: "device_2" };
// a device which we have *not* verified via cross-signing
const unverifiedDevice = { device_id: "device_3" };
// a device which is returned by `getDevices` but getDeviceVerificationStatus returns `null` for
// (as it would for a device with no E2E keys).
const nonCryptoDevice = { device_id: "non_crypto" };
const mockCrypto = {
getDeviceVerificationStatus: jest.fn().mockImplementation((_userId, deviceId) => {
if (_userId !== userId) {
throw new Error(`bad user id ${_userId}`);
}
if (deviceId === ownDevice.device_id || deviceId === verifiedDevice.device_id) {
return { crossSigningVerified: true };
} else if (deviceId === unverifiedDevice.device_id) {
return {
crossSigningVerified: false,
};
} else {
return null;
}
}),
};
const mockClient = getMockClientWithEventEmitter({
...mockClientMethodsUser(userId),
getDevices: jest.fn(),
getDeviceId: jest.fn().mockReturnValue(ownDevice.device_id),
deleteMultipleDevices: jest.fn(),
getStoredDevice: jest.fn().mockReturnValue(new DeviceInfo("id")),
generateClientSecret: jest.fn(),
getPushers: jest.fn(),
setPusher: jest.fn(),
getCrypto: jest.fn().mockReturnValue(mockCrypto),
});
const getComponent = () => (
<MatrixClientContext.Provider value={mockClient}>
<DevicesPanel />
</MatrixClientContext.Provider>
);
beforeEach(() => {
jest.clearAllMocks();
mockClient.getDevices
.mockReset()
.mockResolvedValue({ devices: [ownDevice, verifiedDevice, unverifiedDevice, nonCryptoDevice] });
mockClient.getPushers.mockReset().mockResolvedValue({
pushers: [
mkPusher({
[PUSHER_DEVICE_ID.name]: ownDevice.device_id,
[PUSHER_ENABLED.name]: true,
}),
],
});
});
it("renders device panel with devices", async () => {
const { container } = render(getComponent());
await flushPromises();
expect(container).toMatchSnapshot();
});
describe("device deletion", () => {
const interactiveAuthError = { httpStatus: 401, data: { flows: [{ stages: ["m.login.password"] }] } };
const toggleDeviceSelection = (container: HTMLElement, deviceId: string) =>
act(() => {
const checkbox = container.querySelector(`#device-tile-checkbox-${deviceId}`)!;
fireEvent.click(checkbox);
});
beforeEach(() => {
mockClient.deleteMultipleDevices.mockReset();
});
it("deletes selected devices when interactive auth is not required", async () => {
mockClient.deleteMultipleDevices.mockResolvedValue({});
mockClient.getDevices
.mockResolvedValueOnce({ devices: [ownDevice, verifiedDevice, unverifiedDevice] })
// pretend it was really deleted on refresh
.mockResolvedValueOnce({ devices: [ownDevice, unverifiedDevice] });
const { container, getByTestId } = render(getComponent());
await flushPromises();
expect(container.getElementsByClassName("mx_DevicesPanel_device").length).toEqual(3);
toggleDeviceSelection(container, verifiedDevice.device_id);
mockClient.getDevices.mockClear();
act(() => {
fireEvent.click(getByTestId("sign-out-devices-btn"));
});
expect(container.getElementsByClassName("mx_Spinner").length).toBeTruthy();
expect(mockClient.deleteMultipleDevices).toHaveBeenCalledWith([verifiedDevice.device_id], undefined);
await flushPromises();
// devices refreshed
expect(mockClient.getDevices).toHaveBeenCalled();
// and rerendered
expect(container.getElementsByClassName("mx_DevicesPanel_device").length).toEqual(2);
});
it("deletes selected devices when interactive auth is required", async () => {
mockClient.deleteMultipleDevices
// require auth
.mockRejectedValueOnce(interactiveAuthError)
// then succeed
.mockResolvedValueOnce({});
mockClient.getDevices
.mockResolvedValueOnce({ devices: [ownDevice, verifiedDevice, unverifiedDevice] })
// pretend it was really deleted on refresh
.mockResolvedValueOnce({ devices: [ownDevice, unverifiedDevice] });
const { container, getByTestId, getByLabelText } = render(getComponent());
await flushPromises();
// reset mock count after initial load
mockClient.getDevices.mockClear();
toggleDeviceSelection(container, verifiedDevice.device_id);
act(() => {
fireEvent.click(getByTestId("sign-out-devices-btn"));
});
await flushPromises();
// modal rendering has some weird sleeps
await sleep(100);
expect(mockClient.deleteMultipleDevices).toHaveBeenCalledWith([verifiedDevice.device_id], undefined);
const modal = document.getElementsByClassName("mx_Dialog");
expect(modal).toMatchSnapshot();
// fill password and submit for interactive auth
act(() => {
fireEvent.change(getByLabelText("Password"), { target: { value: "topsecret" } });
fireEvent.submit(getByLabelText("Password"));
});
await flushPromises();
// called again with auth
expect(mockClient.deleteMultipleDevices).toHaveBeenCalledWith([verifiedDevice.device_id], {
identifier: {
type: "m.id.user",
user: userId,
},
password: "",
type: "m.login.password",
user: userId,
});
// devices refreshed
expect(mockClient.getDevices).toHaveBeenCalled();
// and rerendered
expect(container.getElementsByClassName("mx_DevicesPanel_device").length).toEqual(2);
});
it("clears loading state when interactive auth fail is cancelled", async () => {
mockClient.deleteMultipleDevices
// require auth
.mockRejectedValueOnce(interactiveAuthError)
// then succeed
.mockResolvedValueOnce({});
mockClient.getDevices
.mockResolvedValueOnce({ devices: [ownDevice, verifiedDevice, unverifiedDevice] })
// pretend it was really deleted on refresh
.mockResolvedValueOnce({ devices: [ownDevice, unverifiedDevice] });
const { container, getByTestId } = render(getComponent());
await flushPromises();
// reset mock count after initial load
mockClient.getDevices.mockClear();
toggleDeviceSelection(container, verifiedDevice.device_id);
act(() => {
fireEvent.click(getByTestId("sign-out-devices-btn"));
});
expect(container.getElementsByClassName("mx_Spinner").length).toBeTruthy();
await flushPromises();
// modal rendering has some weird sleeps
await sleep(20);
// close the modal without submission
act(() => {
const modalCloseButton = document.querySelector('[aria-label="Close dialog"]')!;
fireEvent.click(modalCloseButton);
});
await flushPromises();
// not refreshed
expect(mockClient.getDevices).not.toHaveBeenCalled();
// spinner removed
expect(container.getElementsByClassName("mx_Spinner").length).toBeFalsy();
});
});
});

View file

@ -1,506 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<DevicesPanel /> device deletion deletes selected devices when interactive auth is required 1`] = `
HTMLCollection [
<div
class="mx_Dialog"
>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
<div
aria-describedby="mx_Dialog_content"
aria-labelledby="mx_BaseDialog_title"
class="mx_InteractiveAuthDialog mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
>
<div
class="mx_Dialog_header mx_Dialog_headerWithCancel"
>
<h2
class="mx_Heading_h2 mx_Dialog_title"
id="mx_BaseDialog_title"
>
Authentication
</h2>
<div
aria-label="Close dialog"
class="mx_AccessibleButton mx_Dialog_cancelButton"
role="button"
tabindex="0"
/>
</div>
<div
id="mx_Dialog_content"
>
<div>
<p>
Confirm your identity by entering your account password below.
</p>
<form
class="mx_InteractiveAuthEntryComponents_passwordSection"
>
<div
class="mx_Field mx_Field_input"
>
<input
id="mx_Field_1"
label="Password"
name="passwordField"
placeholder="Password"
type="password"
value=""
/>
<label
for="mx_Field_1"
>
Password
</label>
</div>
<div
class="mx_button_row"
>
<input
class="mx_Dialog_primary"
disabled=""
type="submit"
value="Continue"
/>
</div>
</form>
</div>
</div>
</div>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
</div>,
]
`;
exports[`<DevicesPanel /> renders device panel with devices 1`] = `
<div>
<div
class="mx_DevicesPanel"
>
<div
class="mx_DevicesPanel_header"
>
<div
class="mx_DevicesPanel_header_title"
>
This device
</div>
</div>
<div
class="mx_DevicesPanel_device mx_DevicesPanel_myDevice"
>
<div
class="mx_DevicesPanel_deviceTrust"
>
<span
class="mx_DevicesPanel_icon mx_E2EIcon mx_E2EIcon_verified"
/>
</div>
<div
class="mx_DeviceTile"
data-testid="device-tile-device_1"
>
<div
class="mx_DeviceTypeIcon"
>
<div
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Verified"
class="mx_DeviceTypeIcon_verificationIcon verified"
role="img"
/>
</div>
<div
class="mx_DeviceTile_info"
>
<h4
class="mx_Heading_h4"
>
device_1
</h4>
<div
class="mx_DeviceTile_metadata"
>
<span
data-testid="device-metadata-isVerified"
>
Verified
</span>
·
<span
data-testid="device-metadata-deviceId"
>
device_1
</span>
</div>
</div>
<div
class="mx_DeviceTile_actions"
>
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger_outline"
role="button"
tabindex="0"
>
Sign Out
</div>
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline"
role="button"
tabindex="0"
>
Rename
</div>
</div>
</div>
</div>
<hr />
<div
class="mx_DevicesPanel_header"
>
<div
class="mx_DevicesPanel_header_trust"
>
<span
class="mx_DevicesPanel_header_icon mx_E2EIcon mx_E2EIcon_verified"
/>
</div>
<div
class="mx_DevicesPanel_header_title"
>
Verified devices
</div>
</div>
<div
class="mx_DevicesPanel_device"
>
<div
class="mx_SelectableDeviceTile"
>
<span
class="mx_Checkbox mx_SelectableDeviceTile_checkbox mx_Checkbox_hasKind mx_Checkbox_kind_solid"
>
<input
data-testid="device-tile-checkbox-device_2"
id="device-tile-checkbox-device_2"
type="checkbox"
/>
<label
for="device-tile-checkbox-device_2"
>
<div
class="mx_Checkbox_background"
>
<div
class="mx_Checkbox_checkmark"
/>
</div>
<div>
<div
class="mx_DeviceTile"
data-testid="device-tile-device_2"
>
<div
class="mx_DeviceTypeIcon"
>
<div
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Verified"
class="mx_DeviceTypeIcon_verificationIcon verified"
role="img"
/>
</div>
<div
class="mx_DeviceTile_info"
>
<h4
class="mx_Heading_h4"
>
device_2
</h4>
<div
class="mx_DeviceTile_metadata"
>
<span
data-testid="device-metadata-isVerified"
>
Verified
</span>
·
<span
data-testid="device-metadata-deviceId"
>
device_2
</span>
</div>
</div>
<div
class="mx_DeviceTile_actions"
>
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline"
role="button"
tabindex="0"
>
Rename
</div>
</div>
</div>
</div>
</label>
</span>
</div>
</div>
<hr />
<div
class="mx_DevicesPanel_header"
>
<div
class="mx_DevicesPanel_header_trust"
>
<span
class="mx_DevicesPanel_header_icon mx_E2EIcon mx_E2EIcon_warning"
/>
</div>
<div
class="mx_DevicesPanel_header_title"
>
Unverified devices
</div>
</div>
<div
class="mx_DevicesPanel_device"
>
<div
class="mx_SelectableDeviceTile"
>
<span
class="mx_Checkbox mx_SelectableDeviceTile_checkbox mx_Checkbox_hasKind mx_Checkbox_kind_solid"
>
<input
data-testid="device-tile-checkbox-device_3"
id="device-tile-checkbox-device_3"
type="checkbox"
/>
<label
for="device-tile-checkbox-device_3"
>
<div
class="mx_Checkbox_background"
>
<div
class="mx_Checkbox_checkmark"
/>
</div>
<div>
<div
class="mx_DeviceTile"
data-testid="device-tile-device_3"
>
<div
class="mx_DeviceTypeIcon"
>
<div
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
role="img"
/>
</div>
<div
class="mx_DeviceTile_info"
>
<h4
class="mx_Heading_h4"
>
device_3
</h4>
<div
class="mx_DeviceTile_metadata"
>
<span
data-testid="device-metadata-isVerified"
>
Unverified
</span>
·
<span
data-testid="device-metadata-deviceId"
>
device_3
</span>
</div>
</div>
<div
class="mx_DeviceTile_actions"
>
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
role="button"
tabindex="0"
>
Verify
</div>
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline"
role="button"
tabindex="0"
>
Rename
</div>
</div>
</div>
</div>
</label>
</span>
</div>
</div>
<hr />
<div
class="mx_DevicesPanel_header"
>
<div
class="mx_DevicesPanel_header_trust"
/>
<div
class="mx_DevicesPanel_header_title"
>
Devices without encryption support
</div>
</div>
<div
class="mx_DevicesPanel_device"
>
<div
class="mx_SelectableDeviceTile"
>
<span
class="mx_Checkbox mx_SelectableDeviceTile_checkbox mx_Checkbox_hasKind mx_Checkbox_kind_solid"
>
<input
data-testid="device-tile-checkbox-non_crypto"
id="device-tile-checkbox-non_crypto"
type="checkbox"
/>
<label
for="device-tile-checkbox-non_crypto"
>
<div
class="mx_Checkbox_background"
>
<div
class="mx_Checkbox_checkmark"
/>
</div>
<div>
<div
class="mx_DeviceTile"
data-testid="device-tile-non_crypto"
>
<div
class="mx_DeviceTypeIcon"
>
<div
class="mx_DeviceTypeIcon_deviceIconWrapper"
>
<div
aria-label="Unknown session type"
class="mx_DeviceTypeIcon_deviceIcon"
role="img"
/>
</div>
<div
aria-label="Unverified"
class="mx_DeviceTypeIcon_verificationIcon unverified"
role="img"
/>
</div>
<div
class="mx_DeviceTile_info"
>
<h4
class="mx_Heading_h4"
>
non_crypto
</h4>
<div
class="mx_DeviceTile_metadata"
>
<span
data-testid="device-metadata-isVerified"
>
Unverified
</span>
·
<span
data-testid="device-metadata-deviceId"
>
non_crypto
</span>
</div>
</div>
<div
class="mx_DeviceTile_actions"
>
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline"
role="button"
tabindex="0"
>
Rename
</div>
</div>
</div>
</div>
</label>
</span>
</div>
</div>
<div
aria-disabled="true"
class="mx_AccessibleButton mx_DevicesPanel_deleteButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger_outline mx_AccessibleButton_disabled"
data-testid="sign-out-devices-btn"
disabled=""
role="button"
tabindex="0"
>
Sign out 0 selected devices
</div>
</div>
</div>
`;

View file

@ -13,13 +13,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { fireEvent, render } from "@testing-library/react";
import { UNSTABLE_MSC3882_CAPABILITY } from "matrix-js-sdk/src/matrix";
import { render } from "@testing-library/react";
import React from "react";
import SecurityUserSettingsTab from "../../../../../../src/components/views/settings/tabs/user/SecurityUserSettingsTab";
import MatrixClientContext from "../../../../../../src/contexts/MatrixClientContext";
import SettingsStore from "../../../../../../src/settings/SettingsStore";
import {
getMockClientWithEventEmitter,
mockClientMethodsServer,
@ -27,7 +25,6 @@ import {
mockClientMethodsCrypto,
mockClientMethodsDevice,
mockPlatformPeg,
flushPromises,
} from "../../../../../test-utils";
describe("<SecurityUserSettingsTab />", () => {
@ -44,16 +41,6 @@ describe("<SecurityUserSettingsTab />", () => {
...mockClientMethodsCrypto(),
getRooms: jest.fn().mockReturnValue([]),
getIgnoredUsers: jest.fn(),
getVersions: jest.fn().mockResolvedValue({
unstable_features: {
"org.matrix.msc3886": true,
},
}),
getCapabilities: jest.fn().mockResolvedValue({
[UNSTABLE_MSC3882_CAPABILITY.name]: {
enabled: true,
},
}),
});
const getComponent = () => (
@ -62,44 +49,14 @@ describe("<SecurityUserSettingsTab />", () => {
</MatrixClientContext.Provider>
);
const settingsValueSpy = jest.spyOn(SettingsStore, "getValue");
beforeEach(() => {
mockPlatformPeg();
jest.clearAllMocks();
settingsValueSpy.mockReturnValue(false);
});
it("renders sessions section when new session manager is disabled", () => {
settingsValueSpy.mockReturnValue(false);
const { getByTestId } = render(getComponent());
it("renders security section", () => {
const { container } = render(getComponent());
expect(getByTestId("devices-section")).toBeTruthy();
});
it("does not render sessions section when new session manager is enabled", () => {
settingsValueSpy.mockReturnValue(true);
const { queryByTestId } = render(getComponent());
expect(queryByTestId("devices-section")).toBeFalsy();
});
it("renders qr code login section", async () => {
const { getByText } = render(getComponent());
// wait for versions call to settle
await flushPromises();
expect(getByText("Sign in with QR code")).toBeTruthy();
});
it("enters qr code login section when show QR code button clicked", async () => {
const { getByText, getByTestId } = render(getComponent());
// wait for versions call to settle
await flushPromises();
fireEvent.click(getByText("Show QR code"));
expect(getByTestId("login-with-qr")).toBeTruthy();
expect(container).toMatchSnapshot();
});
});

View file

@ -79,59 +79,6 @@ exports[`<LabsUserSettingsTab /> renders settings marked as beta as beta cards 1
</div>
</div>
</div>
<div
class="mx_BetaCard"
>
<div
class="mx_BetaCard_columns"
>
<div
class="mx_BetaCard_columns_description"
>
<h3
class="mx_BetaCard_title"
>
<span>
New session manager
</span>
<span
class="mx_BetaCard_betaPill"
>
Beta
</span>
</h3>
<div
class="mx_BetaCard_caption"
>
<p>
Have greater visibility and control over all your sessions.
</p>
<p>
Our new sessions manager provides better visibility of all your sessions, and greater control over them including the ability to remotely toggle push notifications.
</p>
</div>
<div
class="mx_BetaCard_buttons"
>
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
role="button"
tabindex="0"
>
Join the beta
</div>
</div>
</div>
<div
class="mx_BetaCard_columns_image_wrapper"
>
<img
alt=""
class="mx_BetaCard_columns_image"
/>
</div>
</div>
</div>
</div>
</div>
`;

View file

@ -0,0 +1,399 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<SecurityUserSettingsTab /> renders security section 1`] = `
<div>
<div
class="mx_SettingsTab"
>
<div
class="mx_SettingsTab_sections"
>
<div
class="mx_SettingsSection"
>
<h2
class="mx_Heading_h2"
>
Encryption
</h2>
<div
class="mx_SettingsSection_subSections"
>
<div
class="mx_SettingsSubsection"
>
<div
class="mx_SettingsSubsectionHeading"
>
<h3
class="mx_Heading_h3 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 Security 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>
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"
>
<div
class="mx_SettingsSubsectionHeading"
>
<h3
class="mx_Heading_h3 mx_SettingsSubsectionHeading_heading"
>
Message search
</h3>
</div>
<div
class="mx_SettingsSubsection_content"
>
<div
class="mx_SettingsSubsection_text"
>
<span>
Element can't securely cache encrypted messages locally while running in a web browser. Use
<a
class="mx_ExternalLink"
href="https://element.io/get-started"
rel="noreferrer noopener"
target="_blank"
>
Element Desktop
<i
class="mx_ExternalLink_icon"
/>
</a>
for encrypted messages to appear in search results.
</span>
</div>
</div>
</div>
<div
class="mx_SettingsSubsection"
>
<div
class="mx_SettingsSubsectionHeading"
>
<h3
class="mx_Heading_h3 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>
Advanced
</summary>
<table
class="mx_CrossSigningPanel_statusList"
>
<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>
</table>
</details>
</div>
</div>
<div
class="mx_SettingsSubsection"
>
<div
class="mx_SettingsSubsectionHeading"
>
<h3
class="mx_Heading_h3 mx_SettingsSubsectionHeading_heading"
>
Cryptography
</h3>
</div>
<div
class="mx_SettingsSubsection_content"
>
<div
class="mx_SettingsSubsection_text"
>
<table
class="mx_CryptographyPanel_sessionInfo"
>
<tr>
<th
scope="row"
>
Session ID:
</th>
<td>
<code />
</td>
</tr>
<tr>
<th
scope="row"
>
Session key:
</th>
<td>
<code>
<b>
&lt;not supported&gt;
</b>
</code>
</td>
</tr>
</table>
</div>
<div
class="mx_SettingsFlag"
>
<label
class="mx_SettingsFlag_label"
>
<span
class="mx_SettingsFlag_labelText"
>
Never send encrypted messages to unverified sessions from this session
</span>
</label>
<div
aria-checked="false"
aria-disabled="false"
aria-label="Never send encrypted messages to unverified sessions from this session"
class="mx_AccessibleButton mx_ToggleSwitch mx_ToggleSwitch_enabled"
role="switch"
tabindex="0"
>
<div
class="mx_ToggleSwitch_ball"
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="mx_SettingsSection"
>
<h2
class="mx_Heading_h2"
>
Advanced
</h2>
<div
class="mx_SettingsSection_subSections"
>
<div
class="mx_SettingsSubsection"
>
<div
class="mx_SettingsSubsectionHeading"
>
<h3
class="mx_Heading_h3 mx_SettingsSubsectionHeading_heading"
>
Ignored users
</h3>
</div>
<div
class="mx_SettingsSubsection_content"
>
<div
class="mx_SettingsSubsection_text"
>
You have no ignored users.
</div>
</div>
</div>
<div
class="mx_SettingsSubsection"
>
<div
class="mx_SettingsSubsectionHeading"
>
<h3
class="mx_Heading_h3 mx_SettingsSubsectionHeading_heading"
>
Encryption
</h3>
</div>
<div
class="mx_SettingsSubsection_content"
>
<div
class="mx_SettingsFlag"
>
<label
class="mx_SettingsFlag_label"
>
<span
class="mx_SettingsFlag_labelText"
>
Manually verify all remote sessions
</span>
</label>
<div
aria-checked="false"
aria-disabled="false"
aria-label="Manually verify all remote sessions"
class="mx_AccessibleButton mx_ToggleSwitch mx_ToggleSwitch_enabled"
role="switch"
tabindex="0"
>
<div
class="mx_ToggleSwitch_ball"
/>
</div>
</div>
<div
class="mx_SettingsSubsection_text"
>
Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;