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

Initial support for verification in right panel #3796

Merged
merged 27 commits into from
Jan 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d8a38e6
WIP
bwindels Dec 10, 2019
c02fc44
WIP sas in right panel
bwindels Dec 16, 2019
0f41503
actually start verify process in verification panel
bwindels Dec 18, 2019
9e4b65d
fixup after rebase
bwindels Dec 19, 2019
2c28fa0
use verif in right panel from "verify" button
bwindels Dec 19, 2019
41cf187
remove now-unused import
bwindels Dec 19, 2019
b36df73
fix for ref refactor pr
bwindels Dec 19, 2019
db17321
await verify so errors (like cancellation) are caught
bwindels Dec 19, 2019
b866c16
show cancellation
bwindels Dec 19, 2019
b80bfd0
make sure to have roomId of DM when starting verif. req.
bwindels Dec 19, 2019
8c5f3d6
show devices and unverify action also in unencrypted rooms
bwindels Dec 19, 2019
d57e76f
hide verify button for own member
bwindels Dec 19, 2019
f4a276c
port MVerificationConclusion to use VerificationRequest
bwindels Dec 20, 2019
1aebc95
slightly better copy
bwindels Dec 20, 2019
dd633bd
port toast to use VerificationRequest and open right panel, not dialog
bwindels Dec 20, 2019
2dd1e93
show message after clicking "they match"
bwindels Dec 20, 2019
de1c3e2
use same style as UserInfo for sections and paragraphs
bwindels Dec 20, 2019
075e42c
use transactionId as key for react
bwindels Dec 20, 2019
b49c471
render empty tiles when no request
bwindels Dec 20, 2019
52c7c5b
render done tile as accepted
bwindels Dec 20, 2019
3b9c5c0
remove unused code
bwindels Dec 20, 2019
7a88a94
fixes!
bwindels Jan 3, 2020
d1fcef1
Merge branch 'develop' into bwindels/verification-right-panel
turt2live Jan 16, 2020
d20db35
fix import paths after build system refactor
bwindels Jan 17, 2020
5556cb5
Merge branch 'develop' into bwindels/verification-right-panel
bwindels Jan 17, 2020
a73b722
fix lint
bwindels Jan 17, 2020
716c8ba
pr feedback
bwindels Jan 17, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 wrapperRect = ReactDOM.findDOMNode(messagePanel).getBoundingClientRect();
const myUserId = MatrixClientPeg.get().credentials.userId;
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