WIP
This commit is contained in:
parent
560cff0ae1
commit
d8a38e6b74
10 changed files with 112 additions and 54 deletions
|
@ -1458,20 +1458,16 @@ export default createReactClass({
|
||||||
|
|
||||||
if (SettingsStore.isFeatureEnabled("feature_cross_signing")) {
|
if (SettingsStore.isFeatureEnabled("feature_cross_signing")) {
|
||||||
cli.on("crypto.verification.request", request => {
|
cli.on("crypto.verification.request", request => {
|
||||||
let requestObserver;
|
console.log(`MatrixChat got a .request ${request.channel.transactionId}`, request.event.getRoomId());
|
||||||
if (request.event.getRoomId()) {
|
if (request.pending) {
|
||||||
requestObserver = new KeyVerificationStateObserver(
|
console.log(`emitting toast for verification request with txnid ${request.channel.transactionId}`, request.event && request.event.getId());
|
||||||
request.event, MatrixClientPeg.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!requestObserver || requestObserver.pending) {
|
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: "show_toast",
|
action: "show_toast",
|
||||||
toast: {
|
toast: {
|
||||||
key: request.event.getId(),
|
key: request.event.getId(),
|
||||||
title: _t("Verification Request"),
|
title: _t("Verification Request"),
|
||||||
icon: "verification",
|
icon: "verification",
|
||||||
props: {request, requestObserver},
|
props: {request},
|
||||||
component: sdk.getComponent("toasts.VerificationRequestToast"),
|
component: sdk.getComponent("toasts.VerificationRequestToast"),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -160,6 +160,7 @@ export default class RightPanel extends React.Component {
|
||||||
groupId: payload.groupId,
|
groupId: payload.groupId,
|
||||||
member: payload.member,
|
member: payload.member,
|
||||||
event: payload.event,
|
event: payload.event,
|
||||||
|
verificationRequest: payload.verificationRequest,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,6 +169,7 @@ export default class RightPanel extends React.Component {
|
||||||
const MemberList = sdk.getComponent('rooms.MemberList');
|
const MemberList = sdk.getComponent('rooms.MemberList');
|
||||||
const MemberInfo = sdk.getComponent('rooms.MemberInfo');
|
const MemberInfo = sdk.getComponent('rooms.MemberInfo');
|
||||||
const UserInfo = sdk.getComponent('right_panel.UserInfo');
|
const UserInfo = sdk.getComponent('right_panel.UserInfo');
|
||||||
|
const EncryptionPanel = sdk.getComponent('right_panel.EncryptionPanel');
|
||||||
const ThirdPartyMemberInfo = sdk.getComponent('rooms.ThirdPartyMemberInfo');
|
const ThirdPartyMemberInfo = sdk.getComponent('rooms.ThirdPartyMemberInfo');
|
||||||
const NotificationPanel = sdk.getComponent('structures.NotificationPanel');
|
const NotificationPanel = sdk.getComponent('structures.NotificationPanel');
|
||||||
const FilePanel = sdk.getComponent('structures.FilePanel');
|
const FilePanel = sdk.getComponent('structures.FilePanel');
|
||||||
|
@ -235,6 +237,8 @@ export default class RightPanel extends React.Component {
|
||||||
panel = <NotificationPanel />;
|
panel = <NotificationPanel />;
|
||||||
} else if (this.state.phase === RIGHT_PANEL_PHASES.FilePanel) {
|
} else if (this.state.phase === RIGHT_PANEL_PHASES.FilePanel) {
|
||||||
panel = <FilePanel roomId={this.props.roomId} resizeNotifier={this.props.resizeNotifier} />;
|
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", {
|
const classes = classNames("mx_RightPanel", "mx_fadable", {
|
||||||
|
|
|
@ -26,6 +26,7 @@ export default class ToastContainer extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
console.log("ToastContainer mounted");
|
||||||
this._dispatcherRef = dis.register(this.onAction);
|
this._dispatcherRef = dis.register(this.onAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,9 +100,15 @@ export default class DeviceVerifyDialog extends React.Component {
|
||||||
if (!verifyingOwnDevice && SettingsStore.getValue("feature_cross_signing")) {
|
if (!verifyingOwnDevice && SettingsStore.getValue("feature_cross_signing")) {
|
||||||
const roomId = await ensureDMExistsAndOpen(this.props.userId);
|
const roomId = await ensureDMExistsAndOpen(this.props.userId);
|
||||||
// throws upon cancellation before having started
|
// throws upon cancellation before having started
|
||||||
this._verifier = await client.requestVerificationDM(
|
const request = await client.requestVerificationDM(
|
||||||
this.props.userId, roomId, [verificationMethods.SAS],
|
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 {
|
} else {
|
||||||
this._verifier = client.beginKeyVerification(
|
this._verifier = client.beginKeyVerification(
|
||||||
verificationMethods.SAS, this.props.userId, this.props.device.deviceId,
|
verificationMethods.SAS, this.props.userId, this.props.device.deviceId,
|
||||||
|
|
|
@ -17,48 +17,62 @@ limitations under the License.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||||
import {verificationMethods} from 'matrix-js-sdk/lib/crypto';
|
|
||||||
import sdk from '../../../index';
|
import sdk from '../../../index';
|
||||||
import Modal from "../../../Modal";
|
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import KeyVerificationStateObserver, {getNameForEventRoom, userLabelForEventRoom}
|
import {getNameForEventRoom, userLabelForEventRoom}
|
||||||
from '../../../utils/KeyVerificationStateObserver';
|
from '../../../utils/KeyVerificationStateObserver';
|
||||||
|
import dis from "../../../dispatcher";
|
||||||
|
import {RIGHT_PANEL_PHASES} from "../../../stores/RightPanelStorePhases";
|
||||||
|
|
||||||
export default class MKeyVerificationRequest extends React.Component {
|
export default class MKeyVerificationRequest extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(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() {
|
componentDidMount() {
|
||||||
this.keyVerificationState.attach();
|
const request = this.props.mxEvent.verificationRequest;
|
||||||
|
if (request) {
|
||||||
|
request.on("change", this._onRequestChanged);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.keyVerificationState.detach();
|
const request = this.props.mxEvent.verificationRequest;
|
||||||
|
if (request) {
|
||||||
|
request.off("change", this._onRequestChanged);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onAcceptClicked = () => {
|
_onRequestChanged = () => {
|
||||||
const IncomingSasDialog = sdk.getComponent('views.dialogs.IncomingSasDialog');
|
this.forceUpdate();
|
||||||
// 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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
_onRejectClicked = () => {
|
_onAcceptClicked = async () => {
|
||||||
// todo: validate event, for example if it has sas in the methods.
|
const request = this.props.mxEvent.verificationRequest;
|
||||||
const verifier = MatrixClientPeg.get().acceptVerificationDM(this.props.mxEvent, verificationMethods.SAS);
|
if (request) {
|
||||||
verifier.cancel("User declined");
|
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) {
|
_acceptedLabel(userId) {
|
||||||
|
@ -83,45 +97,43 @@ export default class MKeyVerificationRequest extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {mxEvent} = this.props;
|
const {mxEvent} = this.props;
|
||||||
const fromUserId = mxEvent.getSender();
|
const request = mxEvent.verificationRequest;
|
||||||
const content = mxEvent.getContent();
|
|
||||||
const toUserId = content.to;
|
|
||||||
const client = MatrixClientPeg.get();
|
|
||||||
const myUserId = client.getUserId();
|
|
||||||
const isOwn = fromUserId === myUserId;
|
|
||||||
|
|
||||||
let title;
|
let title;
|
||||||
let subtitle;
|
let subtitle;
|
||||||
let stateNode;
|
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;
|
let stateLabel;
|
||||||
if (this.state.accepted) {
|
if (request.ready || request.started) {
|
||||||
stateLabel = this._acceptedLabel(toUserId);
|
stateLabel = this._acceptedLabel(request.receivingUserId);
|
||||||
} else if (this.state.cancelled) {
|
} else if (request.cancelled) {
|
||||||
stateLabel = this._cancelledLabel(this.state.cancelPartyUserId);
|
stateLabel = this._cancelledLabel(request.cancellingUserId);
|
||||||
}
|
}
|
||||||
stateNode = (<div className="mx_KeyVerification_state">{stateLabel}</div>);
|
stateNode = (<div className="mx_KeyVerification_state">{stateLabel}</div>);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toUserId === myUserId) { // request sent to us
|
if (!request.initiatedByMe) {
|
||||||
title = (<div className="mx_KeyVerification_title">{
|
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">{
|
subtitle = (<div className="mx_KeyVerification_subtitle">{
|
||||||
userLabelForEventRoom(fromUserId, mxEvent)}</div>);
|
userLabelForEventRoom(request.requestingUserId, mxEvent)}</div>);
|
||||||
const isResolved = !(this.state.accepted || this.state.cancelled || this.state.done);
|
if (request.requested) {
|
||||||
if (isResolved) {
|
|
||||||
const FormButton = sdk.getComponent("elements.FormButton");
|
const FormButton = sdk.getComponent("elements.FormButton");
|
||||||
stateNode = (<div className="mx_KeyVerification_buttons">
|
stateNode = (<div className="mx_KeyVerification_buttons">
|
||||||
<FormButton kind="danger" onClick={this._onRejectClicked} label={_t("Decline")} />
|
<FormButton kind="danger" onClick={this._onRejectClicked} label={_t("Decline")} />
|
||||||
<FormButton onClick={this._onAcceptClicked} label={_t("Accept")} />
|
<FormButton onClick={this._onAcceptClicked} label={_t("Accept")} />
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
} else if (isOwn) { // request sent by us
|
} else { // request sent by us
|
||||||
title = (<div className="mx_KeyVerification_title">{
|
title = (<div className="mx_KeyVerification_title">{
|
||||||
_t("You sent a verification request")}</div>);
|
_t("You sent a verification request")}</div>);
|
||||||
subtitle = (<div className="mx_KeyVerification_subtitle">{
|
subtitle = (<div className="mx_KeyVerification_subtitle">{
|
||||||
userLabelForEventRoom(this.state.otherPartyUserId, mxEvent)}</div>);
|
userLabelForEventRoom(request.receivingUserId, mxEvent)}</div>);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (title) {
|
if (title) {
|
||||||
|
|
33
src/components/views/right_panel/EncryptionPanel.js
Normal file
33
src/components/views/right_panel/EncryptionPanel.js
Normal 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>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,7 @@ import {RIGHT_PANEL_PHASES} from "../../../stores/RightPanelStorePhases";
|
||||||
const MEMBER_PHASES = [
|
const MEMBER_PHASES = [
|
||||||
RIGHT_PANEL_PHASES.RoomMemberList,
|
RIGHT_PANEL_PHASES.RoomMemberList,
|
||||||
RIGHT_PANEL_PHASES.RoomMemberInfo,
|
RIGHT_PANEL_PHASES.RoomMemberInfo,
|
||||||
|
RIGHT_PANEL_PHASES.EncryptionPanel,
|
||||||
RIGHT_PANEL_PHASES.Room3pidMemberInfo,
|
RIGHT_PANEL_PHASES.Room3pidMemberInfo,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,11 @@ export default class RightPanelStore extends Store {
|
||||||
|
|
||||||
if (payload.action === 'view_room' || payload.action === 'view_group') {
|
if (payload.action === 'view_room' || payload.action === 'view_group') {
|
||||||
// Reset to the member list if we're viewing member info
|
// 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)) {
|
if (memberInfoPhases.includes(this._state.lastRoomPhase)) {
|
||||||
this._setState({lastRoomPhase: RIGHT_PANEL_PHASES.RoomMemberList, lastRoomPhaseParams: {}});
|
this._setState({lastRoomPhase: RIGHT_PANEL_PHASES.RoomMemberList, lastRoomPhaseParams: {}});
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ export const RIGHT_PANEL_PHASES = Object.freeze({
|
||||||
NotificationPanel: 'NotificationPanel',
|
NotificationPanel: 'NotificationPanel',
|
||||||
RoomMemberInfo: 'RoomMemberInfo',
|
RoomMemberInfo: 'RoomMemberInfo',
|
||||||
Room3pidMemberInfo: 'Room3pidMemberInfo',
|
Room3pidMemberInfo: 'Room3pidMemberInfo',
|
||||||
|
EncryptionPanel: 'EncryptionPanel',
|
||||||
// Group stuff
|
// Group stuff
|
||||||
GroupMemberList: 'GroupMemberList',
|
GroupMemberList: 'GroupMemberList',
|
||||||
GroupRoomList: 'GroupRoomList',
|
GroupRoomList: 'GroupRoomList',
|
||||||
|
|
|
@ -161,6 +161,7 @@ export default class KeyVerificationStateObserver {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.otherPartyUserId = fromUserId === this._client.getUserId() ? toUserId : fromUserId;
|
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});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue