You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-11-28 05:03:59 +03:00
Make Crypto._processReceivedRoomKeyRequests async
This is slightly complicated by the fact that it's initiated from a synchronous process which we don't want to make async (processing the /sync response) and we want to avoid racing two copies of the processor.
This commit is contained in:
@@ -104,6 +104,8 @@ function Crypto(baseApis, sessionStore, userId, deviceId,
|
|||||||
// we received in the current sync.
|
// we received in the current sync.
|
||||||
this._receivedRoomKeyRequests = [];
|
this._receivedRoomKeyRequests = [];
|
||||||
this._receivedRoomKeyRequestCancellations = [];
|
this._receivedRoomKeyRequestCancellations = [];
|
||||||
|
// true if we are currently processing received room key requests
|
||||||
|
this._processingRoomKeyRequests = false;
|
||||||
|
|
||||||
let myDevices = this._sessionStore.getEndToEndDevicesForUser(
|
let myDevices = this._sessionStore.getEndToEndDevicesForUser(
|
||||||
this._userId,
|
this._userId,
|
||||||
@@ -1059,79 +1061,124 @@ Crypto.prototype._onRoomKeyRequestEvent = function(event) {
|
|||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
Crypto.prototype._processReceivedRoomKeyRequests = function() {
|
Crypto.prototype._processReceivedRoomKeyRequests = async function() {
|
||||||
const requests = this._receivedRoomKeyRequests;
|
if (this._processingRoomKeyRequests) {
|
||||||
this._receivedRoomKeyRequests = [];
|
// we're still processing last time's requests; keep queuing new ones
|
||||||
for (const req of requests) {
|
// up for now.
|
||||||
const userId = req.userId;
|
return;
|
||||||
const deviceId = req.deviceId;
|
}
|
||||||
|
this._processingRoomKeyRequests = true;
|
||||||
|
|
||||||
const body = req.requestBody;
|
try {
|
||||||
const roomId = body.room_id;
|
// we need to grab and clear the queues in the synchronous bit of this method,
|
||||||
const alg = body.algorithm;
|
// so that we don't end up racing with the next /sync.
|
||||||
|
const requests = this._receivedRoomKeyRequests;
|
||||||
|
this._receivedRoomKeyRequests = [];
|
||||||
|
const cancellations = this._receivedRoomKeyRequestCancellations;
|
||||||
|
this._receivedRoomKeyRequestCancellations = [];
|
||||||
|
|
||||||
console.log(`m.room_key_request from ${userId}:${deviceId}` +
|
// Process all of the requests, *then* all of the cancellations.
|
||||||
|
//
|
||||||
|
// This makes sure that if we get a request and its cancellation in the
|
||||||
|
// same /sync result, then we process the request before the
|
||||||
|
// cancellation (and end up with a cancelled request), rather than the
|
||||||
|
// cancellation before the request (and end up with an outstanding
|
||||||
|
// request which should have been cancelled.)
|
||||||
|
await Promise.map(
|
||||||
|
requests, (req) =>
|
||||||
|
this._processReceivedRoomKeyRequest(req),
|
||||||
|
);
|
||||||
|
await Promise.map(
|
||||||
|
cancellations, (cancellation) =>
|
||||||
|
this._processReceivedRoomKeyRequestCancellation(cancellation),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`Error processing room key requsts: ${e}`);
|
||||||
|
} finally {
|
||||||
|
this._processingRoomKeyRequests = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for processReceivedRoomKeyRequests
|
||||||
|
*
|
||||||
|
* @param {IncomingRoomKeyRequest} req
|
||||||
|
*/
|
||||||
|
Crypto.prototype._processReceivedRoomKeyRequest = async function(req) {
|
||||||
|
const userId = req.userId;
|
||||||
|
const deviceId = req.deviceId;
|
||||||
|
|
||||||
|
const body = req.requestBody;
|
||||||
|
const roomId = body.room_id;
|
||||||
|
const alg = body.algorithm;
|
||||||
|
|
||||||
|
console.log(`m.room_key_request from ${userId}:${deviceId}` +
|
||||||
` for ${roomId} / ${body.session_id} (id ${req.requestId})`);
|
` for ${roomId} / ${body.session_id} (id ${req.requestId})`);
|
||||||
|
|
||||||
if (userId !== this._userId) {
|
if (userId !== this._userId) {
|
||||||
// TODO: determine if we sent this device the keys already: in
|
// TODO: determine if we sent this device the keys already: in
|
||||||
// which case we can do so again.
|
// which case we can do so again.
|
||||||
console.log("Ignoring room key request from other user for now");
|
console.log("Ignoring room key request from other user for now");
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// todo: should we queue up requests we don't yet have keys for,
|
|
||||||
// in case they turn up later?
|
|
||||||
|
|
||||||
// if we don't have a decryptor for this room/alg, we don't have
|
|
||||||
// the keys for the requested events, and can drop the requests.
|
|
||||||
if (!this._roomDecryptors[roomId]) {
|
|
||||||
console.log(`room key request for unencrypted room ${roomId}`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const decryptor = this._roomDecryptors[roomId][alg];
|
|
||||||
if (!decryptor) {
|
|
||||||
console.log(`room key request for unknown alg ${alg} in room ${roomId}`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!decryptor.hasKeysForKeyRequest(req)) {
|
|
||||||
console.log(
|
|
||||||
`room key request for unknown session ${roomId} / ` +
|
|
||||||
body.session_id,
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
req.share = () => {
|
|
||||||
decryptor.shareKeysWithDevice(req);
|
|
||||||
};
|
|
||||||
|
|
||||||
// if the device is is verified already, share the keys
|
|
||||||
const device = this._deviceList.getStoredDevice(userId, deviceId);
|
|
||||||
if (device && device.isVerified()) {
|
|
||||||
console.log('device is already verified: sharing keys');
|
|
||||||
req.share();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emit("crypto.roomKeyRequest", req);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const cancellations = this._receivedRoomKeyRequestCancellations;
|
// todo: should we queue up requests we don't yet have keys for,
|
||||||
this._receivedRoomKeyRequestCancellations = [];
|
// in case they turn up later?
|
||||||
for (const cancellation of cancellations) {
|
|
||||||
|
// if we don't have a decryptor for this room/alg, we don't have
|
||||||
|
// the keys for the requested events, and can drop the requests.
|
||||||
|
if (!this._roomDecryptors[roomId]) {
|
||||||
|
console.log(`room key request for unencrypted room ${roomId}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const decryptor = this._roomDecryptors[roomId][alg];
|
||||||
|
if (!decryptor) {
|
||||||
|
console.log(`room key request for unknown alg ${alg} in room ${roomId}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!decryptor.hasKeysForKeyRequest(req)) {
|
||||||
console.log(
|
console.log(
|
||||||
`m.room_key_request cancellation for ${cancellation.userId}:` +
|
`room key request for unknown session ${roomId} / ` +
|
||||||
`${cancellation.deviceId} (id ${cancellation.requestId})`,
|
body.session_id,
|
||||||
);
|
);
|
||||||
|
return;
|
||||||
// we should probably only notify the app of cancellations we told it
|
|
||||||
// about, but we don't currently have a record of that, so we just pass
|
|
||||||
// everything through.
|
|
||||||
this.emit("crypto.roomKeyRequestCancellation", cancellation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
req.share = () => {
|
||||||
|
decryptor.shareKeysWithDevice(req);
|
||||||
|
};
|
||||||
|
|
||||||
|
// if the device is is verified already, share the keys
|
||||||
|
const device = this._deviceList.getStoredDevice(userId, deviceId);
|
||||||
|
if (device && device.isVerified()) {
|
||||||
|
console.log('device is already verified: sharing keys');
|
||||||
|
req.share();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emit("crypto.roomKeyRequest", req);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for processReceivedRoomKeyRequests
|
||||||
|
*
|
||||||
|
* @param {IncomingRoomKeyRequestCancellation} cancellation
|
||||||
|
*/
|
||||||
|
Crypto.prototype._processReceivedRoomKeyRequestCancellation = async function(
|
||||||
|
cancellation,
|
||||||
|
) {
|
||||||
|
console.log(
|
||||||
|
`m.room_key_request cancellation for ${cancellation.userId}:` +
|
||||||
|
`${cancellation.deviceId} (id ${cancellation.requestId})`,
|
||||||
|
);
|
||||||
|
|
||||||
|
// we should probably only notify the app of cancellations we told it
|
||||||
|
// about, but we don't currently have a record of that, so we just pass
|
||||||
|
// everything through.
|
||||||
|
this.emit("crypto.roomKeyRequestCancellation", cancellation);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user