Decrypt relations before applying them to target event (#1696)

This commit is contained in:
Germain
2021-05-18 17:21:06 +01:00
committed by GitHub
parent 52a893a811
commit 40cd4629db
5 changed files with 55 additions and 16 deletions
+21 -1
View File
@@ -5566,7 +5566,7 @@ function _PojoToMatrixEventMapper(client, options = {}) {
]);
}
if (decrypt) {
event.attemptDecryption(client._crypto);
client.decryptEventIfNeeded(event);
}
}
if (!preventReEmit) {
@@ -5608,6 +5608,26 @@ MatrixClient.prototype.generateClientSecret = function() {
return randomString(32);
};
/**
* Attempts to decrypt an event
* @param {MatrixEvent} event The event to decrypt
* @returns {Promise<void>} A decryption promise
* @param {object} options
* @param {bool} options.isRetry True if this is a retry (enables more logging)
* @param {bool} options.emit Emits "event.decrypted" if set to true
*/
MatrixClient.prototype.decryptEventIfNeeded = function(event, options) {
if (event.shouldAttemptDecryption()) {
event.attemptDecryption(this._crypto, options);
}
if (event.isBeingDecrypted()) {
return event._decryptionPromise;
} else {
return Promise.resolve();
}
};
// MatrixClient Event JSDocs
/**
+4 -1
View File
@@ -3322,7 +3322,10 @@ Crypto.prototype._onToDeviceEvent = function(event) {
this._onKeyVerificationMessage(event);
} else if (event.getContent().msgtype === "m.bad.encrypted") {
this._onToDeviceBadEncrypted(event);
} else if (event.isBeingDecrypted()) {
} else if (event.isBeingDecrypted() || event.shouldAttemptDecryption()) {
if (!event.isBeingDecrypted()) {
event.attemptDecryption(this);
}
// once the event has been decrypted, try again
event.once('Event.decrypted', (ev) => {
this._onToDeviceEvent(ev);
+1 -1
View File
@@ -769,7 +769,7 @@ EventTimelineSet.prototype.aggregateRelations = function(event) {
}
// If the event is currently encrypted, wait until it has been decrypted.
if (event.isBeingDecrypted()) {
if (event.isBeingDecrypted() || event.shouldAttemptDecryption()) {
event.once("Event.decrypted", () => {
this.aggregateRelations(event);
});
+22 -10
View File
@@ -46,6 +46,7 @@ export class Relations extends EventEmitter {
this._annotationsBySender = {};
this._sortedAnnotationsByKey = [];
this._targetEvent = null;
this._room = room;
}
/**
@@ -54,7 +55,7 @@ export class Relations extends EventEmitter {
* @param {MatrixEvent} event
* The new relation event to be added.
*/
addEvent(event) {
async addEvent(event) {
if (this._relations.has(event)) {
return;
}
@@ -84,7 +85,8 @@ export class Relations extends EventEmitter {
if (this.relationType === "m.annotation") {
this._addAnnotationToAggregation(event);
} else if (this.relationType === "m.replace" && this._targetEvent) {
this._targetEvent.makeReplaced(this.getLastReplacement());
const lastReplacement = await this.getLastReplacement();
this._targetEvent.makeReplaced(lastReplacement);
}
event.on("Event.beforeRedaction", this._onBeforeRedaction);
@@ -98,7 +100,7 @@ export class Relations extends EventEmitter {
* @param {MatrixEvent} event
* The relation event to remove.
*/
_removeEvent(event) {
async _removeEvent(event) {
if (!this._relations.has(event)) {
return;
}
@@ -122,7 +124,8 @@ export class Relations extends EventEmitter {
if (this.relationType === "m.annotation") {
this._removeAnnotationFromAggregation(event);
} else if (this.relationType === "m.replace" && this._targetEvent) {
this._targetEvent.makeReplaced(this.getLastReplacement());
const lastReplacement = await this.getLastReplacement();
this._targetEvent.makeReplaced(lastReplacement);
}
this.emit("Relations.remove", event);
@@ -227,7 +230,7 @@ export class Relations extends EventEmitter {
* @param {MatrixEvent} redactedEvent
* The original relation event that is about to be redacted.
*/
_onBeforeRedaction = (redactedEvent) => {
_onBeforeRedaction = async (redactedEvent) => {
if (!this._relations.has(redactedEvent)) {
return;
}
@@ -238,7 +241,8 @@ export class Relations extends EventEmitter {
// Remove the redacted annotation from aggregation by key
this._removeAnnotationFromAggregation(redactedEvent);
} else if (this.relationType === "m.replace" && this._targetEvent) {
this._targetEvent.makeReplaced(this.getLastReplacement());
const lastReplacement = await this.getLastReplacement();
this._targetEvent.makeReplaced(lastReplacement);
}
redactedEvent.removeListener("Event.beforeRedaction", this._onBeforeRedaction);
@@ -291,7 +295,7 @@ export class Relations extends EventEmitter {
*
* @return {MatrixEvent?}
*/
getLastReplacement() {
async getLastReplacement() {
if (this.relationType !== "m.replace") {
// Aggregating on last only makes sense for this relation type
return null;
@@ -309,7 +313,7 @@ export class Relations extends EventEmitter {
this._targetEvent.getServerAggregatedRelation("m.replace");
const minTs = replaceRelation && replaceRelation.origin_server_ts;
return this.getRelations().reduce((last, event) => {
const lastReplacement = this.getRelations().reduce((last, event) => {
if (event.getSender() !== this._targetEvent.getSender()) {
return last;
}
@@ -321,18 +325,26 @@ export class Relations extends EventEmitter {
}
return event;
}, null);
if (lastReplacement?.shouldAttemptDecryption()) {
await lastReplacement.attemptDecryption(this._room._client._crypto);
} else if (lastReplacement?.isBeingDecrypted()) {
await lastReplacement._decryptionPromise;
}
return lastReplacement;
}
/*
* @param {MatrixEvent} targetEvent the event the relations are related to.
*/
setTargetEvent(event) {
async setTargetEvent(event) {
if (this._targetEvent) {
return;
}
this._targetEvent = event;
if (this.relationType === "m.replace") {
const replacement = this.getLastReplacement();
const replacement = await this.getLastReplacement();
// this is the initial update, so only call it if we already have something
// to not emit Event.replaced needlessly
if (replacement) {
+7 -3
View File
@@ -55,7 +55,9 @@ export class CallEventHandler {
private evaluateEventBuffer = () => {
if (this.client.getSyncState() === "SYNCING") {
// don't process any events until they are all decrypted
if (this.callEventBuffer.some((e) => e.isBeingDecrypted())) return;
if (this.callEventBuffer.some((e) => {
return e.isBeingDecrypted() || e.shouldAttemptDecryption()
})) return;
const ignoreCallIds = new Set<String>();
// inspect the buffer and mark all calls which have been answered
@@ -87,17 +89,19 @@ export class CallEventHandler {
private onEvent = (event: MatrixEvent) => {
// any call events or ones that might be once they're decrypted
const isBeingDecrypted = event.isBeingDecrypted();
const shouldAttemptDecryption = event.shouldAttemptDecryption();
if (
event.getType().indexOf("m.call.") === 0 ||
event.getType().indexOf("org.matrix.call.") === 0
|| event.isBeingDecrypted()
|| isBeingDecrypted || shouldAttemptDecryption
) {
// queue up for processing once all events from this sync have been
// processed (see above).
this.callEventBuffer.push(event);
}
if (event.isBeingDecrypted() || event.isDecryptionFailure()) {
if (event.isDecryptionFailure() || isBeingDecrypted || shouldAttemptDecryption) {
// add an event listener for once the event is decrypted.
event.once("Event.decrypted", () => {
if (event.getType().indexOf("m.call.") === -1) return;