mirror of
https://github.com/element-hq/element-web.git
synced 2024-12-03 20:36:57 +03:00
Update QR code rendering to support VerificationRequests
Makes for building the QR code easier and more common.
This commit is contained in:
parent
8a09cfbfbd
commit
724cff6a2e
2 changed files with 89 additions and 22 deletions
|
@ -19,6 +19,9 @@ import PropTypes from "prop-types";
|
||||||
import {replaceableComponent} from "../../../../utils/replaceableComponent";
|
import {replaceableComponent} from "../../../../utils/replaceableComponent";
|
||||||
import * as qs from "qs";
|
import * as qs from "qs";
|
||||||
import QRCode from "qrcode-react";
|
import QRCode from "qrcode-react";
|
||||||
|
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";
|
||||||
|
|
||||||
@replaceableComponent("views.elements.crypto.VerificationQRCode")
|
@replaceableComponent("views.elements.crypto.VerificationQRCode")
|
||||||
export default class VerificationQRCode extends React.PureComponent {
|
export default class VerificationQRCode extends React.PureComponent {
|
||||||
|
@ -31,13 +34,81 @@ export default class VerificationQRCode extends React.PureComponent {
|
||||||
// User verification use case only
|
// User verification use case only
|
||||||
secret: PropTypes.string,
|
secret: PropTypes.string,
|
||||||
otherUserKey: PropTypes.string, // Base64 key being verified
|
otherUserKey: PropTypes.string, // Base64 key being verified
|
||||||
requestEventId: PropTypes.string,
|
otherUserDeviceKey: PropTypes.string, // Base64 key of the other user's device (optional)
|
||||||
|
requestEventId: PropTypes.string, // for DM verification only
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
action: "verify",
|
action: "verify",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static async getPropsForRequest(verificationRequest: VerificationRequest) {
|
||||||
|
const cli = MatrixClientPeg.get();
|
||||||
|
const myUserId = cli.getUserId();
|
||||||
|
const otherUserId = verificationRequest.otherUserId;
|
||||||
|
const myDeviceId = cli.getDeviceId();
|
||||||
|
const otherDevice = verificationRequest.estimatedTargetDevice;
|
||||||
|
const otherDeviceId = otherDevice ? otherDevice.deviceId : null;
|
||||||
|
|
||||||
|
const qrProps = {
|
||||||
|
secret: verificationRequest.encodedSharedSecret,
|
||||||
|
keyholderUserId: myUserId,
|
||||||
|
action: "verify",
|
||||||
|
keys: [], // array of pairs: keyId, base64Key
|
||||||
|
otherUserKey: "", // base64key
|
||||||
|
otherUserDeviceKey: "", // base64key
|
||||||
|
requestEventId: "", // we figure this out in a moment
|
||||||
|
};
|
||||||
|
|
||||||
|
const requestEvent = verificationRequest.requestEvent;
|
||||||
|
qrProps.requestEventId = requestEvent.getId()
|
||||||
|
? requestEvent.getId()
|
||||||
|
: ToDeviceChannel.getTransactionId(requestEvent);
|
||||||
|
|
||||||
|
// Populate the keys we need depending on which direction and users are involved in the verification.
|
||||||
|
if (myUserId === otherUserId) {
|
||||||
|
if (!otherDeviceId) {
|
||||||
|
// New -> Existing session QR code
|
||||||
|
qrProps.otherUserDeviceKey = null;
|
||||||
|
} else {
|
||||||
|
// Existing -> New session QR code
|
||||||
|
const myDevices = (await cli.getStoredDevicesForUser(myUserId)) || [];
|
||||||
|
const device = myDevices.find(d => d.deviceId === otherDeviceId);
|
||||||
|
if (device) qrProps.otherUserDeviceKey = device.getFingerprint();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Either direction shares these next few props
|
||||||
|
|
||||||
|
const xsignInfo = cli.getStoredCrossSigningForUser(myUserId);
|
||||||
|
qrProps.otherUserKey = xsignInfo.getId("master");
|
||||||
|
|
||||||
|
qrProps.keys = [
|
||||||
|
[myDeviceId, cli.getDeviceEd25519Key()],
|
||||||
|
[xsignInfo.getId("master"), xsignInfo.getId("master")],
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
// Doesn't matter which direction the verification is, we always show the same QR code
|
||||||
|
// for not-ourself verification.
|
||||||
|
const myXsignInfo = cli.getStoredCrossSigningForUser(myUserId);
|
||||||
|
const otherXsignInfo = cli.getStoredCrossSigningForUser(otherUserId);
|
||||||
|
const otherDevices = (await cli.getStoredDevicesForUser(otherUserId)) || [];
|
||||||
|
const otherDevice = otherDevices.find(d => d.deviceId === otherDeviceId);
|
||||||
|
|
||||||
|
qrProps.keys = [
|
||||||
|
[myDeviceId, cli.getDeviceEd25519Key()],
|
||||||
|
[myXsignInfo.getId("master"), myXsignInfo.getId("master")],
|
||||||
|
];
|
||||||
|
qrProps.otherUserKey = otherXsignInfo.getId("master");
|
||||||
|
if (otherDevice) qrProps.otherUserDeviceKey = otherDevice.getFingerprint();
|
||||||
|
}
|
||||||
|
|
||||||
|
return qrProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const query = {
|
const query = {
|
||||||
request: this.props.requestEventId,
|
request: this.props.requestEventId,
|
||||||
|
|
|
@ -20,7 +20,6 @@ import PropTypes from "prop-types";
|
||||||
import * as sdk from '../../../index';
|
import * as sdk from '../../../index';
|
||||||
import {verificationMethods} from 'matrix-js-sdk/src/crypto';
|
import {verificationMethods} from 'matrix-js-sdk/src/crypto';
|
||||||
import VerificationQRCode from "../elements/crypto/VerificationQRCode";
|
import VerificationQRCode from "../elements/crypto/VerificationQRCode";
|
||||||
import {MatrixClientPeg} from "../../../MatrixClientPeg";
|
|
||||||
import {_t} from "../../../languageHandler";
|
import {_t} from "../../../languageHandler";
|
||||||
import E2EIcon from "../rooms/E2EIcon";
|
import E2EIcon from "../rooms/E2EIcon";
|
||||||
import {
|
import {
|
||||||
|
@ -29,7 +28,7 @@ import {
|
||||||
PHASE_READY,
|
PHASE_READY,
|
||||||
PHASE_DONE,
|
PHASE_DONE,
|
||||||
PHASE_STARTED,
|
PHASE_STARTED,
|
||||||
PHASE_CANCELLED,
|
PHASE_CANCELLED, VerificationRequest,
|
||||||
} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
||||||
import Spinner from "../elements/Spinner";
|
import Spinner from "../elements/Spinner";
|
||||||
|
|
||||||
|
@ -50,12 +49,24 @@ export default class VerificationPanel extends React.PureComponent {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {};
|
this.state = {
|
||||||
|
qrCodeProps: null, // generated by the VerificationQRCode component itself
|
||||||
|
};
|
||||||
this._hasVerifier = false;
|
this._hasVerifier = false;
|
||||||
|
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) {
|
renderQRPhase(pending) {
|
||||||
const {member, request} = this.props;
|
const {member} = this.props;
|
||||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
|
|
||||||
let button;
|
let button;
|
||||||
|
@ -69,10 +80,7 @@ export default class VerificationPanel extends React.PureComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const cli = MatrixClientPeg.get();
|
if (!this.state.qrCodeProps) {
|
||||||
const crossSigningInfo = cli.getStoredCrossSigningForUser(request.otherUserId);
|
|
||||||
if (!crossSigningInfo || !request.requestEvent || !request.requestEvent.getId()) {
|
|
||||||
// for whatever reason we can't generate a QR code, offer only SAS Verification
|
|
||||||
return <div className="mx_UserInfo_container">
|
return <div className="mx_UserInfo_container">
|
||||||
<h3>Verify by emoji</h3>
|
<h3>Verify by emoji</h3>
|
||||||
<p>{_t("Verify by comparing unique emoji.")}</p>
|
<p>{_t("Verify by comparing unique emoji.")}</p>
|
||||||
|
@ -81,12 +89,6 @@ export default class VerificationPanel extends React.PureComponent {
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const myKeyId = cli.getCrossSigningId();
|
|
||||||
const qrCodeKeys = [
|
|
||||||
[cli.getDeviceId(), cli.getDeviceEd25519Key()],
|
|
||||||
[myKeyId, myKeyId],
|
|
||||||
];
|
|
||||||
|
|
||||||
// TODO: add way to open camera to scan a QR code
|
// TODO: add way to open camera to scan a QR code
|
||||||
return <React.Fragment>
|
return <React.Fragment>
|
||||||
<div className="mx_UserInfo_container">
|
<div className="mx_UserInfo_container">
|
||||||
|
@ -96,13 +98,7 @@ export default class VerificationPanel extends React.PureComponent {
|
||||||
})}</p>
|
})}</p>
|
||||||
|
|
||||||
<div className="mx_VerificationPanel_qrCode">
|
<div className="mx_VerificationPanel_qrCode">
|
||||||
<VerificationQRCode
|
<VerificationQRCode {...this.state.qrCodeProps} />
|
||||||
keyholderUserId={MatrixClientPeg.get().getUserId()}
|
|
||||||
requestEventId={request.requestEvent.getId()}
|
|
||||||
otherUserKey={crossSigningInfo.getId("master")}
|
|
||||||
secret={request.encodedSharedSecret}
|
|
||||||
keys={qrCodeKeys}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue