From 1353ddaa96a20514a697cd11d514ba2e99bd241f Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 31 Mar 2020 15:46:11 +0200 Subject: [PATCH 01/11] move qr code data generation to js-sdk --- .../elements/crypto/VerificationQRCode.js | 113 +----------------- .../views/right_panel/VerificationPanel.js | 32 +---- 2 files changed, 8 insertions(+), 137 deletions(-) diff --git a/src/components/views/elements/crypto/VerificationQRCode.js b/src/components/views/elements/crypto/VerificationQRCode.js index 3838aa61ff..5848107b61 100644 --- a/src/components/views/elements/crypto/VerificationQRCode.js +++ b/src/components/views/elements/crypto/VerificationQRCode.js @@ -17,95 +17,17 @@ limitations under the License. import React from "react"; import PropTypes from "prop-types"; import {replaceableComponent} from "../../../../utils/replaceableComponent"; -import {MatrixClientPeg} from "../../../../MatrixClientPeg"; -import {VerificationRequest} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; -import {ToDeviceChannel} from "matrix-js-sdk/src/crypto/verification/request/ToDeviceChannel"; -import {decodeBase64} from "matrix-js-sdk/src/crypto/olmlib"; import Spinner from "../Spinner"; import * as QRCode from "qrcode"; -const CODE_VERSION = 0x02; // the version of binary QR codes we support -const BINARY_PREFIX = "MATRIX"; // ASCII, used to prefix the binary format -const MODE_VERIFY_OTHER_USER = 0x00; // Verifying someone who isn't us -const MODE_VERIFY_SELF_TRUSTED = 0x01; // We trust the master key -const MODE_VERIFY_SELF_UNTRUSTED = 0x02; // We do not trust the master key - @replaceableComponent("views.elements.crypto.VerificationQRCode") export default class VerificationQRCode extends React.PureComponent { static propTypes = { - prefix: PropTypes.string.isRequired, - version: PropTypes.number.isRequired, - mode: PropTypes.number.isRequired, - transactionId: PropTypes.string.isRequired, // or requestEventId - firstKeyB64: PropTypes.string.isRequired, - secondKeyB64: PropTypes.string.isRequired, - secretB64: PropTypes.string.isRequired, + qrCodeData: PropTypes.Object.isRequired, }; - static async getPropsForRequest(verificationRequest: VerificationRequest) { - const cli = MatrixClientPeg.get(); - const myUserId = cli.getUserId(); - const otherUserId = verificationRequest.otherUserId; - - let mode = MODE_VERIFY_OTHER_USER; - if (myUserId === otherUserId) { - // Mode changes depending on whether or not we trust the master cross signing key - const myTrust = cli.checkUserTrust(myUserId); - if (myTrust.isCrossSigningVerified()) { - mode = MODE_VERIFY_SELF_TRUSTED; - } else { - mode = MODE_VERIFY_SELF_UNTRUSTED; - } - } - - const requestEvent = verificationRequest.requestEvent; - const transactionId = requestEvent.getId() - ? requestEvent.getId() - : ToDeviceChannel.getTransactionId(requestEvent); - - const qrProps = { - prefix: BINARY_PREFIX, - version: CODE_VERSION, - mode, - transactionId, - firstKeyB64: '', // worked out shortly - secondKeyB64: '', // worked out shortly - secretB64: verificationRequest.encodedSharedSecret, - }; - - const myCrossSigningInfo = cli.getStoredCrossSigningForUser(myUserId); - const myDevices = (await cli.getStoredDevicesForUser(myUserId)) || []; - - if (mode === MODE_VERIFY_OTHER_USER) { - // First key is our master cross signing key - qrProps.firstKeyB64 = myCrossSigningInfo.getId("master"); - - // Second key is the other user's master cross signing key - const otherUserCrossSigningInfo = cli.getStoredCrossSigningForUser(otherUserId); - qrProps.secondKeyB64 = otherUserCrossSigningInfo.getId("master"); - } else if (mode === MODE_VERIFY_SELF_TRUSTED) { - // First key is our master cross signing key - qrProps.firstKeyB64 = myCrossSigningInfo.getId("master"); - - // Second key is the other device's device key - const otherDevice = verificationRequest.targetDevice; - const otherDeviceId = otherDevice ? otherDevice.deviceId : null; - const device = myDevices.find(d => d.deviceId === otherDeviceId); - qrProps.secondKeyB64 = device.getFingerprint(); - } else if (mode === MODE_VERIFY_SELF_UNTRUSTED) { - // First key is our device's key - qrProps.firstKeyB64 = cli.getDeviceEd25519Key(); - - // Second key is what we think our master cross signing key is - qrProps.secondKeyB64 = myCrossSigningInfo.getId("master"); - } - - return qrProps; - } - constructor(props) { super(props); - this.state = { dataUri: null, }; @@ -119,39 +41,8 @@ export default class VerificationQRCode extends React.PureComponent { } async generateQrCode() { - let buf = Buffer.alloc(0); // we'll concat our way through life - - const appendByte = (b: number) => { - const tmpBuf = Buffer.from([b]); - buf = Buffer.concat([buf, tmpBuf]); - }; - const appendInt = (i: number) => { - const tmpBuf = Buffer.alloc(2); - tmpBuf.writeInt16BE(i, 0); - buf = Buffer.concat([buf, tmpBuf]); - }; - const appendStr = (s: string, enc: string, withLengthPrefix = true) => { - const tmpBuf = Buffer.from(s, enc); - if (withLengthPrefix) appendInt(tmpBuf.byteLength); - buf = Buffer.concat([buf, tmpBuf]); - }; - const appendEncBase64 = (b64: string) => { - const b = decodeBase64(b64); - const tmpBuf = Buffer.from(b); - buf = Buffer.concat([buf, tmpBuf]); - }; - - // Actually build the buffer for the QR code - appendStr(this.props.prefix, "ascii", false); - appendByte(this.props.version); - appendByte(this.props.mode); - appendStr(this.props.transactionId, "utf-8"); - appendEncBase64(this.props.firstKeyB64); - appendEncBase64(this.props.secondKeyB64); - appendEncBase64(this.props.secretB64); - // Now actually assemble the QR code's data URI - const uri = await QRCode.toDataURL([{data: buf, mode: 'byte'}], { + const uri = await QRCode.toDataURL([{data: this.props.qrCodeData.buffer, mode: 'byte'}], { errorCorrectionLevel: 'L', // we want it as trivial-looking as possible }); this.setState({dataUri: uri}); diff --git a/src/components/views/right_panel/VerificationPanel.js b/src/components/views/right_panel/VerificationPanel.js index 7ba1fb829a..62a552e9a4 100644 --- a/src/components/views/right_panel/VerificationPanel.js +++ b/src/components/views/right_panel/VerificationPanel.js @@ -30,7 +30,7 @@ import { PHASE_READY, PHASE_DONE, PHASE_STARTED, - PHASE_CANCELLED, VerificationRequest, + PHASE_CANCELLED, } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; import Spinner from "../elements/Spinner"; @@ -53,22 +53,8 @@ export default class VerificationPanel extends React.PureComponent { constructor(props) { super(props); - this.state = { - qrCodeProps: null, // generated by the VerificationQRCode component itself - }; + this.state = {}; this._hasVerifier = false; - if (this.props.request.otherPartySupportsMethod(SCAN_QR_CODE_METHOD)) { - this._generateQRCodeProps(props.request); - } - } - - async _generateQRCodeProps(verificationRequest: VerificationRequest) { - try { - this.setState({qrCodeProps: await VerificationQRCode.getPropsForRequest(verificationRequest)}); - } catch (e) { - console.error(e); - // Do nothing - we won't render a QR code. - } } renderQRPhase(pending) { @@ -86,16 +72,10 @@ export default class VerificationPanel extends React.PureComponent { let qrBlock; let sasBlock; if (showQR) { - let qrCode; - if (this.state.qrCodeProps) { - qrCode = ; - } else { - qrCode =
; - } qrBlock =

{_t("Scan this unique code")}

- {qrCode} +
; } if (showSAS) { @@ -124,7 +104,7 @@ export default class VerificationPanel extends React.PureComponent { } let qrBlock; - if (this.state.qrCodeProps) { + if (showQR) { qrBlock =

{_t("Verify by scanning")}

{_t("Ask %(displayName)s to scan your code:", { @@ -132,7 +112,7 @@ export default class VerificationPanel extends React.PureComponent { })}

- +
; } @@ -150,7 +130,7 @@ export default class VerificationPanel extends React.PureComponent { ); } - const sasLabel = this.state.qrCodeProps ? + const sasLabel = showQR ? _t("If you can't scan the code above, verify by comparing unique emoji.") : _t("Verify by comparing unique emoji."); sasBlock =
From 00b1afe0fa88a1fa53b743bdc3f6919c54682a95 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 31 Mar 2020 15:46:41 +0200 Subject: [PATCH 02/11] first go at reciprocate UX --- .../views/right_panel/VerificationPanel.js | 96 ++++++++++++------- 1 file changed, 62 insertions(+), 34 deletions(-) diff --git a/src/components/views/right_panel/VerificationPanel.js b/src/components/views/right_panel/VerificationPanel.js index 62a552e9a4..58d07e318c 100644 --- a/src/components/views/right_panel/VerificationPanel.js +++ b/src/components/views/right_panel/VerificationPanel.js @@ -57,7 +57,7 @@ export default class VerificationPanel extends React.PureComponent { this._hasVerifier = false; } - renderQRPhase(pending) { + renderQRPhase() { const {member, request} = this.props; const showSAS = request.otherPartySupportsMethod(verificationMethods.SAS); const showQR = request.otherPartySupportsMethod(SCAN_QR_CODE_METHOD); @@ -119,24 +119,16 @@ export default class VerificationPanel extends React.PureComponent { let sasBlock; if (showSAS) { - let button; - if (pending) { - button = ; - } else { - const disabled = this.state.emojiButtonClicked; - button = ( - - {_t("Verify by emoji")} - - ); - } + const disabled = this.state.emojiButtonClicked; const sasLabel = showQR ? _t("If you can't scan the code above, verify by comparing unique emoji.") : _t("Verify by comparing unique emoji."); sasBlock =

{_t("Verify by emoji")}

{sasLabel}

- { button } + + {_t("Verify by emoji")} +
; } @@ -152,6 +144,30 @@ export default class VerificationPanel extends React.PureComponent { ; } + renderQRReciprocatePhase() { + const {member} = this.props; + const FormButton = sdk.getComponent("elements.FormButton"); + + let body; + if (this.state.reciprocateQREvent) { + // riot web doesn't support scanning yet, so assume here we're the client being scanned. + body = +

{_t("Almost there! Is %(displayName)s show the same shield?", { + displayName: member.displayName || member.name || member.userId, + })}

+ +

+

+
; + } else { + body =

; + } + return
+

{_t("Verify by scanning")}

+ { body } +
; + } + renderVerifiedPhase() { const {member} = this.props; @@ -208,7 +224,7 @@ export default class VerificationPanel extends React.PureComponent { } render() { - const {member, phase} = this.props; + const {member, phase, request} = this.props; const displayName = member.displayName || member.name || member.userId; @@ -216,20 +232,26 @@ export default class VerificationPanel extends React.PureComponent { case PHASE_READY: return this.renderQRPhase(); case PHASE_STARTED: - if (this.state.sasEvent) { - const VerificationShowSas = sdk.getComponent('views.verification.VerificationShowSas'); - return
-

{_t("Compare emoji")}

- -
; - } else { - return this.renderQRPhase(true); // keep showing same phase but with a spinner + switch (request.chosenMethod) { + case verificationMethods.RECIPROCATE_QR_CODE: + return this.renderQRReciprocatePhase(); + case verificationMethods.SAS: { + const VerificationShowSas = sdk.getComponent('views.verification.VerificationShowSas'); + const emojis = this.state.sasEvent ? + : ; + return
+

{_t("Compare emoji")}

+ { emojis } +
; + } + default: + return null; } case PHASE_DONE: return this.renderVerifiedPhase(); @@ -258,10 +280,12 @@ export default class VerificationPanel extends React.PureComponent { this.state.sasEvent.mismatch(); }; - _onVerifierShowSas = (sasEvent) => { + _updateVerifierState = () => { const {request} = this.props; - request.verifier.off('show_sas', this._onVerifierShowSas); - this.setState({sasEvent}); + const {sasEvent, reciprocateQREvent} = request; + request.verifier.off('show_sas', this._updateVerifierState); + request.verifier.off('show_reciprocate_qr', this._updateVerifierState); + this.setState({sasEvent, reciprocateQREvent}); }; _onRequestChange = async () => { @@ -269,7 +293,8 @@ export default class VerificationPanel extends React.PureComponent { const hadVerifier = this._hasVerifier; this._hasVerifier = !!request.verifier; if (!hadVerifier && this._hasVerifier) { - request.verifier.on('show_sas', this._onVerifierShowSas); + request.verifier.on('show_sas', this._updateVerifierState); + request.verifier.on('show_reciprocate_qr', this._updateVerifierState); try { // on the requester side, this is also awaited in _startSAS, // but that's ok as verify should return the same promise. @@ -284,7 +309,9 @@ export default class VerificationPanel extends React.PureComponent { const {request} = this.props; request.on("change", this._onRequestChange); if (request.verifier) { - this.setState({sasEvent: request.verifier.sasEvent}); + const {request} = this.props; + const {sasEvent, reciprocateQREvent} = request; + this.setState({sasEvent, reciprocateQREvent}); } this._onRequestChange(); } @@ -292,7 +319,8 @@ export default class VerificationPanel extends React.PureComponent { componentWillUnmount() { const {request} = this.props; if (request.verifier) { - request.verifier.off('show_sas', this._onVerifierShowSas); + request.verifier.off('show_sas', this._updateVerifierState); + request.verifier.off('show_reciprocate_qr', this._updateVerifierState); } request.off("change", this._onRequestChange); } From fd04f248c43e645eb95ef9aed759083b09392e84 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 1 Apr 2020 09:42:24 +0200 Subject: [PATCH 03/11] fix proptype typo --- src/components/views/elements/crypto/VerificationQRCode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/elements/crypto/VerificationQRCode.js b/src/components/views/elements/crypto/VerificationQRCode.js index 5848107b61..08cd0c772e 100644 --- a/src/components/views/elements/crypto/VerificationQRCode.js +++ b/src/components/views/elements/crypto/VerificationQRCode.js @@ -23,7 +23,7 @@ import * as QRCode from "qrcode"; @replaceableComponent("views.elements.crypto.VerificationQRCode") export default class VerificationQRCode extends React.PureComponent { static propTypes = { - qrCodeData: PropTypes.Object.isRequired, + qrCodeData: PropTypes.object.isRequired, }; constructor(props) { From 119fd2f5191a039314ad64b7db6e9e277dd267d4 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 2 Apr 2020 11:27:00 +0200 Subject: [PATCH 04/11] fixup: these are actually on the verifier --- src/components/views/right_panel/VerificationPanel.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/right_panel/VerificationPanel.js b/src/components/views/right_panel/VerificationPanel.js index 58d07e318c..c640c73055 100644 --- a/src/components/views/right_panel/VerificationPanel.js +++ b/src/components/views/right_panel/VerificationPanel.js @@ -282,7 +282,7 @@ export default class VerificationPanel extends React.PureComponent { _updateVerifierState = () => { const {request} = this.props; - const {sasEvent, reciprocateQREvent} = request; + const {sasEvent, reciprocateQREvent} = request.verifier; request.verifier.off('show_sas', this._updateVerifierState); request.verifier.off('show_reciprocate_qr', this._updateVerifierState); this.setState({sasEvent, reciprocateQREvent}); @@ -310,7 +310,7 @@ export default class VerificationPanel extends React.PureComponent { request.on("change", this._onRequestChange); if (request.verifier) { const {request} = this.props; - const {sasEvent, reciprocateQREvent} = request; + const {sasEvent, reciprocateQREvent} = request.verifier; this.setState({sasEvent, reciprocateQREvent}); } this._onRequestChange(); From a4f448d4ca34512c00ae2cda5cf63c59e6bffdfe Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 2 Apr 2020 11:36:05 +0200 Subject: [PATCH 05/11] update i18n --- src/i18n/strings/en_EN.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 24a6568d82..50dc06ce8b 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1249,9 +1249,12 @@ "The session you are trying to verify doesn't support scanning a QR code or emoji verification, which is what Riot supports. Try with a different client.": "The session you are trying to verify doesn't support scanning a QR code or emoji verification, which is what Riot supports. Try with a different client.", "Verify by scanning": "Verify by scanning", "Ask %(displayName)s to scan your code:": "Ask %(displayName)s to scan your code:", - "Verify by emoji": "Verify by 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.", "Verify by comparing unique emoji.": "Verify by comparing unique emoji.", + "Verify by emoji": "Verify by emoji", + "Almost there! Is %(displayName)s show the same shield?": "Almost there! Is %(displayName)s show the same shield?", + "No": "No", + "Yes": "Yes", "Verify all users in a room to ensure it's secure.": "Verify all users in a room to ensure it's secure.", "In encrypted rooms, verify all users to ensure it’s secure.": "In encrypted rooms, verify all users to ensure it’s secure.", "Verified": "Verified", @@ -1397,8 +1400,6 @@ "Verify...": "Verify...", "Join": "Join", "No results": "No results", - "Yes": "Yes", - "No": "No", "Please create a new issue on GitHub so that we can investigate this bug.": "Please create a new issue on GitHub so that we can investigate this bug.", "collapse": "collapse", "expand": "expand", From ccf6c9efdc407b9562ccd26704fbe72fdd255acb Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 2 Apr 2020 12:54:14 +0200 Subject: [PATCH 06/11] fixup: more i18n --- .../views/right_panel/_VerificationPanel.scss | 20 ++++++++++++++++--- .../views/right_panel/VerificationPanel.js | 6 +++--- src/i18n/strings/en_EN.json | 2 +- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/res/css/views/right_panel/_VerificationPanel.scss b/res/css/views/right_panel/_VerificationPanel.scss index 459622b277..ba74d46eaf 100644 --- a/res/css/views/right_panel/_VerificationPanel.scss +++ b/res/css/views/right_panel/_VerificationPanel.scss @@ -30,11 +30,15 @@ limitations under the License. right: 14px; } - .mx_VerificationPanel_verified_section .mx_E2EIcon { - // Override general user info margin - margin: 0 auto !important; + .mx_VerificationPanel_verified_section, + .mx_VerificationPanel_reciprocate_section { + .mx_E2EIcon { + // Override general user info margin + margin: 20px auto !important; + } } + .mx_VerificationPanel_qrCode { padding: 4px 4px 0 4px; background: white; @@ -51,6 +55,16 @@ limitations under the License. max-width: 240px; } } + + .mx_VerificationPanel_reciprocate_section { + .mx_FormButton { + width: 100%; + box-sizing: border-box; + padding: 10px; + display: block; + margin: 10px 0; + } + } } // Special case styling for EncryptionPanel in a Modal dialog diff --git a/src/components/views/right_panel/VerificationPanel.js b/src/components/views/right_panel/VerificationPanel.js index c640c73055..e2dd1f0408 100644 --- a/src/components/views/right_panel/VerificationPanel.js +++ b/src/components/views/right_panel/VerificationPanel.js @@ -156,13 +156,13 @@ export default class VerificationPanel extends React.PureComponent { displayName: member.displayName || member.name || member.userId, })}

-

-

+ + ; } else { body =

; } - return
+ return

{_t("Verify by scanning")}

{ body }
; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 50dc06ce8b..26dcfb7ee8 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1252,7 +1252,7 @@ "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.", "Verify by comparing unique emoji.": "Verify by comparing unique emoji.", "Verify by emoji": "Verify by emoji", - "Almost there! Is %(displayName)s show the same shield?": "Almost there! Is %(displayName)s show the same shield?", + "Almost there! Is %(displayName)s showing the same shield?": "Almost there! Is %(displayName)s showing the same shield?", "No": "No", "Yes": "Yes", "Verify all users in a room to ensure it's secure.": "Verify all users in a room to ensure it's secure.", From 1f65cfb7f69934a06161060e9a205742f47aa93a Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 2 Apr 2020 13:00:45 +0200 Subject: [PATCH 07/11] polish design and disable buttons after click --- .../views/right_panel/_VerificationPanel.scss | 15 ++++++++++ .../views/right_panel/VerificationPanel.js | 28 ++++++++++++++++--- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/res/css/views/right_panel/_VerificationPanel.scss b/res/css/views/right_panel/_VerificationPanel.scss index ba74d46eaf..3313e47c66 100644 --- a/res/css/views/right_panel/_VerificationPanel.scss +++ b/res/css/views/right_panel/_VerificationPanel.scss @@ -132,4 +132,19 @@ limitations under the License. float: right; } } + + .mx_VerificationPanel_reciprocate_section { + .mx_FormButton { + margin: 0 10px; + padding: 10px; + flex: 1; + } + + // show Yes/No buttons next to each other + .mx_VerificationPanel_reciprocateButtons { + display: flex; + flex-direction: row; + } + } + } diff --git a/src/components/views/right_panel/VerificationPanel.js b/src/components/views/right_panel/VerificationPanel.js index e2dd1f0408..103497169f 100644 --- a/src/components/views/right_panel/VerificationPanel.js +++ b/src/components/views/right_panel/VerificationPanel.js @@ -144,6 +144,16 @@ export default class VerificationPanel extends React.PureComponent { ; } + _onReciprocateYesClick = () => { + this.setState({reciprocateButtonClicked: true}); + this.state.reciprocateQREvent.confirm(); + }; + + _onReciprocateNoClick = () => { + this.setState({reciprocateButtonClicked: true}); + this.state.reciprocateQREvent.cancel(); + }; + renderQRReciprocatePhase() { const {member} = this.props; const FormButton = sdk.getComponent("elements.FormButton"); @@ -152,15 +162,25 @@ export default class VerificationPanel extends React.PureComponent { if (this.state.reciprocateQREvent) { // riot web doesn't support scanning yet, so assume here we're the client being scanned. body = -

{_t("Almost there! Is %(displayName)s show the same shield?", { +

{_t("Almost there! Is %(displayName)s showing the same shield?", { displayName: member.displayName || member.name || member.userId, })}

- - +
+ + +
; } else { - body =

; + body =

; } return

{_t("Verify by scanning")}

From 31ca52dedec20eeedbfac1b8f4e0cf88e75b84bd Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 2 Apr 2020 13:10:04 +0200 Subject: [PATCH 08/11] fix stylelint --- res/css/views/right_panel/_VerificationPanel.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/res/css/views/right_panel/_VerificationPanel.scss b/res/css/views/right_panel/_VerificationPanel.scss index 3313e47c66..e4e7e2dddc 100644 --- a/res/css/views/right_panel/_VerificationPanel.scss +++ b/res/css/views/right_panel/_VerificationPanel.scss @@ -146,5 +146,4 @@ limitations under the License. flex-direction: row; } } - } From 0307361fa2b815e841707d034bc58102d7d61c85 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 2 Apr 2020 16:42:39 +0200 Subject: [PATCH 09/11] more polish for self-verification --- .../views/right_panel/_VerificationPanel.scss | 33 ++++++++---------- .../views/right_panel/VerificationPanel.js | 34 ++++++++++++------- src/i18n/strings/en_EN.json | 1 + 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/res/css/views/right_panel/_VerificationPanel.scss b/res/css/views/right_panel/_VerificationPanel.scss index e4e7e2dddc..f8e5a54afb 100644 --- a/res/css/views/right_panel/_VerificationPanel.scss +++ b/res/css/views/right_panel/_VerificationPanel.scss @@ -13,6 +13,17 @@ 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_VerificationPanel_verified_section, +.mx_VerificationPanel_reciprocate_section { + // center the big shield icon + .mx_E2EIcon { + // Override general user info margin + margin: 20px auto !important; + } +} + .mx_UserInfo { .mx_EncryptionPanel_cancel { @@ -30,15 +41,6 @@ limitations under the License. right: 14px; } - .mx_VerificationPanel_verified_section, - .mx_VerificationPanel_reciprocate_section { - .mx_E2EIcon { - // Override general user info margin - margin: 20px auto !important; - } - } - - .mx_VerificationPanel_qrCode { padding: 4px 4px 0 4px; background: white; @@ -123,10 +125,6 @@ limitations under the License. // 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; @@ -134,16 +132,15 @@ limitations under the License. } .mx_VerificationPanel_reciprocate_section { - .mx_FormButton { - margin: 0 10px; - padding: 10px; - flex: 1; + .mx_AccessibleButton { + margin-left: 10px; + padding: 7px 40px; } - // show Yes/No buttons next to each other .mx_VerificationPanel_reciprocateButtons { display: flex; flex-direction: row; + justify-content: flex-end; } } } diff --git a/src/components/views/right_panel/VerificationPanel.js b/src/components/views/right_panel/VerificationPanel.js index 103497169f..840ece873c 100644 --- a/src/components/views/right_panel/VerificationPanel.js +++ b/src/components/views/right_panel/VerificationPanel.js @@ -18,6 +18,7 @@ import React from "react"; import PropTypes from "prop-types"; import * as sdk from '../../../index'; +import {MatrixClientPeg} from '../../../MatrixClientPeg'; import {verificationMethods} from 'matrix-js-sdk/src/crypto'; import {SCAN_QR_CODE_METHOD} from "matrix-js-sdk/src/crypto/verification/QRCode"; @@ -154,29 +155,38 @@ export default class VerificationPanel extends React.PureComponent { this.state.reciprocateQREvent.cancel(); }; + get _isSelfVerification() { + return this.props.request.otherUserId === MatrixClientPeg.get().getUserId(); + } + renderQRReciprocatePhase() { const {member} = this.props; - const FormButton = sdk.getComponent("elements.FormButton"); - + let Button; + if (this.props.inDialog) { + Button = sdk.getComponent("elements.AccessibleButton"); + } else { + Button = sdk.getComponent("elements.FormButton"); + } + const description = this._isSelfVerification ? + _t("Almost there! Is your other session showing the same shield?") : + _t("Almost there! Is %(displayName)s showing the same shield?", { + displayName: member.displayName || member.name || member.userId, + }); let body; if (this.state.reciprocateQREvent) { // riot web doesn't support scanning yet, so assume here we're the client being scanned. body = -

{_t("Almost there! Is %(displayName)s showing the same shield?", { - displayName: member.displayName || member.name || member.userId, - })}

+

{description}

- - {_t("No")} +
; } else { diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 26dcfb7ee8..389a30fe8f 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1252,6 +1252,7 @@ "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.", "Verify by comparing unique emoji.": "Verify by comparing unique emoji.", "Verify by emoji": "Verify by emoji", + "Almost there! Is your other session showing the same shield?": "Almost there! Is your other session showing the same shield?", "Almost there! Is %(displayName)s showing the same shield?": "Almost there! Is %(displayName)s showing the same shield?", "No": "No", "Yes": "Yes", From 1baaafe7b9174dcb6b11da4edbd3be1c6abc13b7 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 2 Apr 2020 16:44:42 +0200 Subject: [PATCH 10/11] some comments to explain the mess --- src/components/views/right_panel/VerificationPanel.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/components/views/right_panel/VerificationPanel.js b/src/components/views/right_panel/VerificationPanel.js index 840ece873c..579cd2c000 100644 --- a/src/components/views/right_panel/VerificationPanel.js +++ b/src/components/views/right_panel/VerificationPanel.js @@ -162,6 +162,8 @@ export default class VerificationPanel extends React.PureComponent { renderQRReciprocatePhase() { const {member} = this.props; let Button; + // a bit of a hack, but the FormButton should only be used in the right panel + // they should probably just be the same component with a css class applied to it? if (this.props.inDialog) { Button = sdk.getComponent("elements.AccessibleButton"); } else { @@ -175,6 +177,9 @@ export default class VerificationPanel extends React.PureComponent { let body; if (this.state.reciprocateQREvent) { // riot web doesn't support scanning yet, so assume here we're the client being scanned. + // + // we're passing both a label and a child string to Button as + // FormButton and AccessibleButton expect this differently body =

{description}

From fffd5a4a5ee4449d3a0949ecb429c206b82824f9 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 2 Apr 2020 16:46:29 +0200 Subject: [PATCH 11/11] fix stylelint --- res/css/views/right_panel/_VerificationPanel.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/res/css/views/right_panel/_VerificationPanel.scss b/res/css/views/right_panel/_VerificationPanel.scss index f8e5a54afb..01a654b523 100644 --- a/res/css/views/right_panel/_VerificationPanel.scss +++ b/res/css/views/right_panel/_VerificationPanel.scss @@ -13,7 +13,6 @@ 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_VerificationPanel_verified_section, .mx_VerificationPanel_reciprocate_section {