Merge pull request #1233 from matrix-org/rav/async_crypto
Prepare for asynchronous e2e APIs
This commit is contained in:
commit
0e8ad75248
5 changed files with 93 additions and 62 deletions
|
@ -78,6 +78,18 @@ class MatrixClientPeg {
|
||||||
}
|
}
|
||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
|
// try to initialise e2e on the new client
|
||||||
|
try {
|
||||||
|
// check that we have a version of the js-sdk which includes initCrypto
|
||||||
|
if (this.matrixClient.initCrypto) {
|
||||||
|
await this.matrixClient.initCrypto();
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
// this can happen for a number of reasons, the most likely being
|
||||||
|
// that the olm library was missing. It's not fatal.
|
||||||
|
console.warn("Unable to initialise e2e: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
const opts = utils.deepCopy(this.opts);
|
const opts = utils.deepCopy(this.opts);
|
||||||
// the react sdk doesn't work without this, so don't allow
|
// the react sdk doesn't work without this, so don't allow
|
||||||
opts.pendingEventOrdering = "detached";
|
opts.pendingEventOrdering = "detached";
|
||||||
|
|
|
@ -301,51 +301,54 @@ const commands = {
|
||||||
const deviceId = matches[2];
|
const deviceId = matches[2];
|
||||||
const fingerprint = matches[3];
|
const fingerprint = matches[3];
|
||||||
|
|
||||||
const device = MatrixClientPeg.get().getStoredDevice(userId, deviceId);
|
return success(
|
||||||
if (!device) {
|
// Promise.resolve to handle transition from static result to promise; can be removed
|
||||||
return reject(_t(`Unknown (user, device) pair:`) + ` (${userId}, ${deviceId})`);
|
// in future
|
||||||
}
|
Promise.resolve(MatrixClientPeg.get().getStoredDevice(userId, deviceId)).then((device) => {
|
||||||
|
if (!device) {
|
||||||
|
throw new Error(_t(`Unknown (user, device) pair:`) + ` (${userId}, ${deviceId})`);
|
||||||
|
}
|
||||||
|
|
||||||
if (device.isVerified()) {
|
if (device.isVerified()) {
|
||||||
if (device.getFingerprint() === fingerprint) {
|
if (device.getFingerprint() === fingerprint) {
|
||||||
return reject(_t(`Device already verified!`));
|
throw new Error(_t(`Device already verified!`));
|
||||||
} else {
|
} else {
|
||||||
return reject(_t(`WARNING: Device already verified, but keys do NOT MATCH!`));
|
throw new Error(_t(`WARNING: Device already verified, but keys do NOT MATCH!`));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device.getFingerprint() === fingerprint) {
|
if (device.getFingerprint() !== fingerprint) {
|
||||||
MatrixClientPeg.get().setDeviceVerified(
|
const fprint = device.getFingerprint();
|
||||||
userId, deviceId, true,
|
throw new Error(
|
||||||
);
|
_t('WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and device' +
|
||||||
|
' %(deviceId)s is "%(fprint)s" which does not match the provided key' +
|
||||||
|
' "%(fingerprint)s". This could mean your communications are being intercepted!',
|
||||||
|
{deviceId: deviceId, fprint: fprint, userId: userId, fingerprint: fingerprint}));
|
||||||
|
}
|
||||||
|
|
||||||
// Tell the user we verified everything!
|
return MatrixClientPeg.get().setDeviceVerified(
|
||||||
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
userId, deviceId, true,
|
||||||
Modal.createDialog(QuestionDialog, {
|
);
|
||||||
title: _t("Verified key"),
|
}).then(() => {
|
||||||
description: (
|
// Tell the user we verified everything
|
||||||
<div>
|
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
||||||
<p>
|
Modal.createDialog(QuestionDialog, {
|
||||||
{
|
title: _t("Verified key"),
|
||||||
_t("The signing key you provided matches the signing key you received " +
|
description: (
|
||||||
"from %(userId)s's device %(deviceId)s. Device marked as verified.",
|
<div>
|
||||||
{userId: userId, deviceId: deviceId})
|
<p>
|
||||||
}
|
{
|
||||||
</p>
|
_t("The signing key you provided matches the signing key you received " +
|
||||||
</div>
|
"from %(userId)s's device %(deviceId)s. Device marked as verified.",
|
||||||
),
|
{userId: userId, deviceId: deviceId})
|
||||||
hasCancelButton: false,
|
}
|
||||||
});
|
</p>
|
||||||
|
</div>
|
||||||
return success();
|
),
|
||||||
} else {
|
hasCancelButton: false,
|
||||||
const fprint = device.getFingerprint();
|
});
|
||||||
return reject(
|
}),
|
||||||
_t('WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and device' +
|
);
|
||||||
' %(deviceId)s is "%(fprint)s" which does not match the provided key' +
|
|
||||||
' "%(fingerprint)s". This could mean your communications are being intercepted!',
|
|
||||||
{deviceId: deviceId, fprint: fprint, userId: userId, fingerprint: fingerprint}));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return reject(this.getUsage());
|
return reject(this.getUsage());
|
||||||
|
|
|
@ -28,23 +28,31 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return { device: this.refreshDevice() };
|
return { device: null };
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentWillMount: function() {
|
||||||
this._unmounted = false;
|
this._unmounted = false;
|
||||||
var client = MatrixClientPeg.get();
|
var client = MatrixClientPeg.get();
|
||||||
client.on("deviceVerificationChanged", this.onDeviceVerificationChanged);
|
|
||||||
|
|
||||||
// no need to redownload keys if we already have the device
|
// first try to load the device from our store.
|
||||||
if (this.state.device) {
|
//
|
||||||
return;
|
this.refreshDevice().then((dev) => {
|
||||||
}
|
if (dev) {
|
||||||
client.downloadKeys([this.props.event.getSender()], true).done(()=>{
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tell the client to try to refresh the device list for this user
|
||||||
|
return client.downloadKeys([this.props.event.getSender()], true).then(() => {
|
||||||
|
return this.refreshDevice();
|
||||||
|
});
|
||||||
|
}).then((dev) => {
|
||||||
if (this._unmounted) {
|
if (this._unmounted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.setState({ device: this.refreshDevice() });
|
|
||||||
|
this.setState({ device: dev });
|
||||||
|
client.on("deviceVerificationChanged", this.onDeviceVerificationChanged);
|
||||||
}, (err)=>{
|
}, (err)=>{
|
||||||
console.log("Error downloading devices", err);
|
console.log("Error downloading devices", err);
|
||||||
});
|
});
|
||||||
|
@ -59,12 +67,16 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
refreshDevice: function() {
|
refreshDevice: function() {
|
||||||
return MatrixClientPeg.get().getEventSenderDeviceInfo(this.props.event);
|
// Promise.resolve to handle transition from static result to promise; can be removed
|
||||||
|
// in future
|
||||||
|
return Promise.resolve(MatrixClientPeg.get().getEventSenderDeviceInfo(this.props.event));
|
||||||
},
|
},
|
||||||
|
|
||||||
onDeviceVerificationChanged: function(userId, device) {
|
onDeviceVerificationChanged: function(userId, device) {
|
||||||
if (userId == this.props.event.getSender()) {
|
if (userId == this.props.event.getSender()) {
|
||||||
this.setState({ device: this.refreshDevice() });
|
this.refreshDevice().then((dev) => {
|
||||||
|
this.setState({ device: dev });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -193,13 +193,12 @@ module.exports = withMatrixClient(React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_verifyEvent: function(mxEvent) {
|
_verifyEvent: async function(mxEvent) {
|
||||||
var verified = null;
|
if (!mxEvent.isEncrypted()) {
|
||||||
|
return;
|
||||||
if (mxEvent.isEncrypted()) {
|
|
||||||
verified = this.props.matrixClient.isEventSenderVerified(mxEvent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const verified = await this.props.matrixClient.isEventSenderVerified(mxEvent);
|
||||||
this.setState({
|
this.setState({
|
||||||
verified: verified
|
verified: verified
|
||||||
});
|
});
|
||||||
|
|
|
@ -136,8 +136,12 @@ module.exports = withMatrixClient(React.createClass({
|
||||||
if (userId == this.props.member.userId) {
|
if (userId == this.props.member.userId) {
|
||||||
// no need to re-download the whole thing; just update our copy of
|
// no need to re-download the whole thing; just update our copy of
|
||||||
// the list.
|
// the list.
|
||||||
var devices = this.props.matrixClient.getStoredDevicesForUser(userId);
|
|
||||||
this.setState({devices: devices});
|
// Promise.resolve to handle transition from static result to promise; can be removed
|
||||||
|
// in future
|
||||||
|
Promise.resolve(this.props.matrixClient.getStoredDevicesForUser(userId)).then((devices) => {
|
||||||
|
this.setState({devices: devices});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -204,14 +208,15 @@ module.exports = withMatrixClient(React.createClass({
|
||||||
|
|
||||||
var client = this.props.matrixClient;
|
var client = this.props.matrixClient;
|
||||||
var self = this;
|
var self = this;
|
||||||
client.downloadKeys([member.userId], true).finally(function() {
|
client.downloadKeys([member.userId], true).then(() => {
|
||||||
|
return client.getStoredDevicesForUser(member.userId);
|
||||||
|
}).finally(function() {
|
||||||
self._cancelDeviceList = null;
|
self._cancelDeviceList = null;
|
||||||
}).done(function() {
|
}).done(function(devices) {
|
||||||
if (cancelled) {
|
if (cancelled) {
|
||||||
// we got cancelled - presumably a different user now
|
// we got cancelled - presumably a different user now
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var devices = client.getStoredDevicesForUser(member.userId);
|
|
||||||
self._disambiguateDevices(devices);
|
self._disambiguateDevices(devices);
|
||||||
self.setState({devicesLoading: false, devices: devices});
|
self.setState({devicesLoading: false, devices: devices});
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
|
|
Loading…
Reference in a new issue