This commit is contained in:
Bruno Windels 2019-12-10 17:53:51 +01:00
parent 560cff0ae1
commit d8a38e6b74
10 changed files with 112 additions and 54 deletions

View file

@ -1458,20 +1458,16 @@ export default createReactClass({
if (SettingsStore.isFeatureEnabled("feature_cross_signing")) {
cli.on("crypto.verification.request", request => {
let requestObserver;
if (request.event.getRoomId()) {
requestObserver = new KeyVerificationStateObserver(
request.event, MatrixClientPeg.get());
}
if (!requestObserver || requestObserver.pending) {
console.log(`MatrixChat got a .request ${request.channel.transactionId}`, request.event.getRoomId());
if (request.pending) {
console.log(`emitting toast for verification request with txnid ${request.channel.transactionId}`, request.event && request.event.getId());
dis.dispatch({
action: "show_toast",
toast: {
key: request.event.getId(),
title: _t("Verification Request"),
icon: "verification",
props: {request, requestObserver},
props: {request},
component: sdk.getComponent("toasts.VerificationRequestToast"),
},
});

View file

@ -160,6 +160,7 @@ export default class RightPanel extends React.Component {
groupId: payload.groupId,
member: payload.member,
event: payload.event,
verificationRequest: payload.verificationRequest,
});
}
}
@ -168,6 +169,7 @@ export default class RightPanel extends React.Component {
const MemberList = sdk.getComponent('rooms.MemberList');
const MemberInfo = sdk.getComponent('rooms.MemberInfo');
const UserInfo = sdk.getComponent('right_panel.UserInfo');
const EncryptionPanel = sdk.getComponent('right_panel.EncryptionPanel');
const ThirdPartyMemberInfo = sdk.getComponent('rooms.ThirdPartyMemberInfo');
const NotificationPanel = sdk.getComponent('structures.NotificationPanel');
const FilePanel = sdk.getComponent('structures.FilePanel');
@ -235,6 +237,8 @@ export default class RightPanel extends React.Component {
panel = <NotificationPanel />;
} else if (this.state.phase === RIGHT_PANEL_PHASES.FilePanel) {
panel = <FilePanel roomId={this.props.roomId} resizeNotifier={this.props.resizeNotifier} />;
} else if (this.state.phase === RIGHT_PANEL_PHASES.EncryptionPanel) {
panel = <EncryptionPanel member={this.state.member} verificationRequest={this.state.verificationRequest} />;
}
const classes = classNames("mx_RightPanel", "mx_fadable", {

View file

@ -26,6 +26,7 @@ export default class ToastContainer extends React.Component {
}
componentDidMount() {
console.log("ToastContainer mounted");
this._dispatcherRef = dis.register(this.onAction);
}

View file

@ -100,9 +100,15 @@ export default class DeviceVerifyDialog extends React.Component {
if (!verifyingOwnDevice && SettingsStore.getValue("feature_cross_signing")) {
const roomId = await ensureDMExistsAndOpen(this.props.userId);
// throws upon cancellation before having started
this._verifier = await client.requestVerificationDM(
const request = await client.requestVerificationDM(
this.props.userId, roomId, [verificationMethods.SAS],
);
await request.waitFor(r => r.ready || r.started);
if (request.ready) {
this._verifier = request.beginKeyVerification(verificationMethods.SAS);
} else {
this._verifier = request.verifier;
}
} else {
this._verifier = client.beginKeyVerification(
verificationMethods.SAS, this.props.userId, this.props.device.deviceId,

View file

@ -17,48 +17,62 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import MatrixClientPeg from '../../../MatrixClientPeg';
import {verificationMethods} from 'matrix-js-sdk/lib/crypto';
import sdk from '../../../index';
import Modal from "../../../Modal";
import { _t } from '../../../languageHandler';
import KeyVerificationStateObserver, {getNameForEventRoom, userLabelForEventRoom}
import {getNameForEventRoom, userLabelForEventRoom}
from '../../../utils/KeyVerificationStateObserver';
import dis from "../../../dispatcher";
import {RIGHT_PANEL_PHASES} from "../../../stores/RightPanelStorePhases";
export default class MKeyVerificationRequest extends React.Component {
constructor(props) {
super(props);
this.keyVerificationState = new KeyVerificationStateObserver(this.props.mxEvent, MatrixClientPeg.get(), () => {
this.setState(this._copyState());
});
this.state = this._copyState();
}
_copyState() {
const {accepted, done, cancelled, cancelPartyUserId, otherPartyUserId} = this.keyVerificationState;
return {accepted, done, cancelled, cancelPartyUserId, otherPartyUserId};
}
componentDidMount() {
this.keyVerificationState.attach();
const request = this.props.mxEvent.verificationRequest;
if (request) {
request.on("change", this._onRequestChanged);
}
}
componentWillUnmount() {
this.keyVerificationState.detach();
const request = this.props.mxEvent.verificationRequest;
if (request) {
request.off("change", this._onRequestChanged);
}
}
_onAcceptClicked = () => {
const IncomingSasDialog = sdk.getComponent('views.dialogs.IncomingSasDialog');
// todo: validate event, for example if it has sas in the methods.
const verifier = MatrixClientPeg.get().acceptVerificationDM(this.props.mxEvent, verificationMethods.SAS);
Modal.createTrackedDialog('Incoming Verification', '', IncomingSasDialog, {
verifier,
}, null, /* priority = */ false, /* static = */ true);
_onRequestChanged = () => {
this.forceUpdate();
};
_onRejectClicked = () => {
// todo: validate event, for example if it has sas in the methods.
const verifier = MatrixClientPeg.get().acceptVerificationDM(this.props.mxEvent, verificationMethods.SAS);
verifier.cancel("User declined");
_onAcceptClicked = async () => {
const request = this.props.mxEvent.verificationRequest;
if (request) {
try {
await request.accept();
dis.dispatch({action: "show_right_panel"});
dis.dispatch({
action: "set_right_panel_phase",
phase: RIGHT_PANEL_PHASES.EncryptionPanel,
verificationRequest: request,
});
} catch (err) {
console.error(err.message);
}
}
};
_onRejectClicked = async () => {
const request = this.props.mxEvent.verificationRequest;
if (request) {
try {
await request.cancel();
} catch (err) {
console.error(err.message);
}
}
};
_acceptedLabel(userId) {
@ -83,45 +97,43 @@ export default class MKeyVerificationRequest extends React.Component {
render() {
const {mxEvent} = this.props;
const fromUserId = mxEvent.getSender();
const content = mxEvent.getContent();
const toUserId = content.to;
const client = MatrixClientPeg.get();
const myUserId = client.getUserId();
const isOwn = fromUserId === myUserId;
const request = mxEvent.verificationRequest;
let title;
let subtitle;
let stateNode;
if (this.state.accepted || this.state.cancelled) {
if (!request) {
return <p>This is an invalid request, ho ho ho!</p>;
}
if (request.ready || request.started || request.cancelled) {
let stateLabel;
if (this.state.accepted) {
stateLabel = this._acceptedLabel(toUserId);
} else if (this.state.cancelled) {
stateLabel = this._cancelledLabel(this.state.cancelPartyUserId);
if (request.ready || request.started) {
stateLabel = this._acceptedLabel(request.receivingUserId);
} else if (request.cancelled) {
stateLabel = this._cancelledLabel(request.cancellingUserId);
}
stateNode = (<div className="mx_KeyVerification_state">{stateLabel}</div>);
}
if (toUserId === myUserId) { // request sent to us
if (!request.initiatedByMe) {
title = (<div className="mx_KeyVerification_title">{
_t("%(name)s wants to verify", {name: getNameForEventRoom(fromUserId, mxEvent)})}</div>);
_t("%(name)s wants to verify", {name: getNameForEventRoom(request.requestingUserId, mxEvent)})}</div>);
subtitle = (<div className="mx_KeyVerification_subtitle">{
userLabelForEventRoom(fromUserId, mxEvent)}</div>);
const isResolved = !(this.state.accepted || this.state.cancelled || this.state.done);
if (isResolved) {
userLabelForEventRoom(request.requestingUserId, mxEvent)}</div>);
if (request.requested) {
const FormButton = sdk.getComponent("elements.FormButton");
stateNode = (<div className="mx_KeyVerification_buttons">
<FormButton kind="danger" onClick={this._onRejectClicked} label={_t("Decline")} />
<FormButton onClick={this._onAcceptClicked} label={_t("Accept")} />
</div>);
}
} else if (isOwn) { // request sent by us
} else { // request sent by us
title = (<div className="mx_KeyVerification_title">{
_t("You sent a verification request")}</div>);
subtitle = (<div className="mx_KeyVerification_subtitle">{
userLabelForEventRoom(this.state.otherPartyUserId, mxEvent)}</div>);
userLabelForEventRoom(request.receivingUserId, mxEvent)}</div>);
}
if (title) {

View file

@ -0,0 +1,33 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017, 2018 Vector Creations Ltd
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
export default class EncryptionPanel extends React.PureComponent {
render() {
const request = this.props.verificationRequest;
if (request) {
return <p>got a request, go straight to wizard</p>;
} else if (this.props.member) {
return <p>show encryption options for member {this.props.member.name}</p>;
} else {
return <p>nada</p>;
}
}
}

View file

@ -27,6 +27,7 @@ import {RIGHT_PANEL_PHASES} from "../../../stores/RightPanelStorePhases";
const MEMBER_PHASES = [
RIGHT_PANEL_PHASES.RoomMemberList,
RIGHT_PANEL_PHASES.RoomMemberInfo,
RIGHT_PANEL_PHASES.EncryptionPanel,
RIGHT_PANEL_PHASES.Room3pidMemberInfo,
];

View file

@ -123,7 +123,11 @@ export default class RightPanelStore extends Store {
if (payload.action === 'view_room' || payload.action === 'view_group') {
// Reset to the member list if we're viewing member info
const memberInfoPhases = [RIGHT_PANEL_PHASES.RoomMemberInfo, RIGHT_PANEL_PHASES.Room3pidMemberInfo];
const memberInfoPhases = [
RIGHT_PANEL_PHASES.RoomMemberInfo,
RIGHT_PANEL_PHASES.Room3pidMemberInfo,
RIGHT_PANEL_PHASES.EncryptionPanel,
];
if (memberInfoPhases.includes(this._state.lastRoomPhase)) {
this._setState({lastRoomPhase: RIGHT_PANEL_PHASES.RoomMemberList, lastRoomPhaseParams: {}});
}

View file

@ -22,7 +22,7 @@ export const RIGHT_PANEL_PHASES = Object.freeze({
NotificationPanel: 'NotificationPanel',
RoomMemberInfo: 'RoomMemberInfo',
Room3pidMemberInfo: 'Room3pidMemberInfo',
EncryptionPanel: 'EncryptionPanel',
// Group stuff
GroupMemberList: 'GroupMemberList',
GroupRoomList: 'GroupRoomList',

View file

@ -161,6 +161,7 @@ export default class KeyVerificationStateObserver {
}
this.otherPartyUserId = fromUserId === this._client.getUserId() ? toUserId : fromUserId;
console.log("KeyVerificationStateObserver update for txnId", this._requestEvent.getId(), {accepted: this.accepted, cancelled: this.cancelled, done: this.done});
}
}