2019-01-24 15:47:04 -07:00
|
|
|
|
/*
|
|
|
|
|
|
Copyright 2019 New Vector Ltd
|
2020-07-10 19:07:11 +01:00
|
|
|
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
2019-01-24 15:47:04 -07:00
|
|
|
|
|
|
|
|
|
|
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 PropTypes from 'prop-types';
|
2019-02-22 10:47:18 -07:00
|
|
|
|
import {_t} from "../../../../../languageHandler";
|
2020-07-10 19:07:11 +01:00
|
|
|
|
import SdkConfig from "../../../../../SdkConfig";
|
2019-12-20 14:13:46 -07:00
|
|
|
|
import {MatrixClientPeg} from "../../../../../MatrixClientPeg";
|
2019-02-22 10:47:18 -07:00
|
|
|
|
import * as FormattingUtils from "../../../../../utils/FormattingUtils";
|
|
|
|
|
|
import AccessibleButton from "../../../elements/AccessibleButton";
|
|
|
|
|
|
import Analytics from "../../../../../Analytics";
|
|
|
|
|
|
import Modal from "../../../../../Modal";
|
2019-12-19 18:19:56 -07:00
|
|
|
|
import * as sdk from "../../../../..";
|
2019-11-12 11:46:58 +00:00
|
|
|
|
import {sleep} from "../../../../../utils/promise";
|
2020-05-13 20:41:41 -06:00
|
|
|
|
import dis from "../../../../../dispatcher/dispatcher";
|
2020-06-01 23:09:14 +01:00
|
|
|
|
import {privateShouldBeEncrypted} from "../../../../../createRoom";
|
2020-07-28 11:53:43 -06:00
|
|
|
|
import {SettingLevel} from "../../../../../settings/SettingLevel";
|
2020-09-04 11:37:06 +01:00
|
|
|
|
import SecureBackupPanel from "../../SecureBackupPanel";
|
2020-09-16 12:14:33 +01:00
|
|
|
|
import SettingsStore from "../../../../../settings/SettingsStore";
|
|
|
|
|
|
import {UIFeature} from "../../../../../settings/UIFeature";
|
2020-09-18 11:33:02 -06:00
|
|
|
|
import {isE2eAdvancedPanelPossible} from "../../E2eAdvancedPanel";
|
2020-10-29 15:53:14 +00:00
|
|
|
|
import CountlyAnalytics from "../../../../../CountlyAnalytics";
|
2021-03-08 20:20:07 -07:00
|
|
|
|
import {replaceableComponent} from "../../../../../utils/replaceableComponent";
|
2019-01-24 15:47:04 -07:00
|
|
|
|
|
|
|
|
|
|
export class IgnoredUser extends React.Component {
|
|
|
|
|
|
static propTypes = {
|
|
|
|
|
|
userId: PropTypes.string.isRequired,
|
|
|
|
|
|
onUnignored: PropTypes.func.isRequired,
|
2020-04-22 16:44:47 +02:00
|
|
|
|
inProgress: PropTypes.bool.isRequired,
|
2019-01-24 15:47:04 -07:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
_onUnignoreClicked = (e) => {
|
|
|
|
|
|
this.props.onUnignored(this.props.userId);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
render() {
|
2019-12-13 14:31:34 +00:00
|
|
|
|
const id = `mx_SecurityUserSettingsTab_ignoredUser_${this.props.userId}`;
|
2019-01-24 15:47:04 -07:00
|
|
|
|
return (
|
2019-02-22 10:47:18 -07:00
|
|
|
|
<div className='mx_SecurityUserSettingsTab_ignoredUser'>
|
2020-04-22 16:00:27 +02:00
|
|
|
|
<AccessibleButton onClick={this._onUnignoreClicked} kind='primary_sm' aria-describedby={id} disabled={this.props.inProgress}>
|
2019-12-13 14:31:34 +00:00
|
|
|
|
{ _t('Unignore') }
|
2019-01-24 15:47:04 -07:00
|
|
|
|
</AccessibleButton>
|
2019-12-13 14:31:34 +00:00
|
|
|
|
<span id={id}>{ this.props.userId }</span>
|
2019-01-24 15:47:04 -07:00
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-03-08 20:20:07 -07:00
|
|
|
|
@replaceableComponent("views.settings.tabs.user.SecurityUserSettingsTab")
|
2019-02-22 10:47:18 -07:00
|
|
|
|
export default class SecurityUserSettingsTab extends React.Component {
|
2020-04-27 14:25:47 +01:00
|
|
|
|
static propTypes = {
|
|
|
|
|
|
closeSettingsFn: PropTypes.func.isRequired,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2019-01-24 15:47:04 -07:00
|
|
|
|
constructor() {
|
|
|
|
|
|
super();
|
|
|
|
|
|
|
2019-03-06 13:58:47 +00:00
|
|
|
|
// Get number of rooms we're invited to
|
|
|
|
|
|
const invitedRooms = this._getInvitedRooms();
|
|
|
|
|
|
|
2019-01-24 15:47:04 -07:00
|
|
|
|
this.state = {
|
|
|
|
|
|
ignoredUserIds: MatrixClientPeg.get().getIgnoredUsers(),
|
2020-04-22 16:00:27 +02:00
|
|
|
|
waitingUnignored: [],
|
2019-03-06 13:58:47 +00:00
|
|
|
|
managingInvites: false,
|
|
|
|
|
|
invitedRoomAmt: invitedRooms.length,
|
2019-01-24 15:47:04 -07:00
|
|
|
|
};
|
2020-04-22 01:31:35 +02:00
|
|
|
|
|
|
|
|
|
|
this._onAction = this._onAction.bind(this);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-04-22 16:16:49 +02:00
|
|
|
|
|
2020-04-22 01:31:35 +02:00
|
|
|
|
_onAction({action}) {
|
2020-04-22 16:44:47 +02:00
|
|
|
|
if (action === "ignore_state_changed") {
|
|
|
|
|
|
const ignoredUserIds = MatrixClientPeg.get().getIgnoredUsers();
|
|
|
|
|
|
const newWaitingUnignored = this.state.waitingUnignored.filter(e=> ignoredUserIds.includes(e));
|
|
|
|
|
|
this.setState({ignoredUserIds, waitingUnignored: newWaitingUnignored});
|
2020-04-22 01:31:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
componentDidMount() {
|
2020-04-22 16:44:47 +02:00
|
|
|
|
this.dispatcherRef = dis.register(this._onAction);
|
2020-04-22 01:31:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
|
|
dis.unregister(this.dispatcherRef);
|
2019-01-24 15:47:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_updateBlacklistDevicesFlag = (checked) => {
|
|
|
|
|
|
MatrixClientPeg.get().setGlobalBlacklistUnverifiedDevices(checked);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
_updateAnalytics = (checked) => {
|
|
|
|
|
|
checked ? Analytics.enable() : Analytics.disable();
|
2020-10-30 14:27:14 +00:00
|
|
|
|
CountlyAnalytics.instance.enable(/* anonymous = */ !checked);
|
2019-01-24 15:47:04 -07:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
_onExportE2eKeysClicked = () => {
|
|
|
|
|
|
Modal.createTrackedDialogAsync('Export E2E Keys', '',
|
2020-09-10 13:56:07 +01:00
|
|
|
|
import('../../../../../async-components/views/dialogs/security/ExportE2eKeysDialog'),
|
2019-01-24 15:47:04 -07:00
|
|
|
|
{matrixClient: MatrixClientPeg.get()},
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
_onImportE2eKeysClicked = () => {
|
|
|
|
|
|
Modal.createTrackedDialogAsync('Import E2E Keys', '',
|
2020-09-10 13:56:07 +01:00
|
|
|
|
import('../../../../../async-components/views/dialogs/security/ImportE2eKeysDialog'),
|
2019-01-24 15:47:04 -07:00
|
|
|
|
{matrixClient: MatrixClientPeg.get()},
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2020-04-27 14:25:47 +01:00
|
|
|
|
_onGoToUserProfileClick = () => {
|
2020-05-04 15:41:26 -06:00
|
|
|
|
dis.dispatch({
|
|
|
|
|
|
action: 'view_user_info',
|
|
|
|
|
|
userId: MatrixClientPeg.get().getUserId(),
|
|
|
|
|
|
});
|
2020-04-27 14:25:47 +01:00
|
|
|
|
this.props.closeSettingsFn();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-01-24 15:47:04 -07:00
|
|
|
|
_onUserUnignored = async (userId) => {
|
2020-04-22 16:44:47 +02:00
|
|
|
|
const {ignoredUserIds, waitingUnignored} = this.state;
|
2020-04-22 20:03:22 +02:00
|
|
|
|
const currentlyIgnoredUserIds = ignoredUserIds.filter(e => !waitingUnignored.includes(e));
|
2020-04-22 16:00:27 +02:00
|
|
|
|
|
|
|
|
|
|
const index = currentlyIgnoredUserIds.indexOf(userId);
|
2019-01-24 15:47:04 -07:00
|
|
|
|
if (index !== -1) {
|
2020-04-22 16:00:27 +02:00
|
|
|
|
currentlyIgnoredUserIds.splice(index, 1);
|
2020-04-22 20:03:13 +02:00
|
|
|
|
this.setState(({waitingUnignored}) => ({waitingUnignored: [...waitingUnignored, userId]}));
|
2020-04-22 16:00:27 +02:00
|
|
|
|
MatrixClientPeg.get().setIgnoredUsers(currentlyIgnoredUserIds);
|
2019-01-24 15:47:04 -07:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2019-03-06 13:58:47 +00:00
|
|
|
|
_getInvitedRooms = () => {
|
|
|
|
|
|
return MatrixClientPeg.get().getRooms().filter((r) => {
|
|
|
|
|
|
return r.hasMembershipState(MatrixClientPeg.get().getUserId(), "invite");
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
_manageInvites = async (accept) => {
|
2019-01-24 15:47:04 -07:00
|
|
|
|
this.setState({
|
2019-03-06 13:58:47 +00:00
|
|
|
|
managingInvites: true,
|
2019-01-24 15:47:04 -07:00
|
|
|
|
});
|
2019-03-06 13:58:47 +00:00
|
|
|
|
|
|
|
|
|
|
// Compile array of invitation room ids
|
|
|
|
|
|
const invitedRoomIds = this._getInvitedRooms().map((room) => {
|
|
|
|
|
|
return room.roomId;
|
2019-01-24 15:47:04 -07:00
|
|
|
|
});
|
2019-03-06 13:58:47 +00:00
|
|
|
|
|
|
|
|
|
|
// Execute all acceptances/rejections sequentially
|
|
|
|
|
|
const self = this;
|
|
|
|
|
|
const cli = MatrixClientPeg.get();
|
|
|
|
|
|
const action = accept ? cli.joinRoom.bind(cli) : cli.leave.bind(cli);
|
|
|
|
|
|
for (let i = 0; i < invitedRoomIds.length; i++) {
|
|
|
|
|
|
const roomId = invitedRoomIds[i];
|
|
|
|
|
|
|
|
|
|
|
|
// Accept/reject invite
|
|
|
|
|
|
await action(roomId).then(() => {
|
|
|
|
|
|
// No error, update invited rooms button
|
|
|
|
|
|
this.setState({invitedRoomAmt: self.state.invitedRoomAmt - 1});
|
|
|
|
|
|
}, async (e) => {
|
|
|
|
|
|
// Action failure
|
|
|
|
|
|
if (e.errcode === "M_LIMIT_EXCEEDED") {
|
|
|
|
|
|
// Add a delay between each invite change in order to avoid rate
|
|
|
|
|
|
// limiting by the server.
|
2019-11-12 11:46:58 +00:00
|
|
|
|
await sleep(e.retry_after_ms || 2500);
|
2019-03-06 13:58:47 +00:00
|
|
|
|
|
|
|
|
|
|
// Redo last action
|
|
|
|
|
|
i--;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Print out error with joining/leaving room
|
|
|
|
|
|
console.warn(e);
|
|
|
|
|
|
}
|
2019-01-24 15:47:04 -07:00
|
|
|
|
});
|
2019-03-06 13:58:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
this.setState({
|
|
|
|
|
|
managingInvites: false,
|
2019-01-24 15:47:04 -07:00
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2019-03-06 13:58:47 +00:00
|
|
|
|
_onAcceptAllInvitesClicked = (ev) => {
|
|
|
|
|
|
this._manageInvites(true);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
_onRejectAllInvitesClicked = (ev) => {
|
|
|
|
|
|
this._manageInvites(false);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2019-01-24 15:47:04 -07:00
|
|
|
|
_renderCurrentDeviceInfo() {
|
|
|
|
|
|
const SettingsFlag = sdk.getComponent('views.elements.SettingsFlag');
|
|
|
|
|
|
|
|
|
|
|
|
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 = (
|
2019-02-22 10:47:18 -07:00
|
|
|
|
<div className='mx_SecurityUserSettingsTab_importExportButtons'>
|
2019-01-24 15:47:04 -07:00
|
|
|
|
<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>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-18 11:33:02 -06:00
|
|
|
|
let noSendUnverifiedSetting;
|
|
|
|
|
|
if (SettingsStore.isEnabled("blacklistUnverifiedDevices")) {
|
|
|
|
|
|
noSendUnverifiedSetting = <SettingsFlag
|
|
|
|
|
|
name='blacklistUnverifiedDevices'
|
|
|
|
|
|
level={SettingLevel.DEVICE}
|
|
|
|
|
|
onChange={this._updateBlacklistDevicesFlag}
|
|
|
|
|
|
/>;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-01-24 15:47:04 -07:00
|
|
|
|
return (
|
|
|
|
|
|
<div className='mx_SettingsTab_section'>
|
|
|
|
|
|
<span className='mx_SettingsTab_subheading'>{_t("Cryptography")}</span>
|
2019-02-22 10:47:18 -07:00
|
|
|
|
<ul className='mx_SettingsTab_subsectionText mx_SecurityUserSettingsTab_deviceInfo'>
|
2019-01-24 15:47:04 -07:00
|
|
|
|
<li>
|
2020-01-29 15:48:25 +00:00
|
|
|
|
<label>{_t("Session ID:")}</label>
|
2019-01-24 15:47:04 -07:00
|
|
|
|
<span><code>{deviceId}</code></span>
|
|
|
|
|
|
</li>
|
|
|
|
|
|
<li>
|
2020-01-29 15:48:25 +00:00
|
|
|
|
<label>{_t("Session key:")}</label>
|
2019-01-24 15:47:04 -07:00
|
|
|
|
<span><code><b>{identityKey}</b></code></span>
|
|
|
|
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
|
|
|
|
{importExportButtons}
|
2020-09-18 11:33:02 -06:00
|
|
|
|
{noSendUnverifiedSetting}
|
2019-01-24 15:47:04 -07:00
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_renderIgnoredUsers() {
|
2020-04-22 16:00:27 +02:00
|
|
|
|
const {waitingUnignored, ignoredUserIds} = this.state;
|
2019-01-24 15:47:04 -07:00
|
|
|
|
|
2020-04-22 16:00:27 +02:00
|
|
|
|
if (!ignoredUserIds || ignoredUserIds.length === 0) return null;
|
|
|
|
|
|
|
2021-04-27 17:23:27 +02:00
|
|
|
|
const userIds = ignoredUserIds.map((u) => <IgnoredUser
|
|
|
|
|
|
userId={u}
|
|
|
|
|
|
onUnignored={this._onUserUnignored}
|
|
|
|
|
|
key={u}
|
|
|
|
|
|
inProgress={waitingUnignored.includes(u)}
|
|
|
|
|
|
/>);
|
2019-01-24 15:47:04 -07:00
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div className='mx_SettingsTab_section'>
|
|
|
|
|
|
<span className='mx_SettingsTab_subheading'>{_t('Ignored users')}</span>
|
|
|
|
|
|
<div className='mx_SettingsTab_subsectionText'>
|
|
|
|
|
|
{userIds}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-03-06 13:58:47 +00:00
|
|
|
|
_renderManageInvites() {
|
|
|
|
|
|
if (this.state.invitedRoomAmt === 0) {
|
2019-01-24 15:47:04 -07:00
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-03-06 13:58:47 +00:00
|
|
|
|
const invitedRooms = this._getInvitedRooms();
|
|
|
|
|
|
const InlineSpinner = sdk.getComponent('elements.InlineSpinner');
|
|
|
|
|
|
const onClickAccept = this._onAcceptAllInvitesClicked.bind(this, invitedRooms);
|
|
|
|
|
|
const onClickReject = this._onRejectAllInvitesClicked.bind(this, invitedRooms);
|
2019-01-24 15:47:04 -07:00
|
|
|
|
return (
|
2019-03-06 13:58:47 +00:00
|
|
|
|
<div className='mx_SettingsTab_section mx_SecurityUserSettingsTab_bulkOptions'>
|
2019-01-24 15:47:04 -07:00
|
|
|
|
<span className='mx_SettingsTab_subheading'>{_t('Bulk options')}</span>
|
2019-03-06 13:58:47 +00:00
|
|
|
|
<AccessibleButton onClick={onClickAccept} kind='primary' disabled={this.state.managingInvites}>
|
|
|
|
|
|
{_t("Accept all %(invitedRooms)s invites", {invitedRooms: this.state.invitedRoomAmt})}
|
2019-01-24 15:47:04 -07:00
|
|
|
|
</AccessibleButton>
|
2019-03-06 13:58:47 +00:00
|
|
|
|
<AccessibleButton onClick={onClickReject} kind='danger' disabled={this.state.managingInvites}>
|
|
|
|
|
|
{_t("Reject all %(invitedRooms)s invites", {invitedRooms: this.state.invitedRoomAmt})}
|
|
|
|
|
|
</AccessibleButton>
|
|
|
|
|
|
{this.state.managingInvites ? <InlineSpinner /> : <div />}
|
2019-01-24 15:47:04 -07:00
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
render() {
|
2020-07-10 19:07:11 +01:00
|
|
|
|
const brand = SdkConfig.get().brand;
|
2019-01-24 15:47:04 -07:00
|
|
|
|
const DevicesPanel = sdk.getComponent('views.settings.DevicesPanel');
|
|
|
|
|
|
const SettingsFlag = sdk.getComponent('views.elements.SettingsFlag');
|
2020-01-21 10:06:04 +01:00
|
|
|
|
const EventIndexPanel = sdk.getComponent('views.settings.EventIndexPanel');
|
2019-01-24 15:47:04 -07:00
|
|
|
|
|
2020-09-04 11:37:06 +01:00
|
|
|
|
const secureBackup = (
|
2019-02-08 16:58:09 +00:00
|
|
|
|
<div className='mx_SettingsTab_section'>
|
2020-09-04 11:37:06 +01:00
|
|
|
|
<span className="mx_SettingsTab_subheading">{_t("Secure Backup")}</span>
|
2019-02-08 16:58:09 +00:00
|
|
|
|
<div className='mx_SettingsTab_subsectionText'>
|
2020-09-04 11:37:06 +01:00
|
|
|
|
<SecureBackupPanel />
|
2019-01-24 15:47:04 -07:00
|
|
|
|
</div>
|
2019-02-08 16:58:09 +00:00
|
|
|
|
</div>
|
|
|
|
|
|
);
|
2019-01-24 15:47:04 -07:00
|
|
|
|
|
2020-04-22 11:05:43 -06:00
|
|
|
|
const eventIndex = (
|
2020-04-22 10:58:11 -06:00
|
|
|
|
<div className="mx_SettingsTab_section">
|
|
|
|
|
|
<span className="mx_SettingsTab_subheading">{_t("Message search")}</span>
|
|
|
|
|
|
<EventIndexPanel />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
2020-01-21 10:06:04 +01:00
|
|
|
|
|
2019-11-28 16:45:29 +00:00
|
|
|
|
// XXX: There's no such panel in the current cross-signing designs, but
|
|
|
|
|
|
// it's useful to have for testing the feature. If there's no interest
|
|
|
|
|
|
// in having advanced details here once all flows are implemented, we
|
|
|
|
|
|
// can remove this.
|
|
|
|
|
|
const CrossSigningPanel = sdk.getComponent('views.settings.CrossSigningPanel');
|
2020-05-27 10:28:25 +01:00
|
|
|
|
const crossSigning = (
|
2020-09-16 12:14:33 +01:00
|
|
|
|
<div className='mx_SettingsTab_section'>
|
|
|
|
|
|
<span className="mx_SettingsTab_subheading">{_t("Cross-signing")}</span>
|
|
|
|
|
|
<div className='mx_SettingsTab_subsectionText'>
|
|
|
|
|
|
<CrossSigningPanel />
|
2019-11-28 16:45:29 +00:00
|
|
|
|
</div>
|
2020-09-16 12:14:33 +01:00
|
|
|
|
</div>
|
|
|
|
|
|
);
|
2020-03-25 18:38:12 +00:00
|
|
|
|
|
2020-06-01 23:09:14 +01:00
|
|
|
|
let warning;
|
|
|
|
|
|
if (!privateShouldBeEncrypted()) {
|
|
|
|
|
|
warning = <div className="mx_SecurityUserSettingsTab_warning">
|
|
|
|
|
|
{ _t("Your server admin has disabled end-to-end encryption by default " +
|
|
|
|
|
|
"in private rooms & Direct Messages.") }
|
|
|
|
|
|
</div>;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-16 10:37:15 +01:00
|
|
|
|
let privacySection;
|
2020-10-30 13:42:35 +00:00
|
|
|
|
if (Analytics.canEnable() || CountlyAnalytics.instance.canEnable()) {
|
2020-09-16 10:37:15 +01:00
|
|
|
|
privacySection = <React.Fragment>
|
|
|
|
|
|
<div className="mx_SettingsTab_heading">{_t("Privacy")}</div>
|
|
|
|
|
|
<div className="mx_SettingsTab_section">
|
|
|
|
|
|
<span className="mx_SettingsTab_subheading">{_t("Analytics")}</span>
|
|
|
|
|
|
<div className="mx_SettingsTab_subsectionText">
|
|
|
|
|
|
{_t(
|
|
|
|
|
|
"%(brand)s collects anonymous analytics to allow us to improve the application.",
|
|
|
|
|
|
{ brand },
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{_t("Privacy is important to us, so we don't collect any personal or " +
|
|
|
|
|
|
"identifiable data for our analytics.")}
|
|
|
|
|
|
<AccessibleButton className="mx_SettingsTab_linkBtn" onClick={Analytics.showDetailsModal}>
|
|
|
|
|
|
{_t("Learn more about how we use analytics.")}
|
|
|
|
|
|
</AccessibleButton>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<SettingsFlag name="analyticsOptIn" level={SettingLevel.DEVICE} onChange={this._updateAnalytics} />
|
2020-09-16 10:29:21 +01:00
|
|
|
|
</div>
|
2020-09-16 10:37:15 +01:00
|
|
|
|
</React.Fragment>;
|
2020-09-16 10:29:21 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-16 12:14:33 +01:00
|
|
|
|
const E2eAdvancedPanel = sdk.getComponent('views.settings.E2eAdvancedPanel');
|
|
|
|
|
|
let advancedSection;
|
|
|
|
|
|
if (SettingsStore.getValue(UIFeature.AdvancedSettings)) {
|
2020-09-18 11:33:02 -06:00
|
|
|
|
const ignoreUsersPanel = this._renderIgnoredUsers();
|
|
|
|
|
|
const invitesPanel = this._renderManageInvites();
|
|
|
|
|
|
const e2ePanel = isE2eAdvancedPanelPossible() ? <E2eAdvancedPanel /> : null;
|
|
|
|
|
|
// only show the section if there's something to show
|
|
|
|
|
|
if (ignoreUsersPanel || invitesPanel || e2ePanel) {
|
|
|
|
|
|
advancedSection = <>
|
|
|
|
|
|
<div className="mx_SettingsTab_heading">{_t("Advanced")}</div>
|
|
|
|
|
|
<div className="mx_SettingsTab_section">
|
|
|
|
|
|
{ignoreUsersPanel}
|
|
|
|
|
|
{invitesPanel}
|
|
|
|
|
|
{e2ePanel}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</>;
|
|
|
|
|
|
}
|
2020-09-16 12:14:33 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-01-24 15:47:04 -07:00
|
|
|
|
return (
|
2019-02-22 10:47:18 -07:00
|
|
|
|
<div className="mx_SettingsTab mx_SecurityUserSettingsTab">
|
2020-06-01 23:09:14 +01:00
|
|
|
|
{warning}
|
2020-09-03 15:20:46 +01:00
|
|
|
|
<div className="mx_SettingsTab_heading">{_t("Where you’re logged in")}</div>
|
2019-01-24 15:47:04 -07:00
|
|
|
|
<div className="mx_SettingsTab_section">
|
2020-04-27 14:35:32 +01:00
|
|
|
|
<span>
|
|
|
|
|
|
{_t(
|
|
|
|
|
|
"Manage the names of and sign out of your sessions below or " +
|
|
|
|
|
|
"<a>verify them in your User Profile</a>.", {},
|
|
|
|
|
|
{
|
2020-04-28 17:49:10 +01:00
|
|
|
|
a: sub => <AccessibleButton kind="link" onClick={this._onGoToUserProfileClick}>
|
|
|
|
|
|
{sub}
|
|
|
|
|
|
</AccessibleButton>,
|
2020-04-27 14:43:17 +01:00
|
|
|
|
},
|
2020-04-27 14:35:32 +01:00
|
|
|
|
)}
|
|
|
|
|
|
</span>
|
2019-01-24 15:47:04 -07:00
|
|
|
|
<div className='mx_SettingsTab_subsectionText'>
|
2020-01-29 15:48:25 +00:00
|
|
|
|
{_t("A session's public name is visible to people you communicate with")}
|
2019-01-24 15:47:04 -07:00
|
|
|
|
<DevicesPanel />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2020-09-03 15:20:46 +01:00
|
|
|
|
<div className="mx_SettingsTab_heading">{_t("Encryption")}</div>
|
|
|
|
|
|
<div className="mx_SettingsTab_section">
|
2020-09-04 11:37:06 +01:00
|
|
|
|
{secureBackup}
|
2020-09-03 15:20:46 +01:00
|
|
|
|
{eventIndex}
|
|
|
|
|
|
{crossSigning}
|
|
|
|
|
|
{this._renderCurrentDeviceInfo()}
|
|
|
|
|
|
</div>
|
2020-09-16 10:37:15 +01:00
|
|
|
|
{ privacySection }
|
2020-09-16 12:14:33 +01:00
|
|
|
|
{ advancedSection }
|
2019-01-24 15:47:04 -07:00
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|