diff --git a/res/css/_components.scss b/res/css/_components.scss
index 6890a1ffd1..b959b1f1cd 100644
--- a/res/css/_components.scss
+++ b/res/css/_components.scss
@@ -186,6 +186,7 @@
@import "./views/settings/_AvatarSetting.scss";
@import "./views/settings/_CrossSigningPanel.scss";
@import "./views/settings/_DevicesPanel.scss";
+@import "./views/settings/_E2eAdvancedPanel.scss";
@import "./views/settings/_EmailAddresses.scss";
@import "./views/settings/_IntegrationManager.scss";
@import "./views/settings/_KeyBackupPanel.scss";
diff --git a/res/css/views/settings/_E2eAdvancedPanel.scss b/res/css/views/settings/_E2eAdvancedPanel.scss
new file mode 100644
index 0000000000..9e32685d12
--- /dev/null
+++ b/res/css/views/settings/_E2eAdvancedPanel.scss
@@ -0,0 +1,20 @@
+/*
+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.
+*/
+
+.mx_E2eAdvancedPanel_settingLongDescription {
+ margin-right: 150px;
+}
+
diff --git a/src/MatrixClientPeg.js b/src/MatrixClientPeg.js
index 98fcc85d60..21f05b9759 100644
--- a/src/MatrixClientPeg.js
+++ b/src/MatrixClientPeg.js
@@ -148,6 +148,9 @@ class _MatrixClientPeg {
// check that we have a version of the js-sdk which includes initCrypto
if (!SettingsStore.getValue("lowBandwidth") && this.matrixClient.initCrypto) {
await this.matrixClient.initCrypto();
+ this.matrixClient.setCryptoTrustCrossSignedDevices(
+ !SettingsStore.getValue('e2ee.manuallyVerifyAllSessions'),
+ );
StorageManager.setCryptoInitialised(true);
}
} catch (e) {
diff --git a/src/components/views/rooms/MemberTile.js b/src/components/views/rooms/MemberTile.js
index 1f1d8389b1..a0e900b5fc 100644
--- a/src/components/views/rooms/MemberTile.js
+++ b/src/components/views/rooms/MemberTile.js
@@ -65,6 +65,7 @@ export default createReactClass({
});
if (isRoomEncrypted) {
cli.on("userTrustStatusChanged", this.onUserTrustStatusChanged);
+ cli.on("deviceVerificationChanged", this.onDeviceVerificationChanged);
this.updateE2EStatus();
} else {
// Listen for room to become encrypted
@@ -88,6 +89,7 @@ export default createReactClass({
if (cli) {
cli.removeListener("RoomState.events", this.onRoomStateEvents);
cli.removeListener("userTrustStatusChanged", this.onUserTrustStatusChanged);
+ cli.removeListener("deviceVerificationChanged", this.onDeviceVerificationChanged);
}
},
@@ -110,6 +112,11 @@ export default createReactClass({
this.updateE2EStatus();
},
+ onDeviceVerificationChanged: function(userId, deviceId, deviceInfo) {
+ if (userId !== this.props.member.userId) return;
+ this.updateE2EStatus();
+ },
+
updateE2EStatus: async function() {
const cli = MatrixClientPeg.get();
const { userId } = this.props.member;
diff --git a/src/components/views/settings/E2eAdvancedPanel.js b/src/components/views/settings/E2eAdvancedPanel.js
new file mode 100644
index 0000000000..709465bcb0
--- /dev/null
+++ b/src/components/views/settings/E2eAdvancedPanel.js
@@ -0,0 +1,39 @@
+/*
+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 React from 'react';
+
+import * as sdk from '../../../index';
+import {_t} from "../../../languageHandler";
+import {SettingLevel} from "../../../settings/SettingsStore";
+
+const SETTING_MANUALLY_VERIFY_ALL_SESSIONS = "e2ee.manuallyVerifyAllSessions";
+
+const E2eAdvancedPanel = props => {
+ const SettingsFlag = sdk.getComponent('views.elements.SettingsFlag');
+ return
+
{_t("Advanced")}
+
+
+
{_t(
+ "Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.",
+ )}
+
;
+};
+
+export default E2eAdvancedPanel;
diff --git a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js
index 2e35a6bf6f..3dca6e2490 100644
--- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js
@@ -281,6 +281,8 @@ export default class SecurityUserSettingsTab extends React.Component {
);
}
+ const E2eAdvancedPanel = sdk.getComponent('views.settings.E2eAdvancedPanel');
+
return (
{_t("Security & Privacy")}
@@ -311,6 +313,7 @@ export default class SecurityUserSettingsTab extends React.Component {
{this._renderIgnoredUsers()}
{this._renderManageInvites()}
+
);
}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 7b6acb8e03..c79717e352 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -432,6 +432,7 @@
"Enable message search in encrypted rooms": "Enable message search in encrypted rooms",
"Keep secret storage passphrase in memory for this session": "Keep secret storage passphrase in memory for this session",
"How fast should messages be downloaded.": "How fast should messages be downloaded.",
+ "Manually verify all remote sessions": "Manually verify all remote sessions",
"Collecting app version information": "Collecting app version information",
"Collecting logs": "Collecting logs",
"Uploading report": "Uploading report",
@@ -603,6 +604,7 @@
"Public Name": "Public Name",
"Last seen": "Last seen",
"Failed to set display name": "Failed to set display name",
+ "Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.": "Individually verify each session used by a user to mark it as trusted, not trusting cross-signed devices.",
"Disable Notifications": "Disable Notifications",
"Enable Notifications": "Enable Notifications",
"Securely cache encrypted messages locally for them to appear in search results, using ": "Securely cache encrypted messages locally for them to appear in search results, using ",
diff --git a/src/settings/Settings.js b/src/settings/Settings.js
index 461761dfa2..0d72017878 100644
--- a/src/settings/Settings.js
+++ b/src/settings/Settings.js
@@ -16,6 +16,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
+import {MatrixClient} from 'matrix-js-sdk';
+
import {_td} from '../languageHandler';
import {
AudioNotificationsEnabledController,
@@ -24,6 +26,7 @@ import {
} from "./controllers/NotificationControllers";
import CustomStatusController from "./controllers/CustomStatusController";
import ThemeController from './controllers/ThemeController';
+import PushToMatrixClientController from './controllers/PushToMatrixClientController';
import ReloadOnChangeController from "./controllers/ReloadOnChangeController";
import {RIGHT_PANEL_PHASES} from "../stores/RightPanelStorePhases";
@@ -525,4 +528,12 @@ export const SETTINGS = {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
default: true,
},
+ "e2ee.manuallyVerifyAllSessions": {
+ supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
+ displayName: _td("Manually verify all remote sessions"),
+ default: false,
+ controller: new PushToMatrixClientController(
+ MatrixClient.prototype.setCryptoTrustCrossSignedDevices, true,
+ ),
+ },
};
diff --git a/src/settings/controllers/PushToMatrixClientController.js b/src/settings/controllers/PushToMatrixClientController.js
new file mode 100644
index 0000000000..b7c285227f
--- /dev/null
+++ b/src/settings/controllers/PushToMatrixClientController.js
@@ -0,0 +1,37 @@
+/*
+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 { MatrixClientPeg } from '../../MatrixClientPeg';
+
+/**
+ * When the value changes, call a setter function on the matrix client with the new value
+ */
+export default class PushToMatrixClientController {
+ constructor(setter, inverse) {
+ this._setter = setter;
+ this._inverse = inverse;
+ }
+
+ getValueOverride(level, roomId, calculatedValue, calculatedAtLevel) {
+ return null; // no override
+ }
+
+ onChange(level, roomId, newValue) {
+ // XXX does this work? This surely isn't necessarily the effective value,
+ // but it's what NotificationsEnabledController does...
+ this._setter.call(MatrixClientPeg.get(), this._inverse ? !newValue : newValue);
+ }
+}