Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Merge pull request #3796 from matrix-org/bwindels/verification-right-…
Browse files Browse the repository at this point in the history
…panel

Initial support for verification in right panel
  • Loading branch information
bwindels authored Jan 20, 2020
2 parents 20ec2a6 + 716c8ba commit 95a0eba
Show file tree
Hide file tree
Showing 17 changed files with 411 additions and 346 deletions.
14 changes: 4 additions & 10 deletions src/components/structures/MatrixChat.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ import { countRoomsWithNotif } from '../../RoomNotifs';
import { ThemeWatcher } from "../../theme";
import { storeRoomAliasInCache } from '../../RoomAliasCache';
import { defer } from "../../utils/promise";
import KeyVerificationStateObserver from '../../utils/KeyVerificationStateObserver';
import ToastStore from "../../stores/ToastStore";

/** constants for MatrixChat.state.view */
Expand Down Expand Up @@ -1454,18 +1453,13 @@ 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) {
ToastStore.sharedInstance().addOrReplaceToast({
key: 'verifreq_' + request.event.getId(),
key: 'verifreq_' + request.channel.transactionId,
title: _t("Verification Request"),
icon: "verification",
props: {request, requestObserver},
props: {request},
component: sdk.getComponent("toasts.VerificationRequestToast"),
});
}
Expand Down
4 changes: 4 additions & 0 deletions src/components/structures/RightPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ export default class RightPanel extends React.Component {
groupId: payload.groupId,
member: payload.member,
event: payload.event,
verificationRequest: payload.verificationRequest,
});
}
}
Expand All @@ -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');
Expand Down Expand Up @@ -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", {
Expand Down
2 changes: 1 addition & 1 deletion src/components/structures/TimelinePanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -1134,7 +1134,7 @@ const TimelinePanel = createReactClass({
const allowPartial = opts.allowPartial || false;

const messagePanel = this._messagePanel.current;
if (messagePanel === undefined) return null;
if (!messagePanel) return null;

const messagePanelNode = ReactDOM.findDOMNode(messagePanel);
if (!messagePanelNode) return null; // sometimes this happens for fresh rooms/post-sync
Expand Down
29 changes: 9 additions & 20 deletions src/components/views/dialogs/DeviceVerifyDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ import * as sdk from '../../../index';
import * as FormattingUtils from '../../../utils/FormattingUtils';
import { _t } from '../../../languageHandler';
import {verificationMethods} from 'matrix-js-sdk/src/crypto';
import DMRoomMap from '../../../utils/DMRoomMap';
import createRoom from "../../../createRoom";
import {ensureDMExists} from "../../../createRoom";
import dis from "../../../dispatcher";
import SettingsStore from '../../../settings/SettingsStore';

Expand Down Expand Up @@ -100,9 +99,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,
Expand Down Expand Up @@ -316,23 +321,7 @@ export default class DeviceVerifyDialog extends React.Component {
}

async function ensureDMExistsAndOpen(userId) {
const client = MatrixClientPeg.get();
const roomIds = DMRoomMap.shared().getDMRoomsForUserId(userId);
const rooms = roomIds.map(id => client.getRoom(id));
const suitableDMRooms = rooms.filter(r => {
if (r && r.getMyMembership() === "join") {
const member = r.getMember(userId);
return member && (member.membership === "invite" || member.membership === "join");
}
return false;
});
let roomId;
if (suitableDMRooms.length) {
const room = suitableDMRooms[0];
roomId = room.roomId;
} else {
roomId = await createRoom({dmUserId: userId, spinner: false, andView: false});
}
const roomId = ensureDMExists(MatrixClientPeg.get(), userId);
// don't use andView and spinner in createRoom, together, they cause this dialog to close and reopen,
// we causes us to loose the verifier and restart, and we end up having two verification requests
dis.dispatch({
Expand Down
109 changes: 45 additions & 64 deletions src/components/views/messages/MKeyVerificationConclusion.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,102 +19,83 @@ import classNames from 'classnames';
import PropTypes from 'prop-types';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import { _t } from '../../../languageHandler';
import KeyVerificationStateObserver, {getNameForEventRoom, userLabelForEventRoom}
import {getNameForEventRoom, userLabelForEventRoom}
from '../../../utils/KeyVerificationStateObserver';

export default class MKeyVerificationConclusion extends React.Component {
constructor(props) {
super(props);
this.keyVerificationState = null;
this.state = {
done: false,
cancelled: false,
otherPartyUserId: null,
cancelPartyUserId: null,
};
const rel = this.props.mxEvent.getRelation();
if (rel) {
const client = MatrixClientPeg.get();
const room = client.getRoom(this.props.mxEvent.getRoomId());
const requestEvent = room.findEventById(rel.event_id);
if (requestEvent) {
this._createStateObserver(requestEvent, client);
this.state = this._copyState();
} else {
const findEvent = event => {
if (event.getId() === rel.event_id) {
this._createStateObserver(event, client);
this.setState(this._copyState());
room.removeListener("Room.timeline", findEvent);
}
};
room.on("Room.timeline", findEvent);
}
}
}

_createStateObserver(requestEvent, client) {
this.keyVerificationState = new KeyVerificationStateObserver(requestEvent, client, () => {
this.setState(this._copyState());
});
}

_copyState() {
const {done, cancelled, otherPartyUserId, cancelPartyUserId} = this.keyVerificationState;
return {done, cancelled, otherPartyUserId, cancelPartyUserId};
}

componentDidMount() {
if (this.keyVerificationState) {
this.keyVerificationState.attach();
const request = this.props.mxEvent.verificationRequest;
if (request) {
request.on("change", this._onRequestChanged);
}
}

componentWillUnmount() {
if (this.keyVerificationState) {
this.keyVerificationState.detach();
const request = this.props.mxEvent.verificationRequest;
if (request) {
request.off("change", this._onRequestChanged);
}
}

_getName(userId) {
const roomId = this.props.mxEvent.getRoomId();
const client = MatrixClientPeg.get();
const room = client.getRoom(roomId);
const member = room.getMember(userId);
return member ? member.name : userId;
}
_onRequestChanged = () => {
this.forceUpdate();
};

_userLabel(userId) {
const name = this._getName(userId);
if (name !== userId) {
return _t("%(name)s (%(userId)s)", {name, userId});
} else {
return userId;
_shouldRender(mxEvent, request) {
// normally should not happen
if (!request) {
return false;
}
// .cancel event that was sent after the verification finished, ignore
if (mxEvent.getType() === "m.key.verification.cancel" && !request.cancelled) {
return false;
}
// .done event that was sent after the verification cancelled, ignore
if (mxEvent.getType() === "m.key.verification.done" && !request.done) {
return false;
}

// request hasn't concluded yet
if (request.pending) {
return false;
}
return true;
}

render() {
const {mxEvent} = this.props;
const request = mxEvent.verificationRequest;

if (!this._shouldRender(mxEvent, request)) {
return null;
}

const client = MatrixClientPeg.get();
const myUserId = client.getUserId();

let title;

if (this.state.done) {
title = _t("You verified %(name)s", {name: getNameForEventRoom(this.state.otherPartyUserId, mxEvent)});
} else if (this.state.cancelled) {
if (mxEvent.getSender() === myUserId) {
if (request.done) {
title = _t("You verified %(name)s", {name: getNameForEventRoom(request.otherUserId, mxEvent)});
} else if (request.cancelled) {
const userId = request.cancellingUserId;
if (userId === myUserId) {
title = _t("You cancelled verifying %(name)s",
{name: getNameForEventRoom(this.state.otherPartyUserId, mxEvent)});
} else if (mxEvent.getSender() === this.state.otherPartyUserId) {
{name: getNameForEventRoom(request.otherUserId, mxEvent)});
} else {
title = _t("%(name)s cancelled verifying",
{name: getNameForEventRoom(this.state.otherPartyUserId, mxEvent)});
{name: getNameForEventRoom(userId, mxEvent)});
}
}

if (title) {
const subtitle = userLabelForEventRoom(this.state.otherPartyUserId, mxEvent);
const subtitle = userLabelForEventRoom(request.otherUserId, mxEvent);
const classes = classNames("mx_EventTile_bubble", "mx_KeyVerification", "mx_KeyVerification_icon", {
mx_KeyVerification_icon_verified: this.state.done,
mx_KeyVerification_icon_verified: request.done,
});
return (<div className={classes}>
<div className="mx_KeyVerification_title">{title}</div>
Expand Down
Loading

0 comments on commit 95a0eba

Please sign in to comment.