1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-26 17:03:12 +03:00

Add function to cancel and resend key request (#624)

This commit is contained in:
Luke Barnard
2018-03-08 15:01:01 +00:00
committed by GitHub
parent 0eb72122ce
commit 68b230a78f
4 changed files with 92 additions and 21 deletions

View File

@@ -623,6 +623,16 @@ MatrixClient.prototype.isEventSenderVerified = async function(event) {
return device.isVerified(); return device.isVerified();
}; };
/**
* Cancel a room key request for this event if one is ongoing and resend the
* request.
* @param {MatrxEvent} event event of which to cancel and resend the room
* key request.
*/
MatrixClient.prototype.cancelAndResendEventRoomKeyRequest = function(event) {
event.cancelAndResendKeyRequest(this._crypto);
};
/** /**
* Enable end-to-end encryption for a room. * Enable end-to-end encryption for a room.
* @param {string} roomId The room ID to enable encryption in. * @param {string} roomId The room ID to enable encryption in.

View File

@@ -35,13 +35,19 @@ const SEND_KEY_REQUESTS_DELAY_MS = 500;
* *
* The state machine looks like: * The state machine looks like:
* *
* | * | (cancellation sent)
* V (cancellation requested) * | .-------------------------------------------------.
* UNSENT -----------------------------+ * | | |
* | | * V V (cancellation requested) |
* | (send successful) | * UNSENT -----------------------------+ |
* V | * | | |
* SENT | * | | |
* | (send successful) | CANCELLATION_PENDING_AND_WILL_RESEND
* V | Λ
* SENT | |
* |-------------------------------- | --------------'
* | | (cancellation requested with intent
* | | to resend the original request)
* | | * | |
* | (cancellation requested) | * | (cancellation requested) |
* V | * V |
@@ -62,6 +68,12 @@ const ROOM_KEY_REQUEST_STATES = {
/** reply received, cancellation not yet sent */ /** reply received, cancellation not yet sent */
CANCELLATION_PENDING: 2, CANCELLATION_PENDING: 2,
/**
* Cancellation not yet sent and will transition to UNSENT instead of
* being deleted once the cancellation has been sent.
*/
CANCELLATION_PENDING_AND_WILL_RESEND: 3,
}; };
export default class OutgoingRoomKeyRequestManager { export default class OutgoingRoomKeyRequestManager {
@@ -130,14 +142,16 @@ export default class OutgoingRoomKeyRequestManager {
} }
/** /**
* Cancel room key requests, if any match the given details * Cancel room key requests, if any match the given requestBody
* *
* @param {module:crypto~RoomKeyRequestBody} requestBody * @param {module:crypto~RoomKeyRequestBody} requestBody
* @param {boolean} andResend if true, transition to UNSENT instead of
* deleting after sending cancellation.
* *
* @returns {Promise} resolves when the request has been updated in our * @returns {Promise} resolves when the request has been updated in our
* pending list. * pending list.
*/ */
cancelRoomKeyRequest(requestBody) { cancelRoomKeyRequest(requestBody, andResend=false) {
return this._cryptoStore.getOutgoingRoomKeyRequest( return this._cryptoStore.getOutgoingRoomKeyRequest(
requestBody, requestBody,
).then((req) => { ).then((req) => {
@@ -147,6 +161,7 @@ export default class OutgoingRoomKeyRequestManager {
} }
switch (req.state) { switch (req.state) {
case ROOM_KEY_REQUEST_STATES.CANCELLATION_PENDING: case ROOM_KEY_REQUEST_STATES.CANCELLATION_PENDING:
case ROOM_KEY_REQUEST_STATES.CANCELLATION_PENDING_AND_WILL_RESEND:
// nothing to do here // nothing to do here
return; return;
@@ -166,11 +181,16 @@ export default class OutgoingRoomKeyRequestManager {
req.requestId, ROOM_KEY_REQUEST_STATES.UNSENT, req.requestId, ROOM_KEY_REQUEST_STATES.UNSENT,
); );
case ROOM_KEY_REQUEST_STATES.SENT: case ROOM_KEY_REQUEST_STATES.SENT: {
// If `andResend` is set, transition to UNSENT once the
// cancellation has successfully been sent.
const state = andResend ?
ROOM_KEY_REQUEST_STATES.CANCELLATION_PENDING_AND_WILL_RESEND :
ROOM_KEY_REQUEST_STATES.CANCELLATION_PENDING;
// send a cancellation. // send a cancellation.
return this._cryptoStore.updateOutgoingRoomKeyRequest( return this._cryptoStore.updateOutgoingRoomKeyRequest(
req.requestId, ROOM_KEY_REQUEST_STATES.SENT, { req.requestId, ROOM_KEY_REQUEST_STATES.SENT, {
state: ROOM_KEY_REQUEST_STATES.CANCELLATION_PENDING, state,
cancellationTxnId: this._baseApis.makeTxnId(), cancellationTxnId: this._baseApis.makeTxnId(),
}, },
).then((updatedReq) => { ).then((updatedReq) => {
@@ -200,15 +220,23 @@ export default class OutgoingRoomKeyRequestManager {
// do.) // do.)
this._sendOutgoingRoomKeyRequestCancellation( this._sendOutgoingRoomKeyRequestCancellation(
updatedReq, updatedReq,
andResend,
).catch((e) => { ).catch((e) => {
console.error( console.error(
"Error sending room key request cancellation;" "Error sending room key request cancellation;"
+ " will retry later.", e, + " will retry later.", e,
); );
this._startTimer(); this._startTimer();
}).done(); }).then(() => {
if (!andResend) return;
// The request has transitioned from
// CANCELLATION_PENDING_AND_WILL_RESEND to UNSENT. We
// still need to resend the request which is now UNSENT, so
// start the timer if it isn't already started.
this._startTimer();
});
}); });
}
default: default:
throw new Error('unhandled state: ' + req.state); throw new Error('unhandled state: ' + req.state);
} }
@@ -258,6 +286,7 @@ export default class OutgoingRoomKeyRequestManager {
return this._cryptoStore.getOutgoingRoomKeyRequestByState([ return this._cryptoStore.getOutgoingRoomKeyRequestByState([
ROOM_KEY_REQUEST_STATES.CANCELLATION_PENDING, ROOM_KEY_REQUEST_STATES.CANCELLATION_PENDING,
ROOM_KEY_REQUEST_STATES.CANCELLATION_PENDING_AND_WILL_RESEND,
ROOM_KEY_REQUEST_STATES.UNSENT, ROOM_KEY_REQUEST_STATES.UNSENT,
]).then((req) => { ]).then((req) => {
if (!req) { if (!req) {
@@ -267,10 +296,16 @@ export default class OutgoingRoomKeyRequestManager {
} }
let prom; let prom;
if (req.state === ROOM_KEY_REQUEST_STATES.UNSENT) { switch (req.state) {
prom = this._sendOutgoingRoomKeyRequest(req); case ROOM_KEY_REQUEST_STATES.UNSENT:
} else { // must be a cancellation prom = this._sendOutgoingRoomKeyRequest(req);
prom = this._sendOutgoingRoomKeyRequestCancellation(req); break;
case ROOM_KEY_REQUEST_STATES.CANCELLATION_PENDING:
prom = this._sendOutgoingRoomKeyRequestCancellation(req);
break;
case ROOM_KEY_REQUEST_STATES.CANCELLATION_PENDING_AND_WILL_RESEND:
prom = this._sendOutgoingRoomKeyRequestCancellation(req, true);
break;
} }
return prom.then(() => { return prom.then(() => {
@@ -309,8 +344,9 @@ export default class OutgoingRoomKeyRequestManager {
}); });
} }
// given a RoomKeyRequest, cancel it and delete the request record // Given a RoomKeyRequest, cancel it and delete the request record unless
_sendOutgoingRoomKeyRequestCancellation(req) { // andResend is set, in which case transition to UNSENT.
_sendOutgoingRoomKeyRequestCancellation(req, andResend) {
console.log( console.log(
`Sending cancellation for key request for ` + `Sending cancellation for key request for ` +
`${stringifyRequestBody(req.requestBody)} to ` + `${stringifyRequestBody(req.requestBody)} to ` +
@@ -327,6 +363,14 @@ export default class OutgoingRoomKeyRequestManager {
return this._sendMessageToDevices( return this._sendMessageToDevices(
requestMessage, req.recipients, req.cancellationTxnId, requestMessage, req.recipients, req.cancellationTxnId,
).then(() => { ).then(() => {
if (andResend) {
// We want to resend, so transition to UNSENT
return this._cryptoStore.updateOutgoingRoomKeyRequest(
req.requestId,
ROOM_KEY_REQUEST_STATES.CANCELLATION_PENDING_AND_WILL_RESEND,
{ state: ROOM_KEY_REQUEST_STATES.UNSENT },
);
}
return this._cryptoStore.deleteOutgoingRoomKeyRequest( return this._cryptoStore.deleteOutgoingRoomKeyRequest(
req.requestId, ROOM_KEY_REQUEST_STATES.CANCELLATION_PENDING, req.requestId, ROOM_KEY_REQUEST_STATES.CANCELLATION_PENDING,
); );

View File

@@ -856,9 +856,11 @@ Crypto.prototype.requestRoomKey = function(requestBody, recipients) {
* *
* @param {module:crypto~RoomKeyRequestBody} requestBody * @param {module:crypto~RoomKeyRequestBody} requestBody
* parameters to match for cancellation * parameters to match for cancellation
* @param {boolean} andResend
* if true, resend the key request after cancelling.
*/ */
Crypto.prototype.cancelRoomKeyRequest = function(requestBody) { Crypto.prototype.cancelRoomKeyRequest = function(requestBody, andResend) {
this._outgoingRoomKeyRequestManager.cancelRoomKeyRequest(requestBody) this._outgoingRoomKeyRequestManager.cancelRoomKeyRequest(requestBody, andResend)
.catch((e) => { .catch((e) => {
console.warn("Error clearing pending room key requests", e); console.warn("Error clearing pending room key requests", e);
}).done(); }).done();

View File

@@ -378,6 +378,21 @@ utils.extend(module.exports.MatrixEvent.prototype, {
return this._decryptionPromise; return this._decryptionPromise;
}, },
/**
* Cancel any room key request for this event and resend another.
*
* @param {module:crypto} crypto crypto module
*/
cancelAndResendKeyRequest: function(crypto) {
const wireContent = this.getWireContent();
crypto.cancelRoomKeyRequest({
algorithm: wireContent.algorithm,
room_id: this.getRoomId(),
session_id: wireContent.session_id,
sender_key: wireContent.sender_key,
}, true);
},
_decryptionLoop: async function(crypto) { _decryptionLoop: async function(crypto) {
// make sure that this method never runs completely synchronously. // make sure that this method never runs completely synchronously.
// (doing so would mean that we would clear _decryptionPromise *before* // (doing so would mean that we would clear _decryptionPromise *before*