This commit is contained in:
Bruno Windels
2019-12-10 17:51:34 +01:00
parent cd7cc1b71f
commit b34a2c7ee2
3 changed files with 52 additions and 13 deletions
+4 -1
View File
@@ -1550,6 +1550,7 @@ Crypto.prototype._requestVerificationWithChannel = async function(
} else {
map.set(name, method);
}
return map;
}, new Map());
}
const request = new VerificationRequest(
@@ -2469,6 +2470,8 @@ Crypto.prototype._onKeyVerificationMessage = function(event) {
* @param {module:models/event.MatrixEvent} event the timeline event
*/
Crypto.prototype._onTimelineEvent = function(event) {
// TODO: we still need a request object for past requests, so we can show it in the timeline
// validation now excludes old requests
if (!InRoomChannel.validateEvent(event, this._baseApis)) {
return;
}
@@ -2503,7 +2506,6 @@ Crypto.prototype._handleVerificationEvent = async function(
if (!request) {
return;
}
event.setVerificationRequest(request);
isNewRequest = true;
if (!requestsByTxnId) {
requestsByTxnId = new Map();
@@ -2511,6 +2513,7 @@ Crypto.prototype._handleVerificationEvent = async function(
}
requestsByTxnId.set(transactionId, request);
}
event.setVerificationRequest(request);
try {
const hadVerifier = !!request.verifier;
await request.channel.handleEvent(event, request);
@@ -46,6 +46,10 @@ export default class InRoomChannel {
return true;
}
get roomId() {
return this._roomId;
}
/** The transaction id generated/used by this verification channel */
get transactionId() {
return this._requestEventId;
@@ -96,17 +100,20 @@ export default class InRoomChannel {
static validateEvent(event, client) {
const txnId = InRoomChannel.getTransactionId(event);
if (typeof txnId !== "string" || txnId.length === 0) {
console.log("InRoomChannel: validateEvent: no valid txnId", type, txnId);
return false;
}
const type = InRoomChannel.getEventType(event);
const content = event.getContent();
if (type === REQUEST_TYPE) {
if (typeof content.to !== "string" || !content.to.length) {
if (!content || typeof content.to !== "string" || !content.to.length) {
console.log("InRoomChannel: validateEvent: no valid to", type, content.to);
return false;
}
const ownUserId = client.getUserId();
// ignore requests that are not direct to or sent by the syncing user
if (event.getSender() !== ownUserId && content.to !== ownUserId) {
console.log("InRoomChannel: validateEvent: not directed or sent my me", type, event.getSender(), content.to);
return false;
}
}
@@ -66,9 +66,12 @@ export default class VerificationRequest extends EventEmitter {
this._commonMethods = [];
this._setPhase(PHASE_UNSENT, false);
this._requestEvent = null;
// TODO: this can also be ourselves, we need to fish .to out of content on a .request
this._otherUserId = userId;
this._initiatedByMe = null;
this._startTimestamp = null;
this._cancellingUserId = null;
this._readyEvent = null;
}
/**
@@ -83,12 +86,18 @@ export default class VerificationRequest extends EventEmitter {
static validateEvent(type, event, timestamp, client) {
const content = event.getContent();
if (!content) {
console.log("VerificationRequest: validateEvent: no content", type);
}
if (!type.startsWith(EVENT_PREFIX)) {
console.log("VerificationRequest: validateEvent: fail because type doesnt start with " + EVENT_PREFIX, type);
return false;
}
if (type === REQUEST_TYPE || type === READY_TYPE) {
if (!Array.isArray(content.methods)) {
console.log("VerificationRequest: validateEvent: fail because methods", type);
return false;
}
}
@@ -97,6 +106,7 @@ export default class VerificationRequest extends EventEmitter {
if (typeof content.from_device !== "string" ||
content.from_device.length === 0
) {
console.log("VerificationRequest: validateEvent: fail because from_device", type);
return false;
}
}
@@ -106,7 +116,9 @@ export default class VerificationRequest extends EventEmitter {
const elapsed = Date.now() - timestamp;
// ignore if event is too far in the past or too far in the future
if (elapsed > (VERIFICATION_REQUEST_TIMEOUT - VERIFICATION_REQUEST_MARGIN) ||
elapsed < -(VERIFICATION_REQUEST_TIMEOUT / 2)) {
elapsed < -(VERIFICATION_REQUEST_TIMEOUT / 2)
) {
console.log("VerificationRequest: validateEvent: verification event to far in future or past", type, elapsed);
logger.log("received verification that is too old or from the future");
return false;
}
@@ -199,6 +211,14 @@ export default class VerificationRequest extends EventEmitter {
}
}
/**
* the id of the user that cancelled the request,
* only defined when phase is PHASE_CANCELLED
*/
get cancellingUserId() {
return this._cancellingUserId;
}
/* Start the key verification, creating a verifier and sending a .start event.
* If no previous events have been sent, pass in `targetDevice` to set who to direct this request to.
* @param {string} method the name of the verification method to use.
@@ -249,6 +269,7 @@ export default class VerificationRequest extends EventEmitter {
if (this._verifier) {
return this._verifier.cancel(errorFactory(code, reason));
} else {
this._cancellingUserId = this._client.getUserId();
this._setPhase(PHASE_CANCELLED, false);
await this.channel.send(CANCEL_TYPE, {code, reason});
}
@@ -262,8 +283,8 @@ export default class VerificationRequest extends EventEmitter {
*/
async accept() {
if (this.phase === PHASE_REQUESTED && !this.initiatedByMe) {
const methods = [...this._verificationMethods.keys()];
this._setPhase(PHASE_READY, false);
const methods = [...this._verificationMethods.keys()];
await this.channel.send(READY_TYPE, {methods});
this.emit("change");
}
@@ -322,7 +343,7 @@ export default class VerificationRequest extends EventEmitter {
if (type === REQUEST_TYPE) {
await this._handleRequest(content, event);
} else if (type === READY_TYPE) {
await this._handleReady(content);
await this._handleReady(event);
} else if (type === START_TYPE) {
await this._handleStart(content, event);
}
@@ -335,7 +356,7 @@ export default class VerificationRequest extends EventEmitter {
}
if (type === CANCEL_TYPE) {
this._handleCancel();
this._handleCancel(event);
} else if (type === DONE_TYPE) {
this._handleDone();
}
@@ -349,19 +370,22 @@ export default class VerificationRequest extends EventEmitter {
this._initiatedByMe = this._wasSentByMe(event);
this._setPhase(PHASE_REQUESTED);
} else if (this._phase !== PHASE_REQUESTED) {
logger.warn("Ignoring flagged verification request from " +
logger.warn("Cancelling, unexpected .request verification event from " +
event.getSender());
await this.cancel(errorFromEvent(newUnexpectedMessageError()));
}
}
async _handleReady(content) {
if (this._phase === PHASE_REQUESTED) {
async _handleReady(event) {
const content = event.getContent();
console.log("handling ready event", content, this._phase);
if (this.phase === PHASE_REQUESTED || this.phase === PHASE_READY) {
this._readyEvent = event;
const otherMethods = content.methods;
this._commonMethods = this._filterMethods(otherMethods);
this._setPhase(PHASE_READY);
} else {
logger.warn("Ignoring flagged verification ready event from " +
logger.warn("Cancelling, unexpected .ready verification event from " +
event.getSender());
await this.cancel(errorFromEvent(newUnexpectedMessageError()));
}
@@ -385,7 +409,9 @@ export default class VerificationRequest extends EventEmitter {
if (this.phase === PHASE_UNSENT) {
this._initiatedByMe = this._wasSentByMe(event);
}
this._verifier = this._createVerifier(method, event);
if (!this._verifier) {
this._verifier = this._createVerifier(method, event);
}
this._setPhase(PHASE_STARTED);
}
}
@@ -409,8 +435,9 @@ export default class VerificationRequest extends EventEmitter {
}
}
_handleCancel() {
_handleCancel(event = null) {
if (this._phase !== PHASE_CANCELLED) {
this._cancellingUserId = event ? event.getSender() : this._client.getUserId();
this._setPhase(PHASE_CANCELLED);
}
}
@@ -450,6 +477,8 @@ export default class VerificationRequest extends EventEmitter {
let targetEvent;
if (startEvent && !this._wasSentByMe(startEvent)) {
targetEvent = startEvent;
} else if (this._readyEvent && !this._wasSentByMe(this._readyEvent)) {
targetEvent = this._readyEvent;
} else if (this._requestEvent && !this._wasSentByMe(this._requestEvent)) {
targetEvent = this._requestEvent;
} else {
@@ -468,7 +497,7 @@ export default class VerificationRequest extends EventEmitter {
return methodNames.filter(m => this._verificationMethods.has(m));
}
// only for .request and .start
// only for .request, .ready or .start
_wasSentByMe(event) {
if (event.getSender() !== this._client.getUserId()) {
return false;