parent
076a3e058d
commit
a496dafd41
|
@ -1,158 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 Vector Creations Ltd
|
|
||||||
Copyright 2020 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 * as sdk from './index';
|
|
||||||
import Modal from './Modal';
|
|
||||||
import SettingsStore from './settings/SettingsStore';
|
|
||||||
|
|
||||||
// TODO: We can remove this once cross-signing is the only way.
|
|
||||||
// https://github.com/vector-im/riot-web/issues/11908
|
|
||||||
export default class KeyRequestHandler {
|
|
||||||
constructor(matrixClient) {
|
|
||||||
this._matrixClient = matrixClient;
|
|
||||||
|
|
||||||
// the user/device for which we currently have a dialog open
|
|
||||||
this._currentUser = null;
|
|
||||||
this._currentDevice = null;
|
|
||||||
|
|
||||||
// userId -> deviceId -> [keyRequest]
|
|
||||||
this._pendingKeyRequests = Object.create(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleKeyRequest(keyRequest) {
|
|
||||||
// Ignore own device key requests if cross-signing lab enabled
|
|
||||||
if (SettingsStore.getValue("feature_cross_signing")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const userId = keyRequest.userId;
|
|
||||||
const deviceId = keyRequest.deviceId;
|
|
||||||
const requestId = keyRequest.requestId;
|
|
||||||
|
|
||||||
if (!this._pendingKeyRequests[userId]) {
|
|
||||||
this._pendingKeyRequests[userId] = Object.create(null);
|
|
||||||
}
|
|
||||||
if (!this._pendingKeyRequests[userId][deviceId]) {
|
|
||||||
this._pendingKeyRequests[userId][deviceId] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if we already have this request
|
|
||||||
const requests = this._pendingKeyRequests[userId][deviceId];
|
|
||||||
if (requests.find((r) => r.requestId === requestId)) {
|
|
||||||
console.log("Already have this key request, ignoring");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
requests.push(keyRequest);
|
|
||||||
|
|
||||||
if (this._currentUser) {
|
|
||||||
// ignore for now
|
|
||||||
console.log("Key request, but we already have a dialog open");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._processNextRequest();
|
|
||||||
}
|
|
||||||
|
|
||||||
handleKeyRequestCancellation(cancellation) {
|
|
||||||
// Ignore own device key requests if cross-signing lab enabled
|
|
||||||
if (SettingsStore.getValue("feature_cross_signing")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// see if we can find the request in the queue
|
|
||||||
const userId = cancellation.userId;
|
|
||||||
const deviceId = cancellation.deviceId;
|
|
||||||
const requestId = cancellation.requestId;
|
|
||||||
|
|
||||||
if (userId === this._currentUser && deviceId === this._currentDevice) {
|
|
||||||
console.log(
|
|
||||||
"room key request cancellation for the user we currently have a"
|
|
||||||
+ " dialog open for",
|
|
||||||
);
|
|
||||||
// TODO: update the dialog. For now, we just ignore the
|
|
||||||
// cancellation.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this._pendingKeyRequests[userId]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const requests = this._pendingKeyRequests[userId][deviceId];
|
|
||||||
if (!requests) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const idx = requests.findIndex((r) => r.requestId === requestId);
|
|
||||||
if (idx < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log("Forgetting room key request");
|
|
||||||
requests.splice(idx, 1);
|
|
||||||
if (requests.length === 0) {
|
|
||||||
delete this._pendingKeyRequests[userId][deviceId];
|
|
||||||
if (Object.keys(this._pendingKeyRequests[userId]).length === 0) {
|
|
||||||
delete this._pendingKeyRequests[userId];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_processNextRequest() {
|
|
||||||
const userId = Object.keys(this._pendingKeyRequests)[0];
|
|
||||||
if (!userId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const deviceId = Object.keys(this._pendingKeyRequests[userId])[0];
|
|
||||||
if (!deviceId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log(`Starting KeyShareDialog for ${userId}:${deviceId}`);
|
|
||||||
|
|
||||||
const finished = (r) => {
|
|
||||||
this._currentUser = null;
|
|
||||||
this._currentDevice = null;
|
|
||||||
|
|
||||||
if (!this._pendingKeyRequests[userId] || !this._pendingKeyRequests[userId][deviceId]) {
|
|
||||||
// request was removed in the time the dialog was displayed
|
|
||||||
this._processNextRequest();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r) {
|
|
||||||
for (const req of this._pendingKeyRequests[userId][deviceId]) {
|
|
||||||
req.share();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete this._pendingKeyRequests[userId][deviceId];
|
|
||||||
if (Object.keys(this._pendingKeyRequests[userId]).length === 0) {
|
|
||||||
delete this._pendingKeyRequests[userId];
|
|
||||||
}
|
|
||||||
|
|
||||||
this._processNextRequest();
|
|
||||||
};
|
|
||||||
|
|
||||||
const KeyShareDialog = sdk.getComponent("dialogs.KeyShareDialog");
|
|
||||||
Modal.appendTrackedDialog('Key Share', 'Process Next Request', KeyShareDialog, {
|
|
||||||
matrixClient: this._matrixClient,
|
|
||||||
userId: userId,
|
|
||||||
deviceId: deviceId,
|
|
||||||
onFinished: finished,
|
|
||||||
});
|
|
||||||
this._currentUser = userId;
|
|
||||||
this._currentDevice = deviceId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -49,7 +49,6 @@ import PageTypes from '../../PageTypes';
|
||||||
import { getHomePageUrl } from '../../utils/pages';
|
import { getHomePageUrl } from '../../utils/pages';
|
||||||
|
|
||||||
import createRoom from "../../createRoom";
|
import createRoom from "../../createRoom";
|
||||||
import KeyRequestHandler from '../../KeyRequestHandler';
|
|
||||||
import { _t, getCurrentLanguage } from '../../languageHandler';
|
import { _t, getCurrentLanguage } from '../../languageHandler';
|
||||||
import SettingsStore, { SettingLevel } from "../../settings/SettingsStore";
|
import SettingsStore, { SettingLevel } from "../../settings/SettingsStore";
|
||||||
import ThemeController from "../../settings/controllers/ThemeController";
|
import ThemeController from "../../settings/controllers/ThemeController";
|
||||||
|
@ -1471,16 +1470,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
cli.on("Session.logged_out", () => dft.stop());
|
cli.on("Session.logged_out", () => dft.stop());
|
||||||
cli.on("Event.decrypted", (e, err) => dft.eventDecrypted(e, err));
|
cli.on("Event.decrypted", (e, err) => dft.eventDecrypted(e, err));
|
||||||
|
|
||||||
// TODO: We can remove this once cross-signing is the only way.
|
|
||||||
// https://github.com/vector-im/riot-web/issues/11908
|
|
||||||
const krh = new KeyRequestHandler(cli);
|
|
||||||
cli.on("crypto.roomKeyRequest", (req) => {
|
|
||||||
krh.handleKeyRequest(req);
|
|
||||||
});
|
|
||||||
cli.on("crypto.roomKeyRequestCancellation", (req) => {
|
|
||||||
krh.handleKeyRequestCancellation(req);
|
|
||||||
});
|
|
||||||
|
|
||||||
cli.on("Room", (room) => {
|
cli.on("Room", (room) => {
|
||||||
if (MatrixClientPeg.get().isCryptoEnabled()) {
|
if (MatrixClientPeg.get().isCryptoEnabled()) {
|
||||||
const blacklistEnabled = SettingsStore.getValueAt(
|
const blacklistEnabled = SettingsStore.getValueAt(
|
||||||
|
|
|
@ -1,178 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 Vector Creations Ltd
|
|
||||||
|
|
||||||
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 Modal from '../../../Modal';
|
|
||||||
import React from 'react';
|
|
||||||
import createReactClass from 'create-react-class';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import * as sdk from '../../../index';
|
|
||||||
|
|
||||||
import { _t, _td } from '../../../languageHandler';
|
|
||||||
|
|
||||||
// TODO: We can remove this once cross-signing is the only way.
|
|
||||||
// https://github.com/vector-im/riot-web/issues/11908
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dialog which asks the user whether they want to share their keys with
|
|
||||||
* an unverified device.
|
|
||||||
*
|
|
||||||
* onFinished is called with `true` if the key should be shared, `false` if it
|
|
||||||
* should not, and `undefined` if the dialog is cancelled. (In other words:
|
|
||||||
* truthy: do the key share. falsy: don't share the keys).
|
|
||||||
*/
|
|
||||||
export default createReactClass({
|
|
||||||
propTypes: {
|
|
||||||
matrixClient: PropTypes.object.isRequired,
|
|
||||||
userId: PropTypes.string.isRequired,
|
|
||||||
deviceId: PropTypes.string.isRequired,
|
|
||||||
onFinished: PropTypes.func.isRequired,
|
|
||||||
},
|
|
||||||
|
|
||||||
getInitialState: function() {
|
|
||||||
return {
|
|
||||||
deviceInfo: null,
|
|
||||||
wasNewDevice: false,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidMount: function() {
|
|
||||||
this._unmounted = false;
|
|
||||||
const userId = this.props.userId;
|
|
||||||
const deviceId = this.props.deviceId;
|
|
||||||
|
|
||||||
// give the client a chance to refresh the device list
|
|
||||||
this.props.matrixClient.downloadKeys([userId], false).then((r) => {
|
|
||||||
if (this._unmounted) { return; }
|
|
||||||
|
|
||||||
const deviceInfo = r[userId][deviceId];
|
|
||||||
|
|
||||||
if (!deviceInfo) {
|
|
||||||
console.warn(`No details found for session ${userId}:${deviceId}`);
|
|
||||||
|
|
||||||
this.props.onFinished(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const wasNewDevice = !deviceInfo.isKnown();
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
deviceInfo: deviceInfo,
|
|
||||||
wasNewDevice: wasNewDevice,
|
|
||||||
});
|
|
||||||
|
|
||||||
// if the device was new before, it's not any more.
|
|
||||||
if (wasNewDevice) {
|
|
||||||
this.props.matrixClient.setDeviceKnown(
|
|
||||||
userId,
|
|
||||||
deviceId,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
componentWillUnmount: function() {
|
|
||||||
this._unmounted = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
_onVerifyClicked: function() {
|
|
||||||
const DeviceVerifyDialog = sdk.getComponent('views.dialogs.DeviceVerifyDialog');
|
|
||||||
|
|
||||||
console.log("KeyShareDialog: Starting verify dialog");
|
|
||||||
Modal.createTrackedDialog('Key Share', 'Starting dialog', DeviceVerifyDialog, {
|
|
||||||
userId: this.props.userId,
|
|
||||||
device: this.state.deviceInfo,
|
|
||||||
onFinished: (verified) => {
|
|
||||||
if (verified) {
|
|
||||||
// can automatically share the keys now.
|
|
||||||
this.props.onFinished(true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}, null, /* priority = */ false, /* static = */ true);
|
|
||||||
},
|
|
||||||
|
|
||||||
_onShareClicked: function() {
|
|
||||||
console.log("KeyShareDialog: User clicked 'share'");
|
|
||||||
this.props.onFinished(true);
|
|
||||||
},
|
|
||||||
|
|
||||||
_onIgnoreClicked: function() {
|
|
||||||
console.log("KeyShareDialog: User clicked 'ignore'");
|
|
||||||
this.props.onFinished(false);
|
|
||||||
},
|
|
||||||
|
|
||||||
_renderContent: function() {
|
|
||||||
const displayName = this.state.deviceInfo.getDisplayName() ||
|
|
||||||
this.state.deviceInfo.deviceId;
|
|
||||||
|
|
||||||
let text;
|
|
||||||
if (this.state.wasNewDevice) {
|
|
||||||
text = _td("You added a new session '%(displayName)s', which is"
|
|
||||||
+ " requesting encryption keys.");
|
|
||||||
} else {
|
|
||||||
text = _td("Your unverified session '%(displayName)s' is requesting"
|
|
||||||
+ " encryption keys.");
|
|
||||||
}
|
|
||||||
text = _t(text, {displayName: displayName});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div id='mx_Dialog_content'>
|
|
||||||
<p>{ text }</p>
|
|
||||||
|
|
||||||
<div className="mx_Dialog_buttons">
|
|
||||||
<button onClick={this._onVerifyClicked} autoFocus="true">
|
|
||||||
{ _t('Start verification') }
|
|
||||||
</button>
|
|
||||||
<button onClick={this._onShareClicked}>
|
|
||||||
{ _t('Share without verifying') }
|
|
||||||
</button>
|
|
||||||
<button onClick={this._onIgnoreClicked}>
|
|
||||||
{ _t('Ignore request') }
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
||||||
const Spinner = sdk.getComponent('views.elements.Spinner');
|
|
||||||
|
|
||||||
let content;
|
|
||||||
|
|
||||||
if (this.state.deviceInfo) {
|
|
||||||
content = this._renderContent();
|
|
||||||
} else {
|
|
||||||
content = (
|
|
||||||
<div id='mx_Dialog_content'>
|
|
||||||
<p>{ _t('Loading session info...') }</p>
|
|
||||||
<Spinner />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<BaseDialog className='mx_KeyShareRequestDialog'
|
|
||||||
onFinished={this.props.onFinished}
|
|
||||||
title={_t('Encryption key request')}
|
|
||||||
contentId='mx_Dialog_content'
|
|
||||||
>
|
|
||||||
{ content }
|
|
||||||
</BaseDialog>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1669,13 +1669,6 @@
|
||||||
"Start a conversation with someone using their name, username (like <userId/>) or email address.": "Start a conversation with someone using their name, username (like <userId/>) or email address.",
|
"Start a conversation with someone using their name, username (like <userId/>) or email address.": "Start a conversation with someone using their name, username (like <userId/>) or email address.",
|
||||||
"Go": "Go",
|
"Go": "Go",
|
||||||
"Invite someone using their name, username (like <userId/>), email address or <a>share this room</a>.": "Invite someone using their name, username (like <userId/>), email address or <a>share this room</a>.",
|
"Invite someone using their name, username (like <userId/>), email address or <a>share this room</a>.": "Invite someone using their name, username (like <userId/>), email address or <a>share this room</a>.",
|
||||||
"You added a new session '%(displayName)s', which is requesting encryption keys.": "You added a new session '%(displayName)s', which is requesting encryption keys.",
|
|
||||||
"Your unverified session '%(displayName)s' is requesting encryption keys.": "Your unverified session '%(displayName)s' is requesting encryption keys.",
|
|
||||||
"Start verification": "Start verification",
|
|
||||||
"Share without verifying": "Share without verifying",
|
|
||||||
"Ignore request": "Ignore request",
|
|
||||||
"Loading session info...": "Loading session info...",
|
|
||||||
"Encryption key request": "Encryption key request",
|
|
||||||
"a new master key signature": "a new master key signature",
|
"a new master key signature": "a new master key signature",
|
||||||
"a new cross-signing key signature": "a new cross-signing key signature",
|
"a new cross-signing key signature": "a new cross-signing key signature",
|
||||||
"a device cross-signing signature": "a device cross-signing signature",
|
"a device cross-signing signature": "a device cross-signing signature",
|
||||||
|
|
Loading…
Reference in New Issue