Merge pull request from matrix-org/bwindels/bringbacklegacyverif

Bring back legacy verification by comparing public device keys
pull/21833/head
Bruno Windels 2020-03-20 14:55:17 +00:00 committed by GitHub
commit c9de12ee74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 137 additions and 27 deletions

View File

@ -0,0 +1,86 @@
/*
Copyright 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Copyright 2019 New Vector Ltd
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
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 PropTypes from 'prop-types';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import * as sdk from '../../../index';
import * as FormattingUtils from '../../../utils/FormattingUtils';
import { _t } from '../../../languageHandler';
export default class ManualDeviceKeyVerificationDialog extends React.Component {
static propTypes = {
userId: PropTypes.string.isRequired,
device: PropTypes.object.isRequired,
onFinished: PropTypes.func.isRequired,
};
_onCancelClick = () => {
this.props.onFinished(false);
}
_onLegacyFinished = (confirm) => {
if (confirm) {
MatrixClientPeg.get().setDeviceVerified(
this.props.userId, this.props.device.deviceId, true,
);
}
this.props.onFinished(confirm);
}
render() {
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
let text;
if (MatrixClientPeg.get().getUserId() === this.props.userId) {
text = _t("Confirm by comparing the following with the User Settings in your other session:");
} else {
text = _t("Confirm this user's session by comparing the following with their User Settings:");
}
const key = FormattingUtils.formatCryptoKey(this.props.device.getFingerprint());
const body = (
<div>
<p>
{ text }
</p>
<div className="mx_DeviceVerifyDialog_cryptoSection">
<ul>
<li><label>{ _t("Session name") }:</label> <span>{ this.props.device.getDisplayName() }</span></li>
<li><label>{ _t("Session ID") }:</label> <span><code>{ this.props.device.deviceId }</code></span></li>
<li><label>{ _t("Session key") }:</label> <span><code><b>{ key }</b></code></span></li>
</ul>
</div>
<p>
{ _t("If they don't match, the security of your communication may be compromised.") }
</p>
</div>
);
return (
<QuestionDialog
title={_t("Verify session")}
description={body}
button={_t("Verify session")}
onFinished={this._onLegacyFinished}
/>
);
}
}

View File

@ -294,8 +294,9 @@
"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.",
"Manually Verify by Text": "Manually Verify by Text",
"Interactively verify by Emoji": "Interactively verify by Emoji",
"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 …",
@ -1613,6 +1614,9 @@
"Manually export keys": "Manually export keys",
"You'll lose access to your encrypted messages": "You'll lose access to your encrypted messages",
"Are you sure you want to sign out?": "Are you sure you want to sign out?",
"Confirm by comparing the following with the User Settings in your other session:": "Confirm by comparing the following with the User Settings in your other session:",
"Confirm this user's session by comparing the following with their User Settings:": "Confirm this user's session by comparing the following with their User Settings:",
"If they don't match, the security of your communication may be compromised.": "If they don't match, the security of your communication may be compromised.",
"Your homeserver doesn't seem to support this feature.": "Your homeserver doesn't seem to support this feature.",
"Message edits": "Message edits",
"Your account is not secure": "Your account is not secure",

View File

@ -39,38 +39,58 @@ async function enable4SIfNeeded() {
return true;
}
function UntrustedDeviceDialog(props) {
const {device, user, onFinished} = props;
const BaseDialog = sdk.getComponent("dialogs.BaseDialog");
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
return <BaseDialog
onFinished={onFinished}
headerImage={require("../res/img/e2e/warning.svg")}
title={_t("Not Trusted")}>
<div className="mx_Dialog_content" id='mx_Dialog_content'>
<p>{_t("%(name)s (%(userId)s) signed in to a new session without verifying it:", {name: user.displayName, userId: user.userId})}</p>
<p>{device.getDisplayName()} ({device.deviceId})</p>
<p>{_t("Ask this user to verify their session, or manually verify it below.")}</p>
</div>
<div className='mx_Dialog_buttons'>
<AccessibleButton element="button" kind="secondary" onClick={() => onFinished("legacy")}>{_t("Manually Verify by Text")}</AccessibleButton>
<AccessibleButton element="button" kind="secondary" onClick={() => onFinished("sas")}>{_t("Interactively verify by Emoji")}</AccessibleButton>
<AccessibleButton kind="primary" onClick={() => onFinished()}>{_t("Done")}</AccessibleButton>
</div>
</BaseDialog>;
}
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: <div>
<p>{_t("%(name)s (%(userId)s) signed in to a new session without verifying it:", {name: user.displayName, userId: user.userId})}</p>
<p>{device.getDisplayName()} ({device.deviceId})</p>
<p>{_t("Ask this user to verify their session, or manually verify it below.")}</p>
</div>,
onFinished: async (doneClicked) => {
const manuallyVerifyClicked = !doneClicked;
if (!manuallyVerifyClicked) {
return;
Modal.createTrackedDialog("Verification warning", "unverified session", UntrustedDeviceDialog, {
user,
device,
onFinished: async (action) => {
if (action === "sas") {
const cli = MatrixClientPeg.get();
const verificationRequestPromise = cli.legacyDeviceVerification(
user.userId,
device.deviceId,
verificationMethods.SAS,
);
dis.dispatch({
action: "set_right_panel_phase",
phase: RIGHT_PANEL_PHASES.EncryptionPanel,
refireParams: {member: user, verificationRequestPromise},
});
} else if (action === "legacy") {
const ManualDeviceKeyVerificationDialog = sdk.getComponent("dialogs.ManualDeviceKeyVerificationDialog");
Modal.createTrackedDialog("Legacy verify session", "legacy verify session",
ManualDeviceKeyVerificationDialog,
{
userId: user.userId,
device,
},
);
}
const cli = MatrixClientPeg.get();
const verificationRequestPromise = cli.legacyDeviceVerification(
user.userId,
device.deviceId,
verificationMethods.SAS,
);
dis.dispatch({
action: "set_right_panel_phase",
phase: RIGHT_PANEL_PHASES.EncryptionPanel,
refireParams: {member: user, verificationRequestPromise},
});
},
primaryButton: _t("Done"),
cancelButton: _t("Manually Verify"),
});
}