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 =