diff --git a/src/components/views/right_panel/UserInfo.js b/src/components/views/right_panel/UserInfo.js
index 24c5489c4f..4219da690e 100644
--- a/src/components/views/right_panel/UserInfo.js
+++ b/src/components/views/right_panel/UserInfo.js
@@ -25,7 +25,7 @@ import dis from '../../../dispatcher';
import Modal from '../../../Modal';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
-import createRoom, {findDMForUser} from '../../../createRoom';
+import createRoom from '../../../createRoom';
import DMRoomMap from '../../../utils/DMRoomMap';
import AccessibleButton from '../elements/AccessibleButton';
import SdkConfig from '../../../SdkConfig';
@@ -43,6 +43,7 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext";
import {RIGHT_PANEL_PHASES} from "../../../stores/RightPanelStorePhases";
import EncryptionPanel from "./EncryptionPanel";
import { useAsyncMemo } from '../../../hooks/useAsyncMemo';
+import { verifyUser, legacyVerifyUser, verifyDevice } from '../../../verification';
const _disambiguateDevices = (devices) => {
const names = Object.create(null);
@@ -153,66 +154,6 @@ function useHasCrossSigningKeys(cli, member, canVerify, setUpdating) {
}, [cli, member, canVerify], false);
}
-async function verifyDevice(userId, device) {
- const cli = MatrixClientPeg.get();
- const member = cli.getUser(userId);
- const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
- Modal.createTrackedDialog("Verification warning", "unverified session", QuestionDialog, {
- headerImage: require("../../../../res/img/e2e/warning.svg"),
- title: _t("Not Trusted"),
- description:
-
{_t("%(name)s (%(userId)s) signed in to a new session without verifying it:", {name: member.displayName, userId})}
-
{device.getDisplayName()} ({device.deviceId})
-
{_t("Ask this user to verify their session, or manually verify it below.")}
-
,
- onFinished: async (doneClicked) => {
- const manuallyVerifyClicked = !doneClicked;
- if (!manuallyVerifyClicked) {
- return;
- }
- const cli = MatrixClientPeg.get();
- const verificationRequestPromise = cli.requestVerification(
- userId,
- [device.deviceId],
- );
- dis.dispatch({
- action: "set_right_panel_phase",
- phase: RIGHT_PANEL_PHASES.EncryptionPanel,
- refireParams: {member, verificationRequestPromise},
- });
- },
- primaryButton: _t("Done"),
- cancelButton: _t("Manually Verify"),
- });
-}
-
-async function legacyVerifyUser(member) {
- const cli = MatrixClientPeg.get();
- const verificationRequestPromise = cli.requestVerification(member.userId);
- dis.dispatch({
- action: "set_right_panel_phase",
- phase: RIGHT_PANEL_PHASES.EncryptionPanel,
- refireParams: {member, verificationRequestPromise},
- });
-}
-
-function verifyUser(user) {
- const cli = MatrixClientPeg.get();
- const dmRoom = findDMForUser(cli, user.userId);
- let existingRequest;
- if (dmRoom) {
- existingRequest = cli.findVerificationRequestDMInProgress(dmRoom.roomId);
- }
- dis.dispatch({
- action: "set_right_panel_phase",
- phase: RIGHT_PANEL_PHASES.EncryptionPanel,
- refireParams: {
- member: user,
- verificationRequest: existingRequest,
- },
- });
-}
-
function DeviceItem({userId, device}) {
const cli = useContext(MatrixClientContext);
const isMe = userId === cli.getUserId();
@@ -239,7 +180,7 @@ function DeviceItem({userId, device}) {
const onDeviceClick = () => {
if (!isVerified) {
- verifyDevice(userId, device);
+ verifyDevice(cli.getUser(userId), device);
}
};
diff --git a/src/components/views/toasts/VerificationRequestToast.js b/src/components/views/toasts/VerificationRequestToast.js
index c11cefc839..f590cecc3e 100644
--- a/src/components/views/toasts/VerificationRequestToast.js
+++ b/src/components/views/toasts/VerificationRequestToast.js
@@ -24,6 +24,7 @@ import {userLabelForEventRoom} from "../../../utils/KeyVerificationStateObserver
import dis from "../../../dispatcher";
import ToastStore from "../../../stores/ToastStore";
import Modal from "../../../Modal";
+import {enable4SIfNeeded} from "../../../verification";
export default class VerificationRequestToast extends React.PureComponent {
constructor(props) {
@@ -73,6 +74,9 @@ export default class VerificationRequestToast extends React.PureComponent {
}
accept = async () => {
+ if (!await enable4SIfNeeded()) {
+ return;
+ }
ToastStore.sharedInstance().dismissToast(this.props.toastKey);
const {request} = this.props;
// no room id for to_device requests
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 15a050d783..2f8f5c48ad 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -291,6 +291,11 @@
"%(senderName)s updated a ban rule that was matching %(oldGlob)s to matching %(newGlob)s for %(reason)s": "%(senderName)s updated a ban rule that was matching %(oldGlob)s to matching %(newGlob)s for %(reason)s",
"Light theme": "Light theme",
"Dark theme": "Dark theme",
+ "Not Trusted": "Not Trusted",
+ "%(name)s (%(userId)s) signed in to a new session without verifying it:": "%(name)s (%(userId)s) signed in to a new session without verifying it:",
+ "Ask this user to verify their session, or manually verify it below.": "Ask this user to verify their session, or manually verify it below.",
+ "Done": "Done",
+ "Manually Verify": "Manually Verify",
"%(displayName)s is typing …": "%(displayName)s is typing …",
"%(names)s and %(count)s others are typing …|other": "%(names)s and %(count)s others are typing …",
"%(names)s and %(count)s others are typing …|one": "%(names)s and one other is typing …",
@@ -1185,11 +1190,6 @@
"Yours, or the other users’ session": "Yours, or the other users’ session",
"Members": "Members",
"Files": "Files",
- "Not Trusted": "Not Trusted",
- "%(name)s (%(userId)s) signed in to a new session without verifying it:": "%(name)s (%(userId)s) signed in to a new session without verifying it:",
- "Ask this user to verify their session, or manually verify it below.": "Ask this user to verify their session, or manually verify it below.",
- "Done": "Done",
- "Manually Verify": "Manually Verify",
"Trusted": "Trusted",
"Not trusted": "Not trusted",
"%(count)s verified sessions|other": "%(count)s verified sessions",
diff --git a/src/verification.js b/src/verification.js
new file mode 100644
index 0000000000..235828dc92
--- /dev/null
+++ b/src/verification.js
@@ -0,0 +1,106 @@
+/*
+Copyright 2019, 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';
+import dis from "./dispatcher";
+import Modal from './Modal';
+import * as sdk from './index';
+import { _t } from './languageHandler';
+import {RIGHT_PANEL_PHASES} from "./stores/RightPanelStorePhases";
+import {findDMForUser} from './createRoom';
+import {accessSecretStorage} from './CrossSigningManager';
+import SettingsStore from './settings/SettingsStore';
+
+export async function enable4SIfNeeded() {
+ const cli = MatrixClientPeg.get();
+ if (!cli.isCryptoEnabled() || !SettingsStore.isFeatureEnabled("feature_cross_signing")) {
+ return false;
+ }
+ const usk = cli.getCrossSigningId("user_signing");
+ if (!usk) {
+ await accessSecretStorage();
+ return false;
+ }
+
+ return true;
+}
+
+export async function verifyDevice(user, device) {
+ if (!await enable4SIfNeeded()) {
+ return;
+ }
+ const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
+ Modal.createTrackedDialog("Verification warning", "unverified session", QuestionDialog, {
+ headerImage: require("../res/img/e2e/warning.svg"),
+ title: _t("Not Trusted"),
+ description:
+
{_t("%(name)s (%(userId)s) signed in to a new session without verifying it:", {name: user.displayName, userId: user.userId})}
+
{device.getDisplayName()} ({device.deviceId})
+
{_t("Ask this user to verify their session, or manually verify it below.")}
+
,
+ onFinished: async (doneClicked) => {
+ const manuallyVerifyClicked = !doneClicked;
+ if (!manuallyVerifyClicked) {
+ return;
+ }
+ const cli = MatrixClientPeg.get();
+ const verificationRequestPromise = cli.requestVerification(
+ user.userId,
+ [device.deviceId],
+ );
+ dis.dispatch({
+ action: "set_right_panel_phase",
+ phase: RIGHT_PANEL_PHASES.EncryptionPanel,
+ refireParams: {member: user, verificationRequestPromise},
+ });
+ },
+ primaryButton: _t("Done"),
+ cancelButton: _t("Manually Verify"),
+ });
+}
+
+export async function legacyVerifyUser(user) {
+ if (!await enable4SIfNeeded()) {
+ return;
+ }
+ const cli = MatrixClientPeg.get();
+ const verificationRequestPromise = cli.requestVerification(user.userId);
+ dis.dispatch({
+ action: "set_right_panel_phase",
+ phase: RIGHT_PANEL_PHASES.EncryptionPanel,
+ refireParams: {member: user, verificationRequestPromise},
+ });
+}
+
+export async function verifyUser(user) {
+ if (!await enable4SIfNeeded()) {
+ return;
+ }
+ const cli = MatrixClientPeg.get();
+ const dmRoom = findDMForUser(cli, user.userId);
+ let existingRequest;
+ if (dmRoom) {
+ existingRequest = cli.findVerificationRequestDMInProgress(dmRoom.roomId);
+ }
+ dis.dispatch({
+ action: "set_right_panel_phase",
+ phase: RIGHT_PANEL_PHASES.EncryptionPanel,
+ refireParams: {
+ member: user,
+ verificationRequest: existingRequest,
+ },
+ });
+}