diff --git a/src/components/views/settings/E2eAdvancedPanel.js b/src/components/views/settings/E2eAdvancedPanel.js
index 0650630901..a8764fa855 100644
--- a/src/components/views/settings/E2eAdvancedPanel.js
+++ b/src/components/views/settings/E2eAdvancedPanel.js
@@ -19,6 +19,7 @@ import React from 'react';
import * as sdk from '../../../index';
import {_t} from "../../../languageHandler";
import {SettingLevel} from "../../../settings/SettingLevel";
+import SettingsStore from "../../../settings/SettingsStore";
const SETTING_MANUALLY_VERIFY_ALL_SESSIONS = "e2ee.manuallyVerifyAllSessions";
@@ -37,3 +38,7 @@ const E2eAdvancedPanel = props => {
};
export default E2eAdvancedPanel;
+
+export function isE2eAdvancedPanelPossible(): boolean {
+ return SettingsStore.isEnabled(SETTING_MANUALLY_VERIFY_ALL_SESSIONS);
+}
diff --git a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js
index 48115146f1..0a0c693158 100644
--- a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js
+++ b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.js
@@ -24,6 +24,7 @@ import Modal from "../../../../../Modal";
import QuestionDialog from "../../../dialogs/QuestionDialog";
import StyledRadioGroup from '../../../elements/StyledRadioGroup';
import {SettingLevel} from "../../../../../settings/SettingLevel";
+import SettingsStore from "../../../../../settings/SettingsStore";
export default class SecurityRoomSettingsTab extends React.Component {
static propTypes = {
@@ -340,10 +341,13 @@ export default class SecurityRoomSettingsTab extends React.Component {
const canEnableEncryption = !isEncrypted && hasEncryptionPermission;
let encryptionSettings = null;
- if (isEncrypted) {
- encryptionSettings = ;
+ if (isEncrypted && SettingsStore.isEnabled("blacklistUnverifiedDevices")) {
+ encryptionSettings = ;
}
return (
diff --git a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js
index 9984baeb13..61402e8881 100644
--- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js
@@ -32,6 +32,7 @@ import {SettingLevel} from "../../../../../settings/SettingLevel";
import SecureBackupPanel from "../../SecureBackupPanel";
import SettingsStore from "../../../../../settings/SettingsStore";
import {UIFeature} from "../../../../../settings/UIFeature";
+import {isE2eAdvancedPanelPossible} from "../../E2eAdvancedPanel";
export class IgnoredUser extends React.Component {
static propTypes = {
@@ -219,6 +220,15 @@ export default class SecurityUserSettingsTab extends React.Component {
);
}
+ let noSendUnverifiedSetting;
+ if (SettingsStore.isEnabled("blacklistUnverifiedDevices")) {
+ noSendUnverifiedSetting = ;
+ }
+
return (
{_t("Cryptography")}
@@ -233,8 +243,7 @@ export default class SecurityUserSettingsTab extends React.Component {
{importExportButtons}
-
+ {noSendUnverifiedSetting}
);
}
@@ -355,14 +364,20 @@ export default class SecurityUserSettingsTab extends React.Component {
const E2eAdvancedPanel = sdk.getComponent('views.settings.E2eAdvancedPanel');
let advancedSection;
if (SettingsStore.getValue(UIFeature.AdvancedSettings)) {
- advancedSection = <>
- {_t("Advanced")}
-
- {this._renderIgnoredUsers()}
- {this._renderManageInvites()}
-
-
- >;
+ const ignoreUsersPanel = this._renderIgnoredUsers();
+ const invitesPanel = this._renderManageInvites();
+ const e2ePanel = isE2eAdvancedPanelPossible() ? : null;
+ // only show the section if there's something to show
+ if (ignoreUsersPanel || invitesPanel || e2ePanel) {
+ advancedSection = <>
+ {_t("Advanced")}
+
+ {ignoreUsersPanel}
+ {invitesPanel}
+ {e2ePanel}
+
+ >;
+ }
}
return (
diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts
index 16366aaa01..737c882919 100644
--- a/src/settings/Settings.ts
+++ b/src/settings/Settings.ts
@@ -34,6 +34,7 @@ import SettingController from "./controllers/SettingController";
import { RightPanelPhases } from "../stores/RightPanelStorePhases";
import UIFeatureController from "./controllers/UIFeatureController";
import { UIFeature } from "./UIFeature";
+import { OrderedMultiController } from "./controllers/OrderedMultiController";
// These are just a bunch of helper arrays to avoid copy/pasting a bunch of times
const LEVELS_ROOM_SETTINGS = [
@@ -436,6 +437,7 @@ export const SETTINGS: {[setting: string]: ISetting} = {
"room-device": _td('Never send encrypted messages to unverified sessions in this room from this session'),
},
default: false,
+ controller: new UIFeatureController(UIFeature.AdvancedEncryption),
},
"urlPreviewsEnabled": {
supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM,
@@ -591,9 +593,15 @@ export const SETTINGS: {[setting: string]: ISetting} = {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
displayName: _td("Manually verify all remote sessions"),
default: false,
- controller: new PushToMatrixClientController(
- MatrixClient.prototype.setCryptoTrustCrossSignedDevices, true,
- ),
+ controller: new OrderedMultiController([
+ // Apply the feature controller first to ensure that the setting doesn't
+ // show up and can't be toggled. PushToMatrixClientController doesn't
+ // do any overrides anyways.
+ new UIFeatureController(UIFeature.AdvancedEncryption),
+ new PushToMatrixClientController(
+ MatrixClient.prototype.setCryptoTrustCrossSignedDevices, true,
+ ),
+ ]),
},
"ircDisplayNameWidth": {
// We specifically want to have room-device > device so that users may set a device default
@@ -612,6 +620,10 @@ export const SETTINGS: {[setting: string]: ISetting} = {
supportedLevels: LEVELS_ROOM_OR_ACCOUNT,
default: {},
},
+ [UIFeature.AdvancedEncryption]: {
+ supportedLevels: LEVELS_UI_FEATURE,
+ default: true,
+ },
[UIFeature.URLPreviews]: {
supportedLevels: LEVELS_UI_FEATURE,
default: true,
diff --git a/src/settings/UIFeature.ts b/src/settings/UIFeature.ts
index 57aefa3a78..231752e19c 100644
--- a/src/settings/UIFeature.ts
+++ b/src/settings/UIFeature.ts
@@ -16,6 +16,7 @@ limitations under the License.
// see settings.md for documentation on conventions
export enum UIFeature {
+ AdvancedEncryption = "UIFeature.advancedEncryption",
URLPreviews = "UIFeature.urlPreviews",
Widgets = "UIFeature.widgets",
Voip = "UIFeature.voip",
diff --git a/src/settings/controllers/OrderedMultiController.ts b/src/settings/controllers/OrderedMultiController.ts
new file mode 100644
index 0000000000..fb94d6d7ef
--- /dev/null
+++ b/src/settings/controllers/OrderedMultiController.ts
@@ -0,0 +1,59 @@
+/*
+Copyright 2020 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 SettingController from "./SettingController";
+import { SettingLevel } from "../SettingLevel";
+
+/**
+ * Allows for multiple controllers to affect a setting. The first controller
+ * provided to this class which overrides the setting value will affect
+ * the value - other controllers are not called. Change notification handlers
+ * are proxied through to all controllers.
+ *
+ * Similarly, the first controller which indicates that a setting is disabled
+ * will be used - other controllers will not be considered.
+ */
+export class OrderedMultiController extends SettingController {
+ constructor(public readonly controllers: SettingController[]) {
+ super();
+ }
+
+ public getValueOverride(
+ level: SettingLevel,
+ roomId: string,
+ calculatedValue: any,
+ calculatedAtLevel: SettingLevel,
+ ): any {
+ for (const controller of this.controllers) {
+ const override = controller.getValueOverride(level, roomId, calculatedValue, calculatedAtLevel);
+ if (override !== undefined && override !== null) return override;
+ }
+ return null; // no override
+ }
+
+ public onChange(level: SettingLevel, roomId: string, newValue: any) {
+ for (const controller of this.controllers) {
+ controller.onChange(level, roomId, newValue);
+ }
+ }
+
+ public get settingDisabled(): boolean {
+ for (const controller of this.controllers) {
+ if (controller.settingDisabled) return true;
+ }
+ return false;
+ }
+}