From 1d2538a7bcb8240dde72b0ed32fe1ebfbb6ba7f0 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 15 Jan 2019 18:08:13 +0000 Subject: [PATCH 01/10] First working version of SAS --- src/MatrixClientPeg.js | 2 + src/components/structures/MatrixChat.js | 7 + .../views/dialogs/DeviceVerifyDialog.js | 312 +++++++++++++++--- .../views/dialogs/IncomingSasDialog.js | 218 ++++++++++++ src/i18n/strings/en_EN.json | 21 +- src/settings/Settings.js | 6 + 6 files changed, 517 insertions(+), 49 deletions(-) create mode 100644 src/components/views/dialogs/IncomingSasDialog.js diff --git a/src/MatrixClientPeg.js b/src/MatrixClientPeg.js index 9a77901d2e..0cf67a3551 100644 --- a/src/MatrixClientPeg.js +++ b/src/MatrixClientPeg.js @@ -29,6 +29,7 @@ import SettingsStore from './settings/SettingsStore'; import MatrixActionCreators from './actions/MatrixActionCreators'; import {phasedRollOutExpiredForUser} from "./PhasedRollOut"; import Modal from './Modal'; +import {verificationMethods} from 'matrix-js-sdk/lib/crypto'; interface MatrixClientCreds { homeserverUrl: string, @@ -184,6 +185,7 @@ class MatrixClientPeg { deviceId: creds.deviceId, timelineSupport: true, forceTURN: SettingsStore.getValue('webRtcForceTURN', false), + verificationMethods: [verificationMethods.SAS] }; this.matrixClient = createMatrixClient(opts, useIndexedDb); diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 2d1c928494..7167e50fb2 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -1277,6 +1277,7 @@ export default React.createClass({ this.firstSyncComplete = false; this.firstSyncPromise = Promise.defer(); const cli = MatrixClientPeg.get(); + const IncomingSasDialog = sdk.getComponent('views.dialogs.IncomingSasDialog'); // Allow the JS SDK to reap timeline events. This reduces the amount of // memory consumed as the JS SDK stores multiple distinct copies of room @@ -1476,6 +1477,12 @@ export default React.createClass({ } }); + cli.on("crypto.verification.start", (verifier) => { + Modal.createTrackedDialog('Incoming Verification', '', IncomingSasDialog, { + verifier, + }); + }); + // Fire the tinter right on startup to ensure the default theme is applied // A later sync can/will correct the tint to be the right value for the user const colorScheme = SettingsStore.getValue("roomColor"); diff --git a/src/components/views/dialogs/DeviceVerifyDialog.js b/src/components/views/dialogs/DeviceVerifyDialog.js index 6bec933389..169dc26c52 100644 --- a/src/components/views/dialogs/DeviceVerifyDialog.js +++ b/src/components/views/dialogs/DeviceVerifyDialog.js @@ -1,6 +1,7 @@ /* Copyright 2016 OpenMarket Ltd Copyright 2017 Vector Creations Ltd +Copyright 2019 New Vector Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,58 +22,273 @@ import MatrixClientPeg from '../../../MatrixClientPeg'; import sdk from '../../../index'; import * as FormattingUtils from '../../../utils/FormattingUtils'; import { _t } from '../../../languageHandler'; +import SettingsStore from '../../../settings/SettingsStore'; +import {verificationMethods} from 'matrix-js-sdk/lib/crypto'; +import {renderSasWaitAccept} from '../../../sas_ui'; -export default function DeviceVerifyDialog(props) { - const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); +const MODE_LEGACY = 'legacy'; +const MODE_SAS = 'sas'; - const key = FormattingUtils.formatCryptoKey(props.device.getFingerprint()); - const body = ( -
-

- { _t("To verify that this device can be trusted, please contact its " + - "owner using some other means (e.g. in person or a phone call) " + - "and ask them whether the key they see in their User Settings " + - "for this device matches the key below:") } -

-
-
    -
  • { props.device.getDisplayName() }
  • -
  • { props.device.deviceId }
  • -
  • { key }
  • -
-
-

- { _t("If it matches, press the verify button below. " + - "If it doesn't, then someone else is intercepting this device " + - "and you probably want to press the blacklist button instead.") } -

-

- { _t("In future this verification process will be more sophisticated.") } -

-
- ); +const PHASE_START = 0; +const PHASE_WAIT_FOR_PARTNER_TO_ACCEPT = 1; +const PHASE_SHOW_SAS = 2; +const PHASE_WAIT_FOR_PARTNER_TO_CONFIRM = 3; +const PHASE_VERIFIED = 4; +const PHASE_CANCELLED = 5; - function onFinished(confirm) { - if (confirm) { - MatrixClientPeg.get().setDeviceVerified( - props.userId, props.device.deviceId, true, - ); - } - props.onFinished(confirm); +export default class DeviceVerifyDialog extends React.Component { + static propTypes = { + userId: PropTypes.string.isRequired, + device: PropTypes.object.isRequired, + onFinished: PropTypes.func.isRequired, + }; + + constructor() { + super(); + this._verifier = null; + this._showSasEvent = null; + this.state = { + phase: PHASE_START, + mode: SettingsStore.isFeatureEnabled("feature_sas") ? MODE_SAS : MODE_LEGACY, + }; } - return ( - - ); + componentWillUnmount() { + if (this._verifier) { + this._verifier.removeListener('show_sas', this._onVerifierShowSas); + this._verifier.cancel('User cancel'); + } + } + + _onSwitchToLegacyClick = () => { + this.setState({mode: MODE_LEGACY}); + } + + _onSwitchToSasClick = () => { + this.setState({mode: MODE_SAS}); + } + + _onCancelClick = () => { + this.props.onFinished(false); + } + + _onLegacyFinished = (confirm) => { + if (confirm) { + MatrixClientPeg.get().setDeviceVerified( + this.props.userId, this.props.device.deviceId, true, + ); + } + this.props.onFinished(confirm); + } + + _onSasRequestClick = () => { + this.setState({ + phase: PHASE_WAIT_FOR_PARTNER_TO_ACCEPT, + }); + this._verifier = MatrixClientPeg.get().beginKeyVerification( + verificationMethods.SAS, this.props.userId, this.props.device.deviceId, + ); + this._verifier.on('show_sas', this._onVerifierShowSas); + this._verifier.verify().then(() => { + 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; + }); + } + + _onSasMatchesClick = () => { + this._showSasEvent.confirm(); + this.setState({ + phase: PHASE_WAIT_FOR_PARTNER_TO_CONFIRM, + }); + } + + _onVerifiedDoneClick = () => { + this.props.onFinished(true); + } + + _onVerifierShowSas = (e) => { + this._showSasEvent = e; + this.setState({ + phase: PHASE_SHOW_SAS, + }); + } + + _renderSasVerification() { + let body; + switch (this.state.phase) { + case PHASE_START: + body = this._renderSasVerificationPhaseStart(); + break; + case PHASE_WAIT_FOR_PARTNER_TO_ACCEPT: + //body = this._renderSasVerificationPhaseWaitForPartnerToAccept(); + body = renderSasWaitAccept(this.props.userId); + break; + case PHASE_SHOW_SAS: + body = this._renderSasVerificationPhaseShowSas(); + break; + case PHASE_WAIT_FOR_PARTNER_TO_CONFIRM: + body = this._renderSasVerificationPhaseWaitForPartnerToConfirm(); + break; + case PHASE_VERIFIED: + body = this._renderSasVerificationPhaseVerified(); + break; + case PHASE_CANCELLED: + body = this._renderSasVerificationPhaseCancelled(); + break; + } + + const BaseDialog = sdk.getComponent("dialogs.BaseDialog"); + return ( + + {body} + + ); + } + + _renderSasVerificationPhaseStart() { + const AccessibleButton = sdk.getComponent('views.elements.AccessibleButton'); + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + return ( +
+ + {_t("Use Legacy Verification (for older clients)")} + +

+ { _t("Do clicky clicky button press request verify user send to do.") } +

+ +
+ ); + } + + _renderSasVerificationPhaseShowSas() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + return
+

{_t( + "Verify this user by confirming the following number appears on their screen" + )}

+

{_t( + "For maximum security, we reccommend you do this in person or use another " + + "trusted means of communication" + )}

+
{this._showSasEvent.sas}
+ +
; + } + + _renderSasVerificationPhaseWaitForPartnerToConfirm() { + const Spinner = sdk.getComponent('views.elements.Spinner'); + return
+ +

{_t( + "Waiting for %(userId)s to confirm...", {userId: this.props.userId}, + )}

+
; + } + + _renderSasVerificationPhaseVerified() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + return
+

{_t("Verification complete!")}

+ +
; + } + + _renderSasVerificationPhaseCancelled() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + + return ( +
+

{_t( + "%(userId)s cancelled the verification.", {userId: this.props.userId}, + )}

+ +
+ ); + } + + _renderLegacyVerification() { + const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); + const AccessibleButton = sdk.getComponent('views.elements.AccessibleButton'); + + const key = FormattingUtils.formatCryptoKey(this.props.device.getFingerprint()); + const body = ( +
+ + {_t("Use two-way text verification")} + +

+ { _t("To verify that this device can be trusted, please contact its " + + "owner using some other means (e.g. in person or a phone call) " + + "and ask them whether the key they see in their User Settings " + + "for this device matches the key below:") } +

+
+
    +
  • { this.props.device.getDisplayName() }
  • +
  • { this.props.device.deviceId }
  • +
  • { key }
  • +
+
+

+ { _t("If it matches, press the verify button below. " + + "If it doesn't, then someone else is intercepting this device " + + "and you probably want to press the blacklist button instead.") } +

+

+ { _t("In future this verification process will be more sophisticated.") } +

+
+ ); + + return ( + + ); + } + + render() { + if (this.state.mode === MODE_LEGACY) { + return this._renderLegacyVerification(); + } else { + return
+ {this._renderSasVerification()} +
; + } + } } -DeviceVerifyDialog.propTypes = { - userId: PropTypes.string.isRequired, - device: PropTypes.object.isRequired, - onFinished: PropTypes.func.isRequired, -}; diff --git a/src/components/views/dialogs/IncomingSasDialog.js b/src/components/views/dialogs/IncomingSasDialog.js new file mode 100644 index 0000000000..732ce2a461 --- /dev/null +++ b/src/components/views/dialogs/IncomingSasDialog.js @@ -0,0 +1,218 @@ +/* +Copyright 2019 New Vector Ltd + +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 sdk from '../../../index'; +import { _t } from '../../../languageHandler'; +import {verificationMethods} from 'matrix-js-sdk/lib/crypto'; + +const PHASE_START = 0; +const PHASE_SHOW_SAS = 1; +const PHASE_WAIT_FOR_PARTNER_TO_CONFIRM = 2; +const PHASE_VERIFIED = 3; +const PHASE_CANCELLED = 4; + +export default class IncomingSasDialog extends React.Component { + static propTypes = { + verifier: PropTypes.object.isRequired, + }; + + constructor(props) { + super(props); + + this._showSasEvent = null; + this.state = { + phase: PHASE_START, + }; + this.props.verifier.on('show_sas', this._onVerifierShowSas); + this.props.verifier.on('cancel', this._onVerifierCancel); + } + + componentWillUnmount() { + if (this.state.phase !== PHASE_CANCELLED && this.state.phase !== PHASE_VERIFIED) { + this.props.verifier.cancel('User cancel'); + } + this.props.verifier.removeListener('show_sas', this._onVerifierShowSas); + } + + _onFinished = () => { + this.props.onFinished(this.state.phase === PHASE_VERIFIED); + } + + _onCancelClick = () => { + this.props.onFinished(this.state.phase === PHASE_VERIFIED); + } + + _onContinueClick = () => { + this.setState({phase: PHASE_WAIT_FOR_PARTNER_TO_CONFIRM}); + this.props.verifier.verify().then(() => { + this.setState({phase: PHASE_VERIFIED}); + }).catch((e) => { + console.log("Verification failed", e); + }); + } + + _onVerifierShowSas = (e) => { + this._showSasEvent = e; + this.setState({ + phase: PHASE_SHOW_SAS, + sas: e.sas, + }); + } + + _onVerifierCancel = (e) => { + this.setState({ + phase: PHASE_CANCELLED, + }); + } + + _onSasMatchesClick = () => { + this._showSasEvent.confirm(); + this.setState({ + phase: PHASE_WAIT_FOR_PARTNER_TO_CONFIRM, + }); + } + + _onVerifiedDoneClick = () => { + this.props.onFinished(true); + } + + _renderPhaseStart() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + + return ( +
+

{this.props.verifier.userId}

+

{_t( + "Verify this user to mark them as trusted. " + + "Trusting users gives you extra peace of mind when using " + + "end-to-end encrypted messages." + )}

+

{_t( + // NB. Below wording adjusted to singular 'device' until we have + // cross-signing + "Verifying this user will mark their device as trusted, and " + + "also mark your device as trusted to them" + )}

+ +
+ ); + } + + _renderPhaseShowSas() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + return
+

{_t( + "Verify this user by confirming the following number appears on their screen" + )}

+

{_t( + "For maximum security, we reccommend you do this in person or use another " + + "trusted means of communication" + )}

+
{this._showSasEvent.sas}
+ +
; + } + + _renderPhaseWaitForPartnerToConfirm() { + const Spinner = sdk.getComponent("views.elements.Spinner"); + + return ( +
+ +

{_t("Waiting for partner to confirm...")}

+
+ ); + } + + _renderPhaseVerified() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + + return ( +
+

{_t( + "Verification Complete!" + )}

+ +
+ ); + } + + _renderPhaseCancelled() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + + return ( +
+

{_t( + "The other party cancelled the verification." + )}

+ +
+ ); + } + + render() { + console.log("rendering pahse "+this.state.phase); + let body; + switch (this.state.phase) { + case PHASE_START: + body = this._renderPhaseStart(); + break; + case PHASE_SHOW_SAS: + body = this._renderPhaseShowSas(); + break; + case PHASE_WAIT_FOR_PARTNER_TO_CONFIRM: + body = this._renderPhaseWaitForPartnerToConfirm(); + break; + case PHASE_VERIFIED: + body = this._renderPhaseVerified(); + break; + case PHASE_CANCELLED: + body = this._renderPhaseCancelled(); + break; + } + + const BaseDialog = sdk.getComponent("dialogs.BaseDialog"); + return ( + + {body} + + ); + } +} + diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 0fbed11e20..c26330dda4 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -114,6 +114,8 @@ "Failed to invite": "Failed to invite", "Failed to invite users to the room:": "Failed to invite users to the room:", "Failed to invite the following users to the %(roomName)s room:": "Failed to invite the following users to the %(roomName)s room:", + "Waiting for %(userId)s to accept...": "Waiting for %(userId)s to accept...", + "Waiting for %(userId)s to confirm...": "Waiting for %(userId)s to confirm...", "You need to be logged in.": "You need to be logged in.", "You need to be able to invite users to do that.": "You need to be able to invite users to do that.", "Unable to create widget.": "Unable to create widget.", @@ -264,6 +266,7 @@ "Backup of encryption keys to server": "Backup of encryption keys to server", "Render simple counters in room header": "Render simple counters in room header", "Allow up to 6 rooms in a community to be shown simultaneously in a grid via the context menu": "Allow up to 6 rooms in a community to be shown simultaneously in a grid via the context menu", + "Two-way device verification using short text": "Two-way device verification using short text", "Disable Emoji suggestions while typing": "Disable Emoji suggestions while typing", "Use compact timeline layout": "Use compact timeline layout", "Hide removed messages": "Hide removed messages", @@ -938,12 +941,22 @@ "Please forget all messages I have sent when my account is deactivated (Warning: this will cause future users to see an incomplete view of conversations)": "Please forget all messages I have sent when my account is deactivated (Warning: this will cause future users to see an incomplete view of conversations)", "To continue, please enter your password:": "To continue, please enter your password:", "password": "password", + "Verify device": "Verify device", + "Use Legacy Verification (for older clients)": "Use Legacy Verification (for older clients)", + "Do clicky clicky button press request verify user send to do.": "Do clicky clicky button press request verify user send to do.", + "Send Verification Request": "Send Verification Request", + "Verify this user by confirming the following number appears on their screen": "Verify this user by confirming the following number appears on their screen", + "For maximum security, we reccommend you do this in person or use another trusted means of communication": "For maximum security, we reccommend you do this in person or use another trusted means of communication", + "This Matches": "This Matches", + "Verification complete!": "Verification complete!", + "Done": "Done", + "%(userId)s cancelled the verification.": "%(userId)s cancelled the verification.", + "Use two-way text verification": "Use two-way text verification", "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:": "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:", "Device name": "Device name", "Device key": "Device key", "If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.": "If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.", "In future this verification process will be more sophisticated.": "In future this verification process will be more sophisticated.", - "Verify device": "Verify device", "I verify that the keys match": "I verify that the keys match", "Back": "Back", "Send Custom Event": "Send Custom Event", @@ -960,6 +973,12 @@ "Toolbox": "Toolbox", "Developer Tools": "Developer Tools", "An error has occurred.": "An error has occurred.", + "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.": "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.", + "Verifying this user will mark their device as trusted, and also mark your device as trusted to them": "Verifying this user will mark their device as trusted, and also mark your device as trusted to them", + "Waiting for partner to confirm...": "Waiting for partner to confirm...", + "Verification Complete!": "Verification Complete!", + "The other party cancelled the verification.": "The other party cancelled the verification.", + "Incoming Verification Request": "Incoming Verification Request", "You added a new device '%(displayName)s', which is requesting encryption keys.": "You added a new device '%(displayName)s', which is requesting encryption keys.", "Your unverified device '%(displayName)s' is requesting encryption keys.": "Your unverified device '%(displayName)s' is requesting encryption keys.", "Start verification": "Start verification", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 9b46f9406b..9e8cd7a672 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -114,6 +114,12 @@ export const SETTINGS = { supportedLevels: LEVELS_FEATURE, default: false, }, + "feature_sas": { + isFeature: true, + displayName: _td("Two-way device verification using short text"), + supportedLevels: LEVELS_FEATURE, + default: false, + }, "MessageComposerInput.dontSuggestEmoji": { supportedLevels: LEVELS_ACCOUNT_SETTINGS, displayName: _td('Disable Emoji suggestions while typing'), From ec2d51cbbbe34c26adaa1ba5072b457022894339 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 18 Jan 2019 16:56:49 +0000 Subject: [PATCH 02/10] SAS verification screen matching design --- res/css/_components.scss | 1 + res/css/views/elements/_HexVerify.scss | 34 ++++++ .../views/dialogs/DeviceVerifyDialog.js | 17 ++- .../views/dialogs/IncomingSasDialog.js | 17 ++- src/components/views/elements/HexVerify.js | 104 ++++++++++++++++++ src/i18n/strings/en_EN.json | 2 +- 6 files changed, 168 insertions(+), 7 deletions(-) create mode 100644 res/css/views/elements/_HexVerify.scss create mode 100644 src/components/views/elements/HexVerify.js diff --git a/res/css/_components.scss b/res/css/_components.scss index 1e2d7ae156..70c2f17e9a 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -60,6 +60,7 @@ @import "./views/elements/_DirectorySearchBox.scss"; @import "./views/elements/_Dropdown.scss"; @import "./views/elements/_EditableItemList.scss"; +@import "./views/elements/_HexVerify.scss"; @import "./views/elements/_ImageView.scss"; @import "./views/elements/_InlineSpinner.scss"; @import "./views/elements/_MemberEventListSummary.scss"; diff --git a/res/css/views/elements/_HexVerify.scss b/res/css/views/elements/_HexVerify.scss new file mode 100644 index 0000000000..3f3ee4b7ea --- /dev/null +++ b/res/css/views/elements/_HexVerify.scss @@ -0,0 +1,34 @@ +/* +Copyright 2019 New Vector Ltd. + +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_HexVerify { + text-align: center; +} + +.mx_HexVerify_pair { + display: inline-block; + font-weight: bold; + padding-left: 3px; + padding-right: 3px; +} + +.mx_HexVerify_pair_verified { + color: $accent-color; +} + +.mx_HexVerify_pair:hover{ + color: $accent-color; +} diff --git a/src/components/views/dialogs/DeviceVerifyDialog.js b/src/components/views/dialogs/DeviceVerifyDialog.js index 169dc26c52..eabae56e25 100644 --- a/src/components/views/dialogs/DeviceVerifyDialog.js +++ b/src/components/views/dialogs/DeviceVerifyDialog.js @@ -50,6 +50,7 @@ export default class DeviceVerifyDialog extends React.Component { this.state = { phase: PHASE_START, mode: SettingsStore.isFeatureEnabled("feature_sas") ? MODE_SAS : MODE_LEGACY, + sasVerified: false, }; } @@ -102,6 +103,10 @@ export default class DeviceVerifyDialog extends React.Component { }); } + _onVerifyStateChanged = (newVal) => { + this.setState({sasVerified: newVal}); + } + _onSasMatchesClick = () => { this._showSasEvent.confirm(); this.setState({ @@ -127,7 +132,6 @@ export default class DeviceVerifyDialog extends React.Component { body = this._renderSasVerificationPhaseStart(); break; case PHASE_WAIT_FOR_PARTNER_TO_ACCEPT: - //body = this._renderSasVerificationPhaseWaitForPartnerToAccept(); body = renderSasWaitAccept(this.props.userId); break; case PHASE_SHOW_SAS: @@ -180,6 +184,7 @@ export default class DeviceVerifyDialog extends React.Component { _renderSasVerificationPhaseShowSas() { const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + const HexVerify = sdk.getComponent('views.elements.HexVerify'); return

{_t( "Verify this user by confirming the following number appears on their screen" @@ -188,9 +193,15 @@ export default class DeviceVerifyDialog extends React.Component { "For maximum security, we reccommend you do this in person or use another " + "trusted means of communication" )}

-
{this._showSasEvent.sas}
+ +

{_t( + "To continue, click on each pair to confirm it's correct.", + )}

diff --git a/src/components/views/dialogs/IncomingSasDialog.js b/src/components/views/dialogs/IncomingSasDialog.js index 732ce2a461..947c757f80 100644 --- a/src/components/views/dialogs/IncomingSasDialog.js +++ b/src/components/views/dialogs/IncomingSasDialog.js @@ -38,6 +38,7 @@ export default class IncomingSasDialog extends React.Component { this._showSasEvent = null; this.state = { phase: PHASE_START, + sasVerified: false, }; this.props.verifier.on('show_sas', this._onVerifierShowSas); this.props.verifier.on('cancel', this._onVerifierCancel); @@ -81,6 +82,10 @@ export default class IncomingSasDialog extends React.Component { }); } + _onVerifiedStateChange = (newVal) => { + this.setState({sasVerified: newVal}); + } + _onSasMatchesClick = () => { this._showSasEvent.confirm(); this.setState({ @@ -121,6 +126,7 @@ export default class IncomingSasDialog extends React.Component { _renderPhaseShowSas() { const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + const HexVerify = sdk.getComponent('views.elements.HexVerify'); return

{_t( "Verify this user by confirming the following number appears on their screen" @@ -129,9 +135,15 @@ export default class IncomingSasDialog extends React.Component { "For maximum security, we reccommend you do this in person or use another " + "trusted means of communication" )}

-
{this._showSasEvent.sas}
+ +

{_t( + "To continue, click on each pair to confirm it's correct.", + )}

@@ -184,7 +196,6 @@ export default class IncomingSasDialog extends React.Component { } render() { - console.log("rendering pahse "+this.state.phase); let body; switch (this.state.phase) { case PHASE_START: diff --git a/src/components/views/elements/HexVerify.js b/src/components/views/elements/HexVerify.js new file mode 100644 index 0000000000..667857a792 --- /dev/null +++ b/src/components/views/elements/HexVerify.js @@ -0,0 +1,104 @@ +/* +Copyright 2019 New Vector Ltd. + +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 classnames from 'classnames'; + +import sdk from '../../../index'; + +class HexVerifyPair extends React.Component { + static propTypes = { + text: PropTypes.string.isRequired, + index: PropTypes.number, + verified: PropTypes.bool, + onChange: PropTypes.func.isRequired, + } + + _onClick = () => { + this.setState({verified: !this.props.verified}); + this.props.onChange(this.props.index, !this.props.verified); + } + + render() { + const classNames = { + mx_HexVerify_pair: true, + mx_HexVerify_pair_verified: this.props.verified, + }; + const AccessibleButton = sdk.getComponent('views.elements.AccessibleButton'); + return + {this.props.text} + + } +} + +/** + * Helps a user verify a hexadecimal code matches one displayed + * elsewhere (eg. on a different device) + */ +export default class HexVerify extends React.Component { + static propTypes = { + text: PropTypes.string.isRequired, + onVerifiedStateChange: PropTypes.func, + } + + static defaultProps = { + onVerifiedStateChange: function() {}, + } + + constructor(props) { + super(props); + this.state = { + pairsVerified: [], + }; + for (let i = 0; i < props.text.length; i += 2) { + this.state.pairsVerified.push(false); + } + } + + _onPairChange = (index, newVal) => { + const oldVerified = this.state.pairsVerified.reduce((acc, val) => { + return acc && val; + }, true); + const newPairsVerified = this.state.pairsVerified.slice(0); + newPairsVerified[index] = newVal; + const newVerified = newPairsVerified.reduce((acc, val) => { + return acc && val; + }, true); + this.setState({pairsVerified: newPairsVerified}); + if (oldVerified !== newVerified) { + this.props.onVerifiedStateChange(newVerified); + } + } + + render() { + const pairs = []; + + for (let i = 0; i < this.props.text.length / 2; ++i) { + pairs.push(); + } + return
+ {pairs} +
; + } +} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index c26330dda4..7f61a13a21 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -947,7 +947,7 @@ "Send Verification Request": "Send Verification Request", "Verify this user by confirming the following number appears on their screen": "Verify this user by confirming the following number appears on their screen", "For maximum security, we reccommend you do this in person or use another trusted means of communication": "For maximum security, we reccommend you do this in person or use another trusted means of communication", - "This Matches": "This Matches", + "To continue, click on each pair to confirm it's correct.": "To continue, click on each pair to confirm it's correct.", "Verification complete!": "Verification complete!", "Done": "Done", "%(userId)s cancelled the verification.": "%(userId)s cancelled the verification.", From 4f2f2f4f4ee57e1d73191d6e64fd9ab39987b70e Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 18 Jan 2019 18:24:38 +0000 Subject: [PATCH 03/10] Move common UI bits out to separate components --- .../views/dialogs/DeviceVerifyDialog.js | 65 ++++--------------- .../views/dialogs/IncomingSasDialog.js | 65 +++---------------- .../verification/VerificationCancelled.js | 40 ++++++++++++ .../verification/VerificationComplete.js | 42 ++++++++++++ .../views/verification/VerificationShowSas.js | 65 +++++++++++++++++++ src/i18n/strings/en_EN.json | 25 +++---- 6 files changed, 184 insertions(+), 118 deletions(-) create mode 100644 src/components/views/verification/VerificationCancelled.js create mode 100644 src/components/views/verification/VerificationComplete.js create mode 100644 src/components/views/verification/VerificationShowSas.js diff --git a/src/components/views/dialogs/DeviceVerifyDialog.js b/src/components/views/dialogs/DeviceVerifyDialog.js index eabae56e25..cc5c8c6ef9 100644 --- a/src/components/views/dialogs/DeviceVerifyDialog.js +++ b/src/components/views/dialogs/DeviceVerifyDialog.js @@ -103,10 +103,6 @@ export default class DeviceVerifyDialog extends React.Component { }); } - _onVerifyStateChanged = (newVal) => { - this.setState({sasVerified: newVal}); - } - _onSasMatchesClick = () => { this._showSasEvent.confirm(); this.setState({ @@ -170,10 +166,16 @@ export default class DeviceVerifyDialog extends React.Component { {_t("Use Legacy Verification (for older clients)")}

- { _t("Do clicky clicky button press request verify user send to do.") } + { _t("Verify by comparing a short text string.") } +

+

+ {_t( + "For maximum security, we recommend you do this in person or " + + "use another trusted means of communication.", + )}

-

{_t( - "Verify this user by confirming the following number appears on their screen" - )}

-

{_t( - "For maximum security, we reccommend you do this in person or use another " + - "trusted means of communication" - )}

- -

{_t( - "To continue, click on each pair to confirm it's correct.", - )}

- -
; + const VerificationShowSas = sdk.getComponent('views.verification.VerificationShowSas'); + return } _renderSasVerificationPhaseWaitForPartnerToConfirm() { @@ -219,31 +200,13 @@ export default class DeviceVerifyDialog extends React.Component { } _renderSasVerificationPhaseVerified() { - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - return
-

{_t("Verification complete!")}

- -
; + const VerificationComplete = sdk.getComponent('views.verification.VerificationComplete'); + return } _renderSasVerificationPhaseCancelled() { - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - - return ( -
-

{_t( - "%(userId)s cancelled the verification.", {userId: this.props.userId}, - )}

- -
- ); + const VerificationCancelled = sdk.getComponent('views.verification.VerificationCancelled'); + return } _renderLegacyVerification() { diff --git a/src/components/views/dialogs/IncomingSasDialog.js b/src/components/views/dialogs/IncomingSasDialog.js index 947c757f80..331b4fc67c 100644 --- a/src/components/views/dialogs/IncomingSasDialog.js +++ b/src/components/views/dialogs/IncomingSasDialog.js @@ -82,10 +82,6 @@ export default class IncomingSasDialog extends React.Component { }); } - _onVerifiedStateChange = (newVal) => { - this.setState({sasVerified: newVal}); - } - _onSasMatchesClick = () => { this._showSasEvent.confirm(); this.setState({ @@ -125,29 +121,12 @@ export default class IncomingSasDialog extends React.Component { } _renderPhaseShowSas() { - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - const HexVerify = sdk.getComponent('views.elements.HexVerify'); - return
-

{_t( - "Verify this user by confirming the following number appears on their screen" - )}

-

{_t( - "For maximum security, we reccommend you do this in person or use another " + - "trusted means of communication" - )}

- -

{_t( - "To continue, click on each pair to confirm it's correct.", - )}

- -
; + const VerificationShowSas = sdk.getComponent('views.verification.VerificationShowSas'); + return } _renderPhaseWaitForPartnerToConfirm() { @@ -162,37 +141,13 @@ export default class IncomingSasDialog extends React.Component { } _renderPhaseVerified() { - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - - return ( -
-

{_t( - "Verification Complete!" - )}

- -
- ); + const VerificationComplete = sdk.getComponent('views.verification.VerificationComplete'); + return } _renderPhaseCancelled() { - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - - return ( -
-

{_t( - "The other party cancelled the verification." - )}

- -
- ); + const VerificationCancelled = sdk.getComponent('views.verification.VerificationCancelled'); + return } render() { diff --git a/src/components/views/verification/VerificationCancelled.js b/src/components/views/verification/VerificationCancelled.js new file mode 100644 index 0000000000..7c08d9eb07 --- /dev/null +++ b/src/components/views/verification/VerificationCancelled.js @@ -0,0 +1,40 @@ +/* +Copyright 2019 Vector Creations Ltd + +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 sdk from '../../../index'; +import { _t } from '../../../languageHandler'; + +export default class VerificationCancelled extends React.Component { + static propTypes = { + onDone: PropTypes.func.isRequired, + } + + render() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + return
+

{_t( + "The other party cancelled the verification.", + )}

+ +
; + } +}; diff --git a/src/components/views/verification/VerificationComplete.js b/src/components/views/verification/VerificationComplete.js new file mode 100644 index 0000000000..5153ae6650 --- /dev/null +++ b/src/components/views/verification/VerificationComplete.js @@ -0,0 +1,42 @@ +/* +Copyright 2019 Vector Creations Ltd + +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 sdk from '../../../index'; +import { _t } from '../../../languageHandler'; + +export default class VerificationComplete extends React.Component { + static propTypes = { + onDone: PropTypes.func.isRequired, + } + + render() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + return
+

{_t("Verified!")}

+

{_t("You've successfully verified this user.")}

+

{_t( + "Secure messages with this user are end-to-end encrypted and not able to be " + + "read by third parties.", + )}

+ +
; + } +}; diff --git a/src/components/views/verification/VerificationShowSas.js b/src/components/views/verification/VerificationShowSas.js new file mode 100644 index 0000000000..b9b5b27ac9 --- /dev/null +++ b/src/components/views/verification/VerificationShowSas.js @@ -0,0 +1,65 @@ +/* +Copyright 2019 Vector Creations Ltd + +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 sdk from '../../../index'; +import { _t } from '../../../languageHandler'; + +export default class VerificationShowSas extends React.Component { + static propTypes = { + onDone: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired, + sas: PropTypes.string.isRequired, + } + + constructor() { + super(); + this.state = { + sasVerified: false, + }; + } + + _onVerifiedStateChange = (newVal) => { + this.setState({sasVerified: newVal}); + } + + render() { + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + const HexVerify = sdk.getComponent('views.elements.HexVerify'); + return
+

{_t( + "Verify this user by confirming the following number appears on their screen" + )}

+

{_t( + "For maximum security, we reccommend you do this in person or use another " + + "trusted means of communication" + )}

+ +

{_t( + "To continue, click on each pair to confirm it's correct.", + )}

+ +
; + } +}; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 7f61a13a21..8cac02d9bd 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -320,6 +320,16 @@ "Incoming call from %(name)s": "Incoming call from %(name)s", "Decline": "Decline", "Accept": "Accept", + "The other party cancelled the verification.": "The other party cancelled the verification.", + "Cancel": "Cancel", + "Verified!": "Verified!", + "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.", + "Got It": "Got It", + "Verify this user by confirming the following number appears on their screen": "Verify this user by confirming the following number appears on their screen", + "For maximum security, we reccommend you do this in person or use another trusted means of communication": "For maximum security, we reccommend you do this in person or use another trusted means of communication", + "To continue, click on each pair to confirm it's correct.": "To continue, click on each pair to confirm it's correct.", + "Continue": "Continue", "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains": "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains", "Incorrect verification code": "Incorrect verification code", "Enter Code": "Enter Code", @@ -334,7 +344,6 @@ "Passwords can't be empty": "Passwords can't be empty", "Warning!": "Warning!", "Changing password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.": "Changing password will currently reset any end-to-end encryption keys on all devices, making encrypted chat history unreadable, unless you first export your room keys and re-import them afterwards. In future this will be improved.", - "Continue": "Continue", "Export E2E room keys": "Export E2E room keys", "Do you want to set an email address?": "Do you want to set an email address?", "Current password": "Current password", @@ -648,7 +657,6 @@ "Search…": "Search…", "This Room": "This Room", "All Rooms": "All Rooms", - "Cancel": "Cancel", "You don't currently have any stickerpacks enabled": "You don't currently have any stickerpacks enabled", "Add some now": "Add some now", "Stickerpack": "Stickerpack", @@ -943,14 +951,9 @@ "password": "password", "Verify device": "Verify device", "Use Legacy Verification (for older clients)": "Use Legacy Verification (for older clients)", - "Do clicky clicky button press request verify user send to do.": "Do clicky clicky button press request verify user send to do.", - "Send Verification Request": "Send Verification Request", - "Verify this user by confirming the following number appears on their screen": "Verify this user by confirming the following number appears on their screen", - "For maximum security, we reccommend you do this in person or use another trusted means of communication": "For maximum security, we reccommend you do this in person or use another trusted means of communication", - "To continue, click on each pair to confirm it's correct.": "To continue, click on each pair to confirm it's correct.", - "Verification complete!": "Verification complete!", - "Done": "Done", - "%(userId)s cancelled the verification.": "%(userId)s cancelled the verification.", + "Verify by comparing a short text string.": "Verify by comparing a short text string.", + "For maximum security, we recommend you do this in person or use another trusted means of communication.": "For maximum security, we recommend you do this in person or use another trusted means of communication.", + "Begin Verifying": "Begin Verifying", "Use two-way text verification": "Use two-way text verification", "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:": "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:", "Device name": "Device name", @@ -976,8 +979,6 @@ "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.": "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.", "Verifying this user will mark their device as trusted, and also mark your device as trusted to them": "Verifying this user will mark their device as trusted, and also mark your device as trusted to them", "Waiting for partner to confirm...": "Waiting for partner to confirm...", - "Verification Complete!": "Verification Complete!", - "The other party cancelled the verification.": "The other party cancelled the verification.", "Incoming Verification Request": "Incoming Verification Request", "You added a new device '%(displayName)s', which is requesting encryption keys.": "You added a new device '%(displayName)s', which is requesting encryption keys.", "Your unverified device '%(displayName)s' is requesting encryption keys.": "Your unverified device '%(displayName)s' is requesting encryption keys.", From 630a6a479bad5e258434b7ec761777cef143d361 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 18 Jan 2019 18:43:40 +0000 Subject: [PATCH 04/10] Lint --- src/components/views/dialogs/DeviceVerifyDialog.js | 10 +++++++--- src/components/views/dialogs/IncomingSasDialog.js | 12 +++++------- src/components/views/elements/HexVerify.js | 7 +++---- .../views/verification/VerificationCancelled.js | 2 +- .../views/verification/VerificationComplete.js | 2 +- .../views/verification/VerificationShowSas.js | 6 +++--- 6 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/components/views/dialogs/DeviceVerifyDialog.js b/src/components/views/dialogs/DeviceVerifyDialog.js index cc5c8c6ef9..c2c754c715 100644 --- a/src/components/views/dialogs/DeviceVerifyDialog.js +++ b/src/components/views/dialogs/DeviceVerifyDialog.js @@ -186,7 +186,11 @@ export default class DeviceVerifyDialog extends React.Component { _renderSasVerificationPhaseShowSas() { const VerificationShowSas = sdk.getComponent('views.verification.VerificationShowSas'); - return + return ; } _renderSasVerificationPhaseWaitForPartnerToConfirm() { @@ -201,12 +205,12 @@ export default class DeviceVerifyDialog extends React.Component { _renderSasVerificationPhaseVerified() { const VerificationComplete = sdk.getComponent('views.verification.VerificationComplete'); - return + return ; } _renderSasVerificationPhaseCancelled() { const VerificationCancelled = sdk.getComponent('views.verification.VerificationCancelled'); - return + return ; } _renderLegacyVerification() { diff --git a/src/components/views/dialogs/IncomingSasDialog.js b/src/components/views/dialogs/IncomingSasDialog.js index 331b4fc67c..bad1377457 100644 --- a/src/components/views/dialogs/IncomingSasDialog.js +++ b/src/components/views/dialogs/IncomingSasDialog.js @@ -16,10 +16,8 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import MatrixClientPeg from '../../../MatrixClientPeg'; import sdk from '../../../index'; import { _t } from '../../../languageHandler'; -import {verificationMethods} from 'matrix-js-sdk/lib/crypto'; const PHASE_START = 0; const PHASE_SHOW_SAS = 1; @@ -102,13 +100,13 @@ export default class IncomingSasDialog extends React.Component {

{_t( "Verify this user to mark them as trusted. " + "Trusting users gives you extra peace of mind when using " + - "end-to-end encrypted messages." + "end-to-end encrypted messages.", )}

{_t( // NB. Below wording adjusted to singular 'device' until we have // cross-signing "Verifying this user will mark their device as trusted, and " + - "also mark your device as trusted to them" + "also mark your device as trusted to them", )}

+ />; } _renderPhaseWaitForPartnerToConfirm() { @@ -142,12 +140,12 @@ export default class IncomingSasDialog extends React.Component { _renderPhaseVerified() { const VerificationComplete = sdk.getComponent('views.verification.VerificationComplete'); - return + return ; } _renderPhaseCancelled() { const VerificationCancelled = sdk.getComponent('views.verification.VerificationCancelled'); - return + return ; } render() { diff --git a/src/components/views/elements/HexVerify.js b/src/components/views/elements/HexVerify.js index 667857a792..86ead3adc1 100644 --- a/src/components/views/elements/HexVerify.js +++ b/src/components/views/elements/HexVerify.js @@ -16,7 +16,6 @@ limitations under the License. import React from "react"; import PropTypes from "prop-types"; -import { _t } from '../../../languageHandler'; import classnames from 'classnames'; import sdk from '../../../index'; @@ -40,15 +39,15 @@ class HexVerifyPair extends React.Component { mx_HexVerify_pair_verified: this.props.verified, }; const AccessibleButton = sdk.getComponent('views.elements.AccessibleButton'); - return {this.props.text} - + ; } } -/** +/* * Helps a user verify a hexadecimal code matches one displayed * elsewhere (eg. on a different device) */ diff --git a/src/components/views/verification/VerificationCancelled.js b/src/components/views/verification/VerificationCancelled.js index 7c08d9eb07..b21153f2cc 100644 --- a/src/components/views/verification/VerificationCancelled.js +++ b/src/components/views/verification/VerificationCancelled.js @@ -37,4 +37,4 @@ export default class VerificationCancelled extends React.Component { />
; } -}; +} diff --git a/src/components/views/verification/VerificationComplete.js b/src/components/views/verification/VerificationComplete.js index 5153ae6650..59f7ff924a 100644 --- a/src/components/views/verification/VerificationComplete.js +++ b/src/components/views/verification/VerificationComplete.js @@ -39,4 +39,4 @@ export default class VerificationComplete extends React.Component { /> ; } -}; +} diff --git a/src/components/views/verification/VerificationShowSas.js b/src/components/views/verification/VerificationShowSas.js index b9b5b27ac9..60f70e2748 100644 --- a/src/components/views/verification/VerificationShowSas.js +++ b/src/components/views/verification/VerificationShowSas.js @@ -42,11 +42,11 @@ export default class VerificationShowSas extends React.Component { const HexVerify = sdk.getComponent('views.elements.HexVerify'); return

{_t( - "Verify this user by confirming the following number appears on their screen" + "Verify this user by confirming the following number appears on their screen", )}

{_t( "For maximum security, we reccommend you do this in person or use another " + - "trusted means of communication" + "trusted means of communication", )}

; } -}; +} From 60a8d560d1b0e62e67d952338049fe12760a50a3 Mon Sep 17 00:00:00 2001 From: David Baker Date: Sat, 19 Jan 2019 11:54:01 +0000 Subject: [PATCH 05/10] Undo abortive first attempt at factoring out --- src/components/views/dialogs/DeviceVerifyDialog.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/components/views/dialogs/DeviceVerifyDialog.js b/src/components/views/dialogs/DeviceVerifyDialog.js index c2c754c715..68a2210814 100644 --- a/src/components/views/dialogs/DeviceVerifyDialog.js +++ b/src/components/views/dialogs/DeviceVerifyDialog.js @@ -24,7 +24,6 @@ import * as FormattingUtils from '../../../utils/FormattingUtils'; import { _t } from '../../../languageHandler'; import SettingsStore from '../../../settings/SettingsStore'; import {verificationMethods} from 'matrix-js-sdk/lib/crypto'; -import {renderSasWaitAccept} from '../../../sas_ui'; const MODE_LEGACY = 'legacy'; const MODE_SAS = 'sas'; @@ -128,7 +127,7 @@ export default class DeviceVerifyDialog extends React.Component { body = this._renderSasVerificationPhaseStart(); break; case PHASE_WAIT_FOR_PARTNER_TO_ACCEPT: - body = renderSasWaitAccept(this.props.userId); + body = this._renderSasVerificationPhaseWaitAccept(); break; case PHASE_SHOW_SAS: body = this._renderSasVerificationPhaseShowSas(); @@ -184,6 +183,17 @@ export default class DeviceVerifyDialog extends React.Component { ); } + _renderSasVerificationPhaseWaitAccept() { + const Spinner = sdk.getComponent("views.elements.Spinner"); + + return ( +
+ +

{_t("Waiting for partner to accept...")}

+
+ ); + } + _renderSasVerificationPhaseShowSas() { const VerificationShowSas = sdk.getComponent('views.verification.VerificationShowSas'); return Date: Wed, 23 Jan 2019 17:41:15 +0000 Subject: [PATCH 06/10] Re-do npm run i18n because things got weird --- src/i18n/strings/en_EN.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 9ab0d6b428..fdff3d4199 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -441,6 +441,7 @@ "Encrypted by an unverified device": "Encrypted by an unverified device", "Unencrypted message": "Unencrypted message", "Please select the destination room for this message": "Please select the destination room for this message", + "Scroll to bottom of page": "Scroll to bottom of page", "Blacklisted": "Blacklisted", "Verified": "Verified", "Unverified": "Unverified", @@ -923,6 +924,8 @@ "Verify by comparing a short text string.": "Verify by comparing a short text string.", "For maximum security, we recommend you do this in person or use another trusted means of communication.": "For maximum security, we recommend you do this in person or use another trusted means of communication.", "Begin Verifying": "Begin Verifying", + "Waiting for partner to accept...": "Waiting for partner to accept...", + "Waiting for %(userId)s to confirm...": "Waiting for %(userId)s to confirm...", "Use two-way text verification": "Use two-way text verification", "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:": "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:", "Device name": "Device name", @@ -1083,6 +1086,8 @@ "Set status": "Set status", "Set a new status...": "Set a new status...", "View Community": "View Community", + "Login": "Login", + "powered by Matrix": "powered by Matrix", "Robot check is currently unavailable on desktop - please use a web browser": "Robot check is currently unavailable on desktop - please use a web browser", "This Home Server would like to make sure you are not a robot": "This Home Server would like to make sure you are not a robot", "Custom Server Options": "Custom Server Options", @@ -1100,7 +1105,6 @@ "Please enter the code it contains:": "Please enter the code it contains:", "Code": "Code", "Start authentication": "Start authentication", - "powered by Matrix": "powered by Matrix", "The email field must not be blank.": "The email field must not be blank.", "The user name field must not be blank.": "The user name field must not be blank.", "The phone number field must not be blank.": "The phone number field must not be blank.", @@ -1173,7 +1177,6 @@ "Couldn't load home page": "Couldn't load home page", "You are currently using Riot anonymously as a guest.": "You are currently using Riot anonymously as a guest.", "If you would like to create a Matrix account you can register now.": "If you would like to create a Matrix account you can register now.", - "Login": "Login", "Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Invalid configuration: Cannot supply a default homeserver URL and a default server name", "Failed to reject invitation": "Failed to reject invitation", "This room is not public. You will not be able to rejoin without an invite.": "This room is not public. You will not be able to rejoin without an invite.", @@ -1215,7 +1218,6 @@ "Directory": "Directory", "Search for a room": "Search for a room", "#example": "#example", - "Scroll to bottom of page": "Scroll to bottom of page", "Message not sent due to unknown devices being present": "Message not sent due to unknown devices being present", "Show devices, send anyway or cancel.": "Show devices, send anyway or cancel.", "You can't send any messages until you review and agree to our terms and conditions.": "You can't send any messages until you review and agree to our terms and conditions.", @@ -1227,8 +1229,6 @@ "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|one": "Resend message or cancel message now.", "Connectivity to the server has been lost.": "Connectivity to the server has been lost.", "Sent messages will be stored until your connection has returned.": "Sent messages will be stored until your connection has returned.", - "%(count)s new messages|other": "%(count)s new messages", - "%(count)s new messages|one": "%(count)s new message", "Active call": "Active call", "There's no one else here! Would you like to invite others or stop warning about the empty room?": "There's no one else here! Would you like to invite others or stop warning about the empty room?", "You seem to be uploading files, are you sure you want to quit?": "You seem to be uploading files, are you sure you want to quit?", From 44a5ee3e441df852532f4798b40a0be6d3480733 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 25 Jan 2019 17:30:22 +0000 Subject: [PATCH 07/10] Add fullstop Co-Authored-By: dbkr --- src/components/views/dialogs/IncomingSasDialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/dialogs/IncomingSasDialog.js b/src/components/views/dialogs/IncomingSasDialog.js index bad1377457..2a76e8a904 100644 --- a/src/components/views/dialogs/IncomingSasDialog.js +++ b/src/components/views/dialogs/IncomingSasDialog.js @@ -106,7 +106,7 @@ export default class IncomingSasDialog extends React.Component { // NB. Below wording adjusted to singular 'device' until we have // cross-signing "Verifying this user will mark their device as trusted, and " + - "also mark your device as trusted to them", + "also mark your device as trusted to them.", )}

Date: Fri, 25 Jan 2019 17:30:47 +0000 Subject: [PATCH 08/10] Fullstop Co-Authored-By: dbkr --- src/components/views/verification/VerificationShowSas.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/verification/VerificationShowSas.js b/src/components/views/verification/VerificationShowSas.js index 60f70e2748..4023da9679 100644 --- a/src/components/views/verification/VerificationShowSas.js +++ b/src/components/views/verification/VerificationShowSas.js @@ -42,7 +42,7 @@ export default class VerificationShowSas extends React.Component { const HexVerify = sdk.getComponent('views.elements.HexVerify'); return

{_t( - "Verify this user by confirming the following number appears on their screen", + "Verify this user by confirming the following number appears on their screen.", )}

{_t( "For maximum security, we reccommend you do this in person or use another " + From 939f8b5591c3e5f8385e77b3ba3b35f7c605e730 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 25 Jan 2019 17:30:59 +0000 Subject: [PATCH 09/10] Fullstop Co-Authored-By: dbkr --- src/components/views/verification/VerificationShowSas.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/verification/VerificationShowSas.js b/src/components/views/verification/VerificationShowSas.js index 4023da9679..cd4ae59b76 100644 --- a/src/components/views/verification/VerificationShowSas.js +++ b/src/components/views/verification/VerificationShowSas.js @@ -46,7 +46,7 @@ export default class VerificationShowSas extends React.Component { )}

{_t( "For maximum security, we reccommend you do this in person or use another " + - "trusted means of communication", + "trusted means of communication.", )}

Date: Fri, 25 Jan 2019 17:29:36 +0000 Subject: [PATCH 10/10] Remove outdated paragraph promising better verification --- src/components/views/dialogs/DeviceVerifyDialog.js | 3 --- src/i18n/strings/en_EN.json | 1 - 2 files changed, 4 deletions(-) diff --git a/src/components/views/dialogs/DeviceVerifyDialog.js b/src/components/views/dialogs/DeviceVerifyDialog.js index 68a2210814..e84010726d 100644 --- a/src/components/views/dialogs/DeviceVerifyDialog.js +++ b/src/components/views/dialogs/DeviceVerifyDialog.js @@ -253,9 +253,6 @@ export default class DeviceVerifyDialog extends React.Component { "If it doesn't, then someone else is intercepting this device " + "and you probably want to press the blacklist button instead.") }

-

- { _t("In future this verification process will be more sophisticated.") } -

); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index fdff3d4199..24e5f27e15 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -931,7 +931,6 @@ "Device name": "Device name", "Device key": "Device key", "If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.": "If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.", - "In future this verification process will be more sophisticated.": "In future this verification process will be more sophisticated.", "I verify that the keys match": "I verify that the keys match", "Back": "Back", "Send Custom Event": "Send Custom Event",