mirror of
https://github.com/vector-im/element-web.git
synced 2024-11-16 05:04:57 +08:00
Merge pull request #6958 from andybalaam/separate-cryptography-setting-component
Break 'Cryptography' settings into a separate component
This commit is contained in:
commit
f05e35bd94
@ -244,6 +244,7 @@
|
|||||||
@import "./views/rooms/_WhoIsTypingTile.scss";
|
@import "./views/rooms/_WhoIsTypingTile.scss";
|
||||||
@import "./views/settings/_AvatarSetting.scss";
|
@import "./views/settings/_AvatarSetting.scss";
|
||||||
@import "./views/settings/_CrossSigningPanel.scss";
|
@import "./views/settings/_CrossSigningPanel.scss";
|
||||||
|
@import "./views/settings/_CryptographyPanel.scss";
|
||||||
@import "./views/settings/_DevicesPanel.scss";
|
@import "./views/settings/_DevicesPanel.scss";
|
||||||
@import "./views/settings/_E2eAdvancedPanel.scss";
|
@import "./views/settings/_E2eAdvancedPanel.scss";
|
||||||
@import "./views/settings/_EmailAddresses.scss";
|
@import "./views/settings/_EmailAddresses.scss";
|
||||||
|
22
res/css/views/settings/_CryptographyPanel.scss
Normal file
22
res/css/views/settings/_CryptographyPanel.scss
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
.mx_CryptographyPanel_sessionInfo {
|
||||||
|
display: table;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_CryptographyPanel_sessionInfo > li {
|
||||||
|
display: table-row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_CryptographyPanel_sessionInfo > li > label,
|
||||||
|
.mx_CryptographyPanel_sessionInfo > li > span {
|
||||||
|
display: table-cell;
|
||||||
|
padding-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_CryptographyPanel_importExportButtons .mx_AccessibleButton {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_CryptographyPanel_importExportButtons {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
@ -14,33 +14,10 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.mx_SecurityUserSettingsTab_deviceInfo {
|
|
||||||
display: table;
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_SecurityUserSettingsTab_deviceInfo > li {
|
|
||||||
display: table-row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_SecurityUserSettingsTab_deviceInfo > li > label,
|
|
||||||
.mx_SecurityUserSettingsTab_deviceInfo > li > span {
|
|
||||||
display: table-cell;
|
|
||||||
padding-right: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_SecurityUserSettingsTab_importExportButtons .mx_AccessibleButton {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_SecurityUserSettingsTab_bulkOptions .mx_AccessibleButton {
|
.mx_SecurityUserSettingsTab_bulkOptions .mx_AccessibleButton {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_SecurityUserSettingsTab_importExportButtons {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_SecurityUserSettingsTab_ignoredUser {
|
.mx_SecurityUserSettingsTab_ignoredUser {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
110
src/components/views/settings/CryptographyPanel.tsx
Normal file
110
src/components/views/settings/CryptographyPanel.tsx
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2021 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 { MatrixClientPeg } from '../../../MatrixClientPeg';
|
||||||
|
import { _t } from '../../../languageHandler';
|
||||||
|
import Modal from '../../../Modal';
|
||||||
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import AccessibleButton from "../elements/AccessibleButton";
|
||||||
|
import * as FormattingUtils from "../../../utils/FormattingUtils";
|
||||||
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
|
import SettingsFlag from "../elements/SettingsFlag";
|
||||||
|
import { SettingLevel } from "../../../settings/SettingLevel";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
}
|
||||||
|
|
||||||
|
@replaceableComponent("views.settings.CryptographyPanel")
|
||||||
|
export default class CryptographyPanel extends React.Component<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(): JSX.Element {
|
||||||
|
const client = MatrixClientPeg.get();
|
||||||
|
const deviceId = client.deviceId;
|
||||||
|
let identityKey = client.getDeviceEd25519Key();
|
||||||
|
if (!identityKey) {
|
||||||
|
identityKey = _t("<not supported>");
|
||||||
|
} else {
|
||||||
|
identityKey = FormattingUtils.formatCryptoKey(identityKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
let importExportButtons = null;
|
||||||
|
if (client.isCryptoEnabled()) {
|
||||||
|
importExportButtons = (
|
||||||
|
<div className='mx_CryptographyPanel_importExportButtons'>
|
||||||
|
<AccessibleButton kind='primary' onClick={this.onExportE2eKeysClicked}>
|
||||||
|
{ _t("Export E2E room keys") }
|
||||||
|
</AccessibleButton>
|
||||||
|
<AccessibleButton kind='primary' onClick={this.onImportE2eKeysClicked}>
|
||||||
|
{ _t("Import E2E room keys") }
|
||||||
|
</AccessibleButton>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let noSendUnverifiedSetting;
|
||||||
|
if (SettingsStore.isEnabled("blacklistUnverifiedDevices")) {
|
||||||
|
noSendUnverifiedSetting = <SettingsFlag
|
||||||
|
name='blacklistUnverifiedDevices'
|
||||||
|
level={SettingLevel.DEVICE}
|
||||||
|
onChange={this.updateBlacklistDevicesFlag}
|
||||||
|
/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='mx_SettingsTab_section mx_CryptographyPanel'>
|
||||||
|
<span className='mx_SettingsTab_subheading'>{ _t("Cryptography") }</span>
|
||||||
|
<ul className='mx_SettingsTab_subsectionText mx_CryptographyPanel_sessionInfo'>
|
||||||
|
<li>
|
||||||
|
<label>{ _t("Session ID:") }</label>
|
||||||
|
<span><code>{ deviceId }</code></span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<label>{ _t("Session key:") }</label>
|
||||||
|
<span><code><b>{ identityKey }</b></code></span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{ importExportButtons }
|
||||||
|
{ noSendUnverifiedSetting }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private onExportE2eKeysClicked = (): void => {
|
||||||
|
Modal.createTrackedDialogAsync('Export E2E Keys', '',
|
||||||
|
import('../../../async-components/views/dialogs/security/ExportE2eKeysDialog'),
|
||||||
|
{ matrixClient: MatrixClientPeg.get() },
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
private onImportE2eKeysClicked = (): void => {
|
||||||
|
Modal.createTrackedDialogAsync('Import E2E Keys', '',
|
||||||
|
import('../../../async-components/views/dialogs/security/ImportE2eKeysDialog'),
|
||||||
|
{ matrixClient: MatrixClientPeg.get() },
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
private updateBlacklistDevicesFlag = (checked): void => {
|
||||||
|
MatrixClientPeg.get().setGlobalBlacklistUnverifiedDevices(checked);
|
||||||
|
};
|
||||||
|
}
|
@ -21,10 +21,8 @@ import { sleep } from "matrix-js-sdk/src/utils";
|
|||||||
import { _t } from "../../../../../languageHandler";
|
import { _t } from "../../../../../languageHandler";
|
||||||
import SdkConfig from "../../../../../SdkConfig";
|
import SdkConfig from "../../../../../SdkConfig";
|
||||||
import { MatrixClientPeg } from "../../../../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../../../MatrixClientPeg";
|
||||||
import * as FormattingUtils from "../../../../../utils/FormattingUtils";
|
|
||||||
import AccessibleButton from "../../../elements/AccessibleButton";
|
import AccessibleButton from "../../../elements/AccessibleButton";
|
||||||
import Analytics from "../../../../../Analytics";
|
import Analytics from "../../../../../Analytics";
|
||||||
import Modal from "../../../../../Modal";
|
|
||||||
import dis from "../../../../../dispatcher/dispatcher";
|
import dis from "../../../../../dispatcher/dispatcher";
|
||||||
import { privateShouldBeEncrypted } from "../../../../../createRoom";
|
import { privateShouldBeEncrypted } from "../../../../../createRoom";
|
||||||
import { SettingLevel } from "../../../../../settings/SettingLevel";
|
import { SettingLevel } from "../../../../../settings/SettingLevel";
|
||||||
@ -37,6 +35,7 @@ import { replaceableComponent } from "../../../../../utils/replaceableComponent"
|
|||||||
import { PosthogAnalytics } from "../../../../../PosthogAnalytics";
|
import { PosthogAnalytics } from "../../../../../PosthogAnalytics";
|
||||||
import { ActionPayload } from "../../../../../dispatcher/payloads";
|
import { ActionPayload } from "../../../../../dispatcher/payloads";
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
import CryptographyPanel from "../../CryptographyPanel";
|
||||||
import DevicesPanel from "../../DevicesPanel";
|
import DevicesPanel from "../../DevicesPanel";
|
||||||
import SettingsFlag from "../../../elements/SettingsFlag";
|
import SettingsFlag from "../../../elements/SettingsFlag";
|
||||||
import CrossSigningPanel from "../../CrossSigningPanel";
|
import CrossSigningPanel from "../../CrossSigningPanel";
|
||||||
@ -112,30 +111,12 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
|
|||||||
dis.unregister(this.dispatcherRef);
|
dis.unregister(this.dispatcherRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateBlacklistDevicesFlag = (checked): void => {
|
|
||||||
MatrixClientPeg.get().setGlobalBlacklistUnverifiedDevices(checked);
|
|
||||||
};
|
|
||||||
|
|
||||||
private updateAnalytics = (checked: boolean): void => {
|
private updateAnalytics = (checked: boolean): void => {
|
||||||
checked ? Analytics.enable() : Analytics.disable();
|
checked ? Analytics.enable() : Analytics.disable();
|
||||||
CountlyAnalytics.instance.enable(/* anonymous = */ !checked);
|
CountlyAnalytics.instance.enable(/* anonymous = */ !checked);
|
||||||
PosthogAnalytics.instance.updateAnonymityFromSettings(MatrixClientPeg.get().getUserId());
|
PosthogAnalytics.instance.updateAnonymityFromSettings(MatrixClientPeg.get().getUserId());
|
||||||
};
|
};
|
||||||
|
|
||||||
private onExportE2eKeysClicked = (): void => {
|
|
||||||
Modal.createTrackedDialogAsync('Export E2E Keys', '',
|
|
||||||
import('../../../../../async-components/views/dialogs/security/ExportE2eKeysDialog'),
|
|
||||||
{ matrixClient: MatrixClientPeg.get() },
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
private onImportE2eKeysClicked = (): void => {
|
|
||||||
Modal.createTrackedDialogAsync('Import E2E Keys', '',
|
|
||||||
import('../../../../../async-components/views/dialogs/security/ImportE2eKeysDialog'),
|
|
||||||
{ matrixClient: MatrixClientPeg.get() },
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
private onGoToUserProfileClick = (): void => {
|
private onGoToUserProfileClick = (): void => {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'view_user_info',
|
action: 'view_user_info',
|
||||||
@ -211,58 +192,6 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
|
|||||||
this.manageInvites(false);
|
this.manageInvites(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
private renderCurrentDeviceInfo(): JSX.Element {
|
|
||||||
const client = MatrixClientPeg.get();
|
|
||||||
const deviceId = client.deviceId;
|
|
||||||
let identityKey = client.getDeviceEd25519Key();
|
|
||||||
if (!identityKey) {
|
|
||||||
identityKey = _t("<not supported>");
|
|
||||||
} else {
|
|
||||||
identityKey = FormattingUtils.formatCryptoKey(identityKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
let importExportButtons = null;
|
|
||||||
if (client.isCryptoEnabled()) {
|
|
||||||
importExportButtons = (
|
|
||||||
<div className='mx_SecurityUserSettingsTab_importExportButtons'>
|
|
||||||
<AccessibleButton kind='primary' onClick={this.onExportE2eKeysClicked}>
|
|
||||||
{ _t("Export E2E room keys") }
|
|
||||||
</AccessibleButton>
|
|
||||||
<AccessibleButton kind='primary' onClick={this.onImportE2eKeysClicked}>
|
|
||||||
{ _t("Import E2E room keys") }
|
|
||||||
</AccessibleButton>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let noSendUnverifiedSetting;
|
|
||||||
if (SettingsStore.isEnabled("blacklistUnverifiedDevices")) {
|
|
||||||
noSendUnverifiedSetting = <SettingsFlag
|
|
||||||
name='blacklistUnverifiedDevices'
|
|
||||||
level={SettingLevel.DEVICE}
|
|
||||||
onChange={this.updateBlacklistDevicesFlag}
|
|
||||||
/>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='mx_SettingsTab_section'>
|
|
||||||
<span className='mx_SettingsTab_subheading'>{ _t("Cryptography") }</span>
|
|
||||||
<ul className='mx_SettingsTab_subsectionText mx_SecurityUserSettingsTab_deviceInfo'>
|
|
||||||
<li>
|
|
||||||
<label>{ _t("Session ID:") }</label>
|
|
||||||
<span><code>{ deviceId }</code></span>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label>{ _t("Session key:") }</label>
|
|
||||||
<span><code><b>{ identityKey }</b></code></span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
{ importExportButtons }
|
|
||||||
{ noSendUnverifiedSetting }
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private renderIgnoredUsers(): JSX.Element {
|
private renderIgnoredUsers(): JSX.Element {
|
||||||
const { waitingUnignored, ignoredUserIds } = this.state;
|
const { waitingUnignored, ignoredUserIds } = this.state;
|
||||||
|
|
||||||
@ -418,7 +347,7 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
|
|||||||
{ secureBackup }
|
{ secureBackup }
|
||||||
{ eventIndex }
|
{ eventIndex }
|
||||||
{ crossSigning }
|
{ crossSigning }
|
||||||
{ this.renderCurrentDeviceInfo() }
|
<CryptographyPanel />
|
||||||
</div>
|
</div>
|
||||||
{ privacySection }
|
{ privacySection }
|
||||||
{ advancedSection }
|
{ advancedSection }
|
||||||
|
@ -1128,6 +1128,11 @@
|
|||||||
"User signing private key:": "User signing private key:",
|
"User signing private key:": "User signing private key:",
|
||||||
"Homeserver feature support:": "Homeserver feature support:",
|
"Homeserver feature support:": "Homeserver feature support:",
|
||||||
"exists": "exists",
|
"exists": "exists",
|
||||||
|
"<not supported>": "<not supported>",
|
||||||
|
"Import E2E room keys": "Import E2E room keys",
|
||||||
|
"Cryptography": "Cryptography",
|
||||||
|
"Session ID:": "Session ID:",
|
||||||
|
"Session key:": "Session key:",
|
||||||
"Your homeserver does not support session management.": "Your homeserver does not support session management.",
|
"Your homeserver does not support session management.": "Your homeserver does not support session management.",
|
||||||
"Unable to load session list": "Unable to load session list",
|
"Unable to load session list": "Unable to load session list",
|
||||||
"Confirm deleting these sessions by using Single Sign On to prove your identity.|other": "Confirm deleting these sessions by using Single Sign On to prove your identity.",
|
"Confirm deleting these sessions by using Single Sign On to prove your identity.|other": "Confirm deleting these sessions by using Single Sign On to prove your identity.",
|
||||||
@ -1393,11 +1398,6 @@
|
|||||||
"Read Marker lifetime (ms)": "Read Marker lifetime (ms)",
|
"Read Marker lifetime (ms)": "Read Marker lifetime (ms)",
|
||||||
"Read Marker off-screen lifetime (ms)": "Read Marker off-screen lifetime (ms)",
|
"Read Marker off-screen lifetime (ms)": "Read Marker off-screen lifetime (ms)",
|
||||||
"Unignore": "Unignore",
|
"Unignore": "Unignore",
|
||||||
"<not supported>": "<not supported>",
|
|
||||||
"Import E2E room keys": "Import E2E room keys",
|
|
||||||
"Cryptography": "Cryptography",
|
|
||||||
"Session ID:": "Session ID:",
|
|
||||||
"Session key:": "Session key:",
|
|
||||||
"You have no ignored users.": "You have no ignored users.",
|
"You have no ignored users.": "You have no ignored users.",
|
||||||
"Bulk options": "Bulk options",
|
"Bulk options": "Bulk options",
|
||||||
"Accept all %(invitedRooms)s invites": "Accept all %(invitedRooms)s invites",
|
"Accept all %(invitedRooms)s invites": "Accept all %(invitedRooms)s invites",
|
||||||
|
38
test/components/views/settings/CryptographyPanel-test.tsx
Normal file
38
test/components/views/settings/CryptographyPanel-test.tsx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import '../../../skinned-sdk';
|
||||||
|
import * as TestUtils from '../../../test-utils';
|
||||||
|
|
||||||
|
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
|
||||||
|
import React, { ReactElement } from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
|
||||||
|
import { MatrixClient } from 'matrix-js-sdk';
|
||||||
|
import CryptographyPanel from '../../../../src/components/views/settings/CryptographyPanel';
|
||||||
|
|
||||||
|
describe('CryptographyPanel', () => {
|
||||||
|
it('shows the session ID and key', () => {
|
||||||
|
const sessionId = "ABCDEFGHIJ";
|
||||||
|
const sessionKey = "AbCDeFghIJK7L/m4nOPqRSTUVW4xyzaBCDef6gHIJkl";
|
||||||
|
const sessionKeyFormatted = "<b>AbCD eFgh IJK7 L/m4 nOPq RSTU VW4x yzaB CDef 6gHI Jkl</b>";
|
||||||
|
|
||||||
|
TestUtils.stubClient();
|
||||||
|
const client: MatrixClient = MatrixClientPeg.get();
|
||||||
|
client.deviceId = sessionId;
|
||||||
|
client.getDeviceEd25519Key = () => sessionKey;
|
||||||
|
|
||||||
|
// When we render the CryptographyPanel
|
||||||
|
const rendered = render(<CryptographyPanel />);
|
||||||
|
|
||||||
|
// Then it displays info about the user's session
|
||||||
|
const codes = rendered.querySelectorAll("code");
|
||||||
|
expect(codes.length).toEqual(2);
|
||||||
|
expect(codes[0].innerHTML).toEqual(sessionId);
|
||||||
|
expect(codes[1].innerHTML).toEqual(sessionKeyFormatted);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function render(component: ReactElement<CryptographyPanel>): HTMLDivElement {
|
||||||
|
const parentDiv = document.createElement('div');
|
||||||
|
document.body.appendChild(parentDiv);
|
||||||
|
ReactDOM.render(component, parentDiv);
|
||||||
|
return parentDiv;
|
||||||
|
}
|
@ -44,7 +44,7 @@ module.exports.enableLazyLoading = async function(session) {
|
|||||||
module.exports.getE2EDeviceFromSettings = async function(session) {
|
module.exports.getE2EDeviceFromSettings = async function(session) {
|
||||||
session.log.step(`gets e2e device/key from settings`);
|
session.log.step(`gets e2e device/key from settings`);
|
||||||
await openSettings(session, "security");
|
await openSettings(session, "security");
|
||||||
const deviceAndKey = await session.queryAll(".mx_SettingsTab_section .mx_SecurityUserSettingsTab_deviceInfo code");
|
const deviceAndKey = await session.queryAll(".mx_SettingsTab_section .mx_CryptographyPanel code");
|
||||||
assert.equal(deviceAndKey.length, 2);
|
assert.equal(deviceAndKey.length, 2);
|
||||||
const id = await (await deviceAndKey[0].getProperty("innerText")).jsonValue();
|
const id = await (await deviceAndKey[0].getProperty("innerText")).jsonValue();
|
||||||
const key = await (await deviceAndKey[1].getProperty("innerText")).jsonValue();
|
const key = await (await deviceAndKey[1].getProperty("innerText")).jsonValue();
|
||||||
|
Loading…
Reference in New Issue
Block a user