mirror of
https://github.com/vector-im/element-web.git
synced 2024-11-17 22:14:58 +08:00
Merge pull request #4042 from matrix-org/bwindels/encryptionpaneleverywhere
Use EncryptionPanel everywhere, part I
This commit is contained in:
commit
a84e90df51
@ -37,3 +37,70 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Special case styling for EncryptionPanel in a Modal dialog
|
||||||
|
.mx_Dialog, .mx_CompleteSecurity_body {
|
||||||
|
.mx_VerificationPanel_QRPhase_startOptions {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
align-items: stretch;
|
||||||
|
|
||||||
|
> .mx_VerificationPanel_QRPhase_betweenText {
|
||||||
|
width: 50px;
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_VerificationPanel_QRPhase_startOption {
|
||||||
|
background-color: $user-tile-hover-bg-color;
|
||||||
|
border-radius: 10px;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
padding: 10px;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
canvas, .mx_VerificationPanel_QRPhase_noQR {
|
||||||
|
width: 220px !important;
|
||||||
|
height: 220px !important;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
> p {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_VerificationPanel_QRPhase_helpText {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-top: 71px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_AccessibleButton {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptionPanel when verification is done
|
||||||
|
.mx_VerificationPanel_verified_section {
|
||||||
|
// center the big shield icon
|
||||||
|
.mx_E2EIcon {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
// right align the "Got it" button
|
||||||
|
.mx_AccessibleButton {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -83,12 +83,13 @@ export default class CompleteSecurity extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onVerificationRequest = (request) => {
|
onVerificationRequest = async (request) => {
|
||||||
if (request.otherUserId !== MatrixClientPeg.get().getUserId()) return;
|
if (request.otherUserId !== MatrixClientPeg.get().getUserId()) return;
|
||||||
|
|
||||||
if (this.state.verificationRequest) {
|
if (this.state.verificationRequest) {
|
||||||
this.state.verificationRequest.off("change", this.onVerificationRequestChange);
|
this.state.verificationRequest.off("change", this.onVerificationRequestChange);
|
||||||
}
|
}
|
||||||
|
await request.accept();
|
||||||
request.on("change", this.onVerificationRequestChange);
|
request.on("change", this.onVerificationRequestChange);
|
||||||
this.setState({
|
this.setState({
|
||||||
verificationRequest: request,
|
verificationRequest: request,
|
||||||
@ -138,9 +139,12 @@ export default class CompleteSecurity extends React.Component {
|
|||||||
let body;
|
let body;
|
||||||
|
|
||||||
if (this.state.verificationRequest) {
|
if (this.state.verificationRequest) {
|
||||||
const IncomingSasDialog = sdk.getComponent("views.dialogs.IncomingSasDialog");
|
const EncryptionPanel = sdk.getComponent("views.right_panel.EncryptionPanel");
|
||||||
body = <IncomingSasDialog verifier={this.state.verificationRequest.verifier}
|
body = <EncryptionPanel
|
||||||
onFinished={this.props.onFinished}
|
layout="dialog"
|
||||||
|
verificationRequest={this.state.verificationRequest}
|
||||||
|
onClose={this.props.onFinished}
|
||||||
|
member={MatrixClientPeg.get().getUser(this.state.verificationRequest.otherUserId)}
|
||||||
/>;
|
/>;
|
||||||
} else if (phase === PHASE_INTRO) {
|
} else if (phase === PHASE_INTRO) {
|
||||||
icon = <span className="mx_CompleteSecurity_headerIcon mx_E2EIcon_warning"></span>;
|
icon = <span className="mx_CompleteSecurity_headerIcon mx_E2EIcon_warning"></span>;
|
||||||
|
@ -27,16 +27,19 @@ import {verificationMethods} from 'matrix-js-sdk/src/crypto';
|
|||||||
import {ensureDMExists} from "../../../createRoom";
|
import {ensureDMExists} from "../../../createRoom";
|
||||||
import dis from "../../../dispatcher";
|
import dis from "../../../dispatcher";
|
||||||
import SettingsStore from '../../../settings/SettingsStore';
|
import SettingsStore from '../../../settings/SettingsStore';
|
||||||
|
import {SHOW_QR_CODE_METHOD} from "matrix-js-sdk/src/crypto/verification/QRCode";
|
||||||
|
import VerificationQREmojiOptions from "../verification/VerificationQREmojiOptions";
|
||||||
|
|
||||||
const MODE_LEGACY = 'legacy';
|
const MODE_LEGACY = 'legacy';
|
||||||
const MODE_SAS = 'sas';
|
const MODE_SAS = 'sas';
|
||||||
|
|
||||||
const PHASE_START = 0;
|
const PHASE_START = 0;
|
||||||
const PHASE_WAIT_FOR_PARTNER_TO_ACCEPT = 1;
|
const PHASE_WAIT_FOR_PARTNER_TO_ACCEPT = 1;
|
||||||
const PHASE_SHOW_SAS = 2;
|
const PHASE_PICK_VERIFICATION_OPTION = 2;
|
||||||
const PHASE_WAIT_FOR_PARTNER_TO_CONFIRM = 3;
|
const PHASE_SHOW_SAS = 3;
|
||||||
const PHASE_VERIFIED = 4;
|
const PHASE_WAIT_FOR_PARTNER_TO_CONFIRM = 4;
|
||||||
const PHASE_CANCELLED = 5;
|
const PHASE_VERIFIED = 5;
|
||||||
|
const PHASE_CANCELLED = 6;
|
||||||
|
|
||||||
export default class DeviceVerifyDialog extends React.Component {
|
export default class DeviceVerifyDialog extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
@ -49,6 +52,7 @@ export default class DeviceVerifyDialog extends React.Component {
|
|||||||
super();
|
super();
|
||||||
this._verifier = null;
|
this._verifier = null;
|
||||||
this._showSasEvent = null;
|
this._showSasEvent = null;
|
||||||
|
this._request = null;
|
||||||
this.state = {
|
this.state = {
|
||||||
phase: PHASE_START,
|
phase: PHASE_START,
|
||||||
mode: MODE_SAS,
|
mode: MODE_SAS,
|
||||||
@ -80,6 +84,25 @@ export default class DeviceVerifyDialog extends React.Component {
|
|||||||
this.props.onFinished(false);
|
this.props.onFinished(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onUseSasClick = async () => {
|
||||||
|
try {
|
||||||
|
this._verifier = this._request.beginKeyVerification(verificationMethods.SAS);
|
||||||
|
this._verifier.on('show_sas', this._onVerifierShowSas);
|
||||||
|
// throws upon cancellation
|
||||||
|
await this._verifier.verify();
|
||||||
|
this.setState({phase: PHASE_VERIFIED});
|
||||||
|
this._verifier.removeListener('show_sas', this._onVerifierShowSas);
|
||||||
|
this._verifier = null;
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Verification failed", e);
|
||||||
|
this.setState({
|
||||||
|
phase: PHASE_CANCELLED,
|
||||||
|
});
|
||||||
|
this._verifier = null;
|
||||||
|
this._request = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
_onLegacyFinished = (confirm) => {
|
_onLegacyFinished = (confirm) => {
|
||||||
if (confirm) {
|
if (confirm) {
|
||||||
MatrixClientPeg.get().setDeviceVerified(
|
MatrixClientPeg.get().setDeviceVerified(
|
||||||
@ -108,11 +131,20 @@ export default class DeviceVerifyDialog extends React.Component {
|
|||||||
} else {
|
} else {
|
||||||
this._verifier = request.verifier;
|
this._verifier = request.verifier;
|
||||||
}
|
}
|
||||||
|
} else if (verifyingOwnDevice && SettingsStore.isFeatureEnabled("feature_cross_signing")) {
|
||||||
|
this._request = await client.requestVerification(this.props.userId, [
|
||||||
|
verificationMethods.SAS,
|
||||||
|
SHOW_QR_CODE_METHOD,
|
||||||
|
]);
|
||||||
|
|
||||||
|
await this._request.waitFor(r => r.ready || r.started);
|
||||||
|
this.setState({phase: PHASE_PICK_VERIFICATION_OPTION});
|
||||||
} else {
|
} else {
|
||||||
this._verifier = client.beginKeyVerification(
|
this._verifier = client.beginKeyVerification(
|
||||||
verificationMethods.SAS, this.props.userId, this.props.device.deviceId,
|
verificationMethods.SAS, this.props.userId, this.props.device.deviceId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (!this._verifier) return;
|
||||||
this._verifier.on('show_sas', this._onVerifierShowSas);
|
this._verifier.on('show_sas', this._onVerifierShowSas);
|
||||||
// throws upon cancellation
|
// throws upon cancellation
|
||||||
await this._verifier.verify();
|
await this._verifier.verify();
|
||||||
@ -150,10 +182,13 @@ export default class DeviceVerifyDialog extends React.Component {
|
|||||||
let body;
|
let body;
|
||||||
switch (this.state.phase) {
|
switch (this.state.phase) {
|
||||||
case PHASE_START:
|
case PHASE_START:
|
||||||
body = this._renderSasVerificationPhaseStart();
|
body = this._renderVerificationPhaseStart();
|
||||||
break;
|
break;
|
||||||
case PHASE_WAIT_FOR_PARTNER_TO_ACCEPT:
|
case PHASE_WAIT_FOR_PARTNER_TO_ACCEPT:
|
||||||
body = this._renderSasVerificationPhaseWaitAccept();
|
body = this._renderVerificationPhaseWaitAccept();
|
||||||
|
break;
|
||||||
|
case PHASE_PICK_VERIFICATION_OPTION:
|
||||||
|
body = this._renderVerificationPhasePick();
|
||||||
break;
|
break;
|
||||||
case PHASE_SHOW_SAS:
|
case PHASE_SHOW_SAS:
|
||||||
body = this._renderSasVerificationPhaseShowSas();
|
body = this._renderSasVerificationPhaseShowSas();
|
||||||
@ -162,10 +197,10 @@ export default class DeviceVerifyDialog extends React.Component {
|
|||||||
body = this._renderSasVerificationPhaseWaitForPartnerToConfirm();
|
body = this._renderSasVerificationPhaseWaitForPartnerToConfirm();
|
||||||
break;
|
break;
|
||||||
case PHASE_VERIFIED:
|
case PHASE_VERIFIED:
|
||||||
body = this._renderSasVerificationPhaseVerified();
|
body = this._renderVerificationPhaseVerified();
|
||||||
break;
|
break;
|
||||||
case PHASE_CANCELLED:
|
case PHASE_CANCELLED:
|
||||||
body = this._renderSasVerificationPhaseCancelled();
|
body = this._renderVerificationPhaseCancelled();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +215,7 @@ export default class DeviceVerifyDialog extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderSasVerificationPhaseStart() {
|
_renderVerificationPhaseStart() {
|
||||||
const AccessibleButton = sdk.getComponent('views.elements.AccessibleButton');
|
const AccessibleButton = sdk.getComponent('views.elements.AccessibleButton');
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||||
return (
|
return (
|
||||||
@ -206,7 +241,7 @@ export default class DeviceVerifyDialog extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderSasVerificationPhaseWaitAccept() {
|
_renderVerificationPhaseWaitAccept() {
|
||||||
const Spinner = sdk.getComponent("views.elements.Spinner");
|
const Spinner = sdk.getComponent("views.elements.Spinner");
|
||||||
const AccessibleButton = sdk.getComponent('views.elements.AccessibleButton');
|
const AccessibleButton = sdk.getComponent('views.elements.AccessibleButton');
|
||||||
|
|
||||||
@ -227,6 +262,14 @@ export default class DeviceVerifyDialog extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_renderVerificationPhasePick() {
|
||||||
|
return <VerificationQREmojiOptions
|
||||||
|
request={this._request}
|
||||||
|
onCancel={this._onCancelClick}
|
||||||
|
onStartEmoji={this._onUseSasClick}
|
||||||
|
/>;
|
||||||
|
}
|
||||||
|
|
||||||
_renderSasVerificationPhaseShowSas() {
|
_renderSasVerificationPhaseShowSas() {
|
||||||
const VerificationShowSas = sdk.getComponent('views.verification.VerificationShowSas');
|
const VerificationShowSas = sdk.getComponent('views.verification.VerificationShowSas');
|
||||||
return <VerificationShowSas
|
return <VerificationShowSas
|
||||||
@ -234,6 +277,7 @@ export default class DeviceVerifyDialog extends React.Component {
|
|||||||
onCancel={this._onCancelClick}
|
onCancel={this._onCancelClick}
|
||||||
onDone={this._onSasMatchesClick}
|
onDone={this._onSasMatchesClick}
|
||||||
isSelf={MatrixClientPeg.get().getUserId() === this.props.userId}
|
isSelf={MatrixClientPeg.get().getUserId() === this.props.userId}
|
||||||
|
onStartEmoji={this._onUseSasClick}
|
||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,12 +291,12 @@ export default class DeviceVerifyDialog extends React.Component {
|
|||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderSasVerificationPhaseVerified() {
|
_renderVerificationPhaseVerified() {
|
||||||
const VerificationComplete = sdk.getComponent('views.verification.VerificationComplete');
|
const VerificationComplete = sdk.getComponent('views.verification.VerificationComplete');
|
||||||
return <VerificationComplete onDone={this._onVerifiedDoneClick} />;
|
return <VerificationComplete onDone={this._onVerifiedDoneClick} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderSasVerificationPhaseCancelled() {
|
_renderVerificationPhaseCancelled() {
|
||||||
const VerificationCancelled = sdk.getComponent('views.verification.VerificationCancelled');
|
const VerificationCancelled = sdk.getComponent('views.verification.VerificationCancelled');
|
||||||
return <VerificationCancelled onDone={this._onCancelClick} />;
|
return <VerificationCancelled onDone={this._onCancelClick} />;
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,12 @@ import PropTypes from 'prop-types';
|
|||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import Modal from '../../../Modal';
|
import Modal from '../../../Modal';
|
||||||
import { replaceableComponent } from '../../../utils/replaceableComponent';
|
import { replaceableComponent } from '../../../utils/replaceableComponent';
|
||||||
import DeviceVerifyDialog from './DeviceVerifyDialog';
|
import VerificationRequestDialog from './VerificationRequestDialog';
|
||||||
import BaseDialog from './BaseDialog';
|
import BaseDialog from './BaseDialog';
|
||||||
import DialogButtons from '../elements/DialogButtons';
|
import DialogButtons from '../elements/DialogButtons';
|
||||||
|
import {verificationMethods} from 'matrix-js-sdk/src/crypto';
|
||||||
|
import {MatrixClientPeg} from "../../../MatrixClientPeg";
|
||||||
|
import {SHOW_QR_CODE_METHOD} from "matrix-js-sdk/src/crypto/verification/QRCode";
|
||||||
|
|
||||||
@replaceableComponent("views.dialogs.NewSessionReviewDialog")
|
@replaceableComponent("views.dialogs.NewSessionReviewDialog")
|
||||||
export default class NewSessionReviewDialog extends React.PureComponent {
|
export default class NewSessionReviewDialog extends React.PureComponent {
|
||||||
@ -35,12 +38,20 @@ export default class NewSessionReviewDialog extends React.PureComponent {
|
|||||||
this.props.onFinished(false);
|
this.props.onFinished(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
onContinueClick = () => {
|
onContinueClick = async () => {
|
||||||
const { userId, device } = this.props;
|
const { userId, device } = this.props;
|
||||||
Modal.createTrackedDialog('New Session Verification', 'Starting dialog', DeviceVerifyDialog, {
|
const cli = MatrixClientPeg.get();
|
||||||
|
const request = await cli.requestVerification(
|
||||||
userId,
|
userId,
|
||||||
device,
|
[verificationMethods.SAS, SHOW_QR_CODE_METHOD],
|
||||||
}, null, /* priority = */ false, /* static = */ true);
|
[device.deviceId],
|
||||||
|
);
|
||||||
|
|
||||||
|
this.props.onFinished(true);
|
||||||
|
|
||||||
|
Modal.createTrackedDialog('New Session Verification', 'Starting dialog', VerificationRequestDialog, {
|
||||||
|
verificationRequest: request,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
45
src/components/views/dialogs/VerificationRequestDialog.js
Normal file
45
src/components/views/dialogs/VerificationRequestDialog.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
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 React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import {MatrixClientPeg} from '../../../MatrixClientPeg';
|
||||||
|
import * as sdk from '../../../index';
|
||||||
|
import { _t } from '../../../languageHandler';
|
||||||
|
|
||||||
|
export default class VerificationRequestDialog extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
verificationRequest: PropTypes.object.isRequired,
|
||||||
|
onFinished: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const BaseDialog = sdk.getComponent("views.dialogs.BaseDialog");
|
||||||
|
const EncryptionPanel = sdk.getComponent("views.right_panel.EncryptionPanel");
|
||||||
|
return <BaseDialog className="mx_InfoDialog" onFinished={this.props.onFinished}
|
||||||
|
contentId="mx_Dialog_content"
|
||||||
|
title={_t("Verification Request")}
|
||||||
|
hasCancel={true}
|
||||||
|
>
|
||||||
|
<EncryptionPanel
|
||||||
|
layout="dialog"
|
||||||
|
verificationRequest={this.props.verificationRequest}
|
||||||
|
onClose={this.props.onFinished}
|
||||||
|
member={MatrixClientPeg.get().getUser(this.props.verificationRequest.otherUserId)}
|
||||||
|
/>
|
||||||
|
</BaseDialog>;
|
||||||
|
}
|
||||||
|
}
|
@ -30,7 +30,7 @@ import {_t} from "../../../languageHandler";
|
|||||||
// cancellation codes which constitute a key mismatch
|
// cancellation codes which constitute a key mismatch
|
||||||
const MISMATCHES = ["m.key_mismatch", "m.user_error", "m.mismatched_sas"];
|
const MISMATCHES = ["m.key_mismatch", "m.user_error", "m.mismatched_sas"];
|
||||||
|
|
||||||
const EncryptionPanel = ({verificationRequest, member, onClose}) => {
|
const EncryptionPanel = ({verificationRequest, member, onClose, layout}) => {
|
||||||
const [request, setRequest] = useState(verificationRequest);
|
const [request, setRequest] = useState(verificationRequest);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setRequest(verificationRequest);
|
setRequest(verificationRequest);
|
||||||
@ -77,6 +77,7 @@ const EncryptionPanel = ({verificationRequest, member, onClose}) => {
|
|||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<VerificationPanel
|
<VerificationPanel
|
||||||
|
layout={layout}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
member={member}
|
member={member}
|
||||||
request={request}
|
request={request}
|
||||||
@ -89,6 +90,7 @@ EncryptionPanel.propTypes = {
|
|||||||
member: PropTypes.object.isRequired,
|
member: PropTypes.object.isRequired,
|
||||||
onClose: PropTypes.func.isRequired,
|
onClose: PropTypes.func.isRequired,
|
||||||
verificationRequest: PropTypes.object,
|
verificationRequest: PropTypes.object,
|
||||||
|
layout: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default EncryptionPanel;
|
export default EncryptionPanel;
|
||||||
|
@ -34,6 +34,7 @@ import Spinner from "../elements/Spinner";
|
|||||||
|
|
||||||
export default class VerificationPanel extends React.PureComponent {
|
export default class VerificationPanel extends React.PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
layout: PropTypes.string,
|
||||||
request: PropTypes.object.isRequired,
|
request: PropTypes.object.isRequired,
|
||||||
member: PropTypes.object.isRequired,
|
member: PropTypes.object.isRequired,
|
||||||
phase: PropTypes.oneOf([
|
phase: PropTypes.oneOf([
|
||||||
@ -69,6 +70,33 @@ export default class VerificationPanel extends React.PureComponent {
|
|||||||
const {member} = this.props;
|
const {member} = this.props;
|
||||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
|
|
||||||
|
if (this.props.layout === 'dialog') {
|
||||||
|
// HACK: This is a terrible idea.
|
||||||
|
let qrCode = <div className='mx_VerificationPanel_QRPhase_noQR'><Spinner /></div>;
|
||||||
|
if (this.state.qrCodeProps) {
|
||||||
|
qrCode = <VerificationQRCode {...this.state.qrCodeProps} />;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{_t("Verify this session by completing one of the following:")}
|
||||||
|
<div className='mx_VerificationPanel_QRPhase_startOptions'>
|
||||||
|
<div className='mx_VerificationPanel_QRPhase_startOption'>
|
||||||
|
<p>{_t("Scan this unique code")}</p>
|
||||||
|
{qrCode}
|
||||||
|
</div>
|
||||||
|
<div className='mx_VerificationPanel_QRPhase_betweenText'>{_t("or")}</div>
|
||||||
|
<div className='mx_VerificationPanel_QRPhase_startOption'>
|
||||||
|
<p>{_t("Compare unique emoji")}</p>
|
||||||
|
<span className='mx_VerificationPanel_QRPhase_helpText'>{_t("Compare a unique set of emoji if you don't have a camera on either device")}</span>
|
||||||
|
<AccessibleButton onClick={this._startSAS} kind='primary'>
|
||||||
|
{_t("Start")}
|
||||||
|
</AccessibleButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let button;
|
let button;
|
||||||
if (pending) {
|
if (pending) {
|
||||||
button = <Spinner />;
|
button = <Spinner />;
|
||||||
@ -82,9 +110,8 @@ export default class VerificationPanel extends React.PureComponent {
|
|||||||
|
|
||||||
if (!this.state.qrCodeProps) {
|
if (!this.state.qrCodeProps) {
|
||||||
return <div className="mx_UserInfo_container">
|
return <div className="mx_UserInfo_container">
|
||||||
<h3>Verify by emoji</h3>
|
<h3>{_t("Verify by emoji")}</h3>
|
||||||
<p>{_t("Verify by comparing unique emoji.")}</p>
|
<p>{_t("Verify by comparing unique emoji.")}</p>
|
||||||
|
|
||||||
{ button }
|
{ button }
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
@ -92,7 +119,7 @@ export default class VerificationPanel extends React.PureComponent {
|
|||||||
// TODO: add way to open camera to scan a QR code
|
// TODO: add way to open camera to scan a QR code
|
||||||
return <React.Fragment>
|
return <React.Fragment>
|
||||||
<div className="mx_UserInfo_container">
|
<div className="mx_UserInfo_container">
|
||||||
<h3>Verify by scanning</h3>
|
<h3>{_t("Verify by scanning")}</h3>
|
||||||
<p>{_t("Ask %(displayName)s to scan your code:", {
|
<p>{_t("Ask %(displayName)s to scan your code:", {
|
||||||
displayName: member.displayName || member.name || member.userId,
|
displayName: member.displayName || member.name || member.userId,
|
||||||
})}</p>
|
})}</p>
|
||||||
@ -103,7 +130,7 @@ export default class VerificationPanel extends React.PureComponent {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mx_UserInfo_container">
|
<div className="mx_UserInfo_container">
|
||||||
<h3>Verify by emoji</h3>
|
<h3>{_t("Verify by emoji")}</h3>
|
||||||
<p>{_t("If you can't scan the code above, verify by comparing unique emoji.")}</p>
|
<p>{_t("If you can't scan the code above, verify by comparing unique emoji.")}</p>
|
||||||
|
|
||||||
{ button }
|
{ button }
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
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 { _t } from '../../../languageHandler';
|
||||||
|
import AccessibleButton from "../elements/AccessibleButton";
|
||||||
|
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
||||||
|
import VerificationQRCode from "../elements/crypto/VerificationQRCode";
|
||||||
|
import {VerificationRequest} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
||||||
|
import Spinner from "../elements/Spinner";
|
||||||
|
|
||||||
|
@replaceableComponent("views.verification.VerificationQREmojiOptions")
|
||||||
|
export default class VerificationQREmojiOptions extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
request: PropTypes.object.isRequired,
|
||||||
|
onCancel: PropTypes.func.isRequired,
|
||||||
|
onStartEmoji: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
qrProps: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
this._prepareQrCode(props.request);
|
||||||
|
}
|
||||||
|
|
||||||
|
async _prepareQrCode(request: VerificationRequest) {
|
||||||
|
try {
|
||||||
|
const props = await VerificationQRCode.getPropsForRequest(request);
|
||||||
|
this.setState({qrProps: props});
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
// We just won't show a QR code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let qrCode = <div className='mx_VerificationQREmojiOptions_noQR'><Spinner /></div>;
|
||||||
|
if (this.state.qrProps) {
|
||||||
|
qrCode = <VerificationQRCode {...this.state.qrProps} />;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{_t("Verify this session by completing one of the following:")}
|
||||||
|
<div className='mx_IncomingSasDialog_startOptions'>
|
||||||
|
<div className='mx_IncomingSasDialog_startOption'>
|
||||||
|
<p>{_t("Scan this unique code")}</p>
|
||||||
|
{qrCode}
|
||||||
|
</div>
|
||||||
|
<div className='mx_IncomingSasDialog_betweenText'>{_t("or")}</div>
|
||||||
|
<div className='mx_IncomingSasDialog_startOption'>
|
||||||
|
<p>{_t("Compare unique emoji")}</p>
|
||||||
|
<span className='mx_IncomingSasDialog_helpText'>{_t("Compare a unique set of emoji if you don't have a camera on either device")}</span>
|
||||||
|
<AccessibleButton onClick={this.props.onStartEmoji} kind='primary'>
|
||||||
|
{_t("Start")}
|
||||||
|
</AccessibleButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<AccessibleButton onClick={this.props.onCancel} kind='danger'>
|
||||||
|
{_t("Cancel")}
|
||||||
|
</AccessibleButton>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -452,6 +452,12 @@
|
|||||||
"You've successfully verified this user.": "You've successfully verified this user.",
|
"You've successfully verified this user.": "You've successfully verified this user.",
|
||||||
"Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "Secure messages with this user are end-to-end encrypted and not able to be read by third parties.",
|
"Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "Secure messages with this user are end-to-end encrypted and not able to be read by third parties.",
|
||||||
"Got It": "Got It",
|
"Got It": "Got It",
|
||||||
|
"Verify this session by completing one of the following:": "Verify this session by completing one of the following:",
|
||||||
|
"Scan this unique code": "Scan this unique code",
|
||||||
|
"or": "or",
|
||||||
|
"Compare unique emoji": "Compare unique emoji",
|
||||||
|
"Compare a unique set of emoji if you don't have a camera on either device": "Compare a unique set of emoji if you don't have a camera on either device",
|
||||||
|
"Start": "Start",
|
||||||
"Confirm the emoji below are displayed on both devices, in the same order:": "Confirm the emoji below are displayed on both devices, in the same order:",
|
"Confirm the emoji below are displayed on both devices, in the same order:": "Confirm the emoji below are displayed on both devices, in the same order:",
|
||||||
"Verify this user by confirming the following emoji appear on their screen.": "Verify this user by confirming the following emoji appear on their screen.",
|
"Verify this user by confirming the following emoji appear on their screen.": "Verify this user by confirming the following emoji appear on their screen.",
|
||||||
"Verify this device by confirming the following number appears on its screen.": "Verify this device by confirming the following number appears on its screen.",
|
"Verify this device by confirming the following number appears on its screen.": "Verify this device by confirming the following number appears on its screen.",
|
||||||
@ -1187,6 +1193,7 @@
|
|||||||
"Security": "Security",
|
"Security": "Security",
|
||||||
"Verify by emoji": "Verify by emoji",
|
"Verify by emoji": "Verify by emoji",
|
||||||
"Verify by comparing unique emoji.": "Verify by comparing unique emoji.",
|
"Verify by comparing unique emoji.": "Verify by comparing unique emoji.",
|
||||||
|
"Verify by scanning": "Verify by scanning",
|
||||||
"Ask %(displayName)s to scan your code:": "Ask %(displayName)s to scan your code:",
|
"Ask %(displayName)s to scan your code:": "Ask %(displayName)s to scan your code:",
|
||||||
"If you can't scan the code above, verify by comparing unique emoji.": "If you can't scan the code above, verify by comparing unique emoji.",
|
"If you can't scan the code above, verify by comparing unique emoji.": "If you can't scan the code above, verify by comparing unique emoji.",
|
||||||
"You've successfully verified %(displayName)s!": "You've successfully verified %(displayName)s!",
|
"You've successfully verified %(displayName)s!": "You've successfully verified %(displayName)s!",
|
||||||
@ -1642,6 +1649,7 @@
|
|||||||
"Upload %(count)s other files|one": "Upload %(count)s other file",
|
"Upload %(count)s other files|one": "Upload %(count)s other file",
|
||||||
"Cancel All": "Cancel All",
|
"Cancel All": "Cancel All",
|
||||||
"Upload Error": "Upload Error",
|
"Upload Error": "Upload Error",
|
||||||
|
"Verification Request": "Verification Request",
|
||||||
"A widget would like to verify your identity": "A widget would like to verify your identity",
|
"A widget would like to verify your identity": "A widget would like to verify your identity",
|
||||||
"A widget located at %(widgetUrl)s would like to verify your identity. By allowing this, the widget will be able to verify your user ID, but not perform actions as you.": "A widget located at %(widgetUrl)s would like to verify your identity. By allowing this, the widget will be able to verify your user ID, but not perform actions as you.",
|
"A widget located at %(widgetUrl)s would like to verify your identity. By allowing this, the widget will be able to verify your user ID, but not perform actions as you.": "A widget located at %(widgetUrl)s would like to verify your identity. By allowing this, the widget will be able to verify your user ID, but not perform actions as you.",
|
||||||
"Remember my selection for this widget": "Remember my selection for this widget",
|
"Remember my selection for this widget": "Remember my selection for this widget",
|
||||||
@ -1853,7 +1861,6 @@
|
|||||||
"Review terms and conditions": "Review terms and conditions",
|
"Review terms and conditions": "Review terms and conditions",
|
||||||
"Old cryptography data detected": "Old cryptography data detected",
|
"Old cryptography data detected": "Old cryptography data detected",
|
||||||
"Data from an older version of Riot has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.": "Data from an older version of Riot has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.",
|
"Data from an older version of Riot has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.": "Data from an older version of Riot has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.",
|
||||||
"Verification Request": "Verification Request",
|
|
||||||
"Logout": "Logout",
|
"Logout": "Logout",
|
||||||
"%(creator)s created and configured the room.": "%(creator)s created and configured the room.",
|
"%(creator)s created and configured the room.": "%(creator)s created and configured the room.",
|
||||||
"Your Communities": "Your Communities",
|
"Your Communities": "Your Communities",
|
||||||
@ -1928,7 +1935,6 @@
|
|||||||
"Could not load user profile": "Could not load user profile",
|
"Could not load user profile": "Could not load user profile",
|
||||||
"Complete security": "Complete security",
|
"Complete security": "Complete security",
|
||||||
"Verify this session to grant it access to encrypted messages.": "Verify this session to grant it access to encrypted messages.",
|
"Verify this session to grant it access to encrypted messages.": "Verify this session to grant it access to encrypted messages.",
|
||||||
"Start": "Start",
|
|
||||||
"Session verified": "Session verified",
|
"Session verified": "Session verified",
|
||||||
"Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.": "Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.",
|
"Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.": "Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.",
|
||||||
"Your new session is now verified. Other users will see it as trusted.": "Your new session is now verified. Other users will see it as trusted.",
|
"Your new session is now verified. Other users will see it as trusted.": "Your new session is now verified. Other users will see it as trusted.",
|
||||||
|
Loading…
Reference in New Issue
Block a user