From 1f8fb93ba2d91c67f4b10fdc1877e67e794e2439 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 7 Mar 2023 23:38:04 +0530 Subject: [PATCH] Implement timeout and cancel --- src/matrix/verification/CrossSigning.ts | 1 + .../verification/SAS/SASVerification.ts | 39 +++++++++++-------- .../verification/SAS/channel/Channel.ts | 17 ++++++-- .../SAS/stages/CalculateSASStage.ts | 3 +- .../SAS/stages/RequestVerificationStage.ts | 1 - .../SAS/stages/SendAcceptVerificationStage.ts | 5 ++- 6 files changed, 41 insertions(+), 25 deletions(-) diff --git a/src/matrix/verification/CrossSigning.ts b/src/matrix/verification/CrossSigning.ts index 40b90585..2e4ebd26 100644 --- a/src/matrix/verification/CrossSigning.ts +++ b/src/matrix/verification/CrossSigning.ts @@ -166,6 +166,7 @@ export class CrossSigning { e2eeAccount: this.e2eeAccount, deviceTracker: this.deviceTracker, hsApi: this.hsApi, + platform: this.platform, }); return this.sasVerificationInProgress; } diff --git a/src/matrix/verification/SAS/SASVerification.ts b/src/matrix/verification/SAS/SASVerification.ts index 6f6f67b9..cab57283 100644 --- a/src/matrix/verification/SAS/SASVerification.ts +++ b/src/matrix/verification/SAS/SASVerification.ts @@ -21,10 +21,12 @@ import type {DeviceTracker} from "../../e2ee/DeviceTracker.js"; import type * as OlmNamespace from "@matrix-org/olm"; import {IChannel} from "./channel/Channel"; import {HomeServerApi} from "../../net/HomeServerApi"; -import {VerificationEventTypes} from "./channel/types"; +import {CancelTypes, VerificationEventTypes} from "./channel/types"; import {SendReadyStage} from "./stages/SendReadyStage"; import {SelectVerificationMethodStage} from "./stages/SelectVerificationMethodStage"; import {VerificationCancelledError} from "./VerificationCancelledError"; +import {Timeout} from "../../../platform/types/types"; +import {Platform} from "../../../platform/web/Platform.js"; type Olm = typeof OlmNamespace; @@ -38,6 +40,7 @@ type Options = { e2eeAccount: Account; deviceTracker: DeviceTracker; hsApi: HomeServerApi; + platform: Platform; } export class SASVerification { @@ -45,29 +48,30 @@ export class SASVerification { private olmSas: Olm.SAS; public finished: boolean = false; public readonly channel: IChannel; + private readonly timeout: Timeout; constructor(options: Options) { - const { ourUser, otherUserId, log, olmUtil, olm, channel, e2eeAccount, deviceTracker, hsApi } = options; + const { olm, channel, platform } = options; const olmSas = new olm.SAS(); this.olmSas = olmSas; this.channel = channel; - try { - const options = { ourUser, otherUserId, log, olmSas, olmUtil, channel, e2eeAccount, deviceTracker, hsApi}; - let stage: BaseSASVerificationStage; - if (channel.receivedMessages.get(VerificationEventTypes.Start)) { - stage = new SelectVerificationMethodStage(options); - } - else if (channel.receivedMessages.get(VerificationEventTypes.Request)) { - stage = new SendReadyStage(options); - } - else { - stage = new RequestVerificationStage(options); - } - this.startStage = stage; - console.log("startStage", this.startStage); + this.timeout = platform.clock.createTimeout(10 * 60 * 1000); + this.timeout.elapsed().then(() => { + // Cancel verification after 10 minutes + // todo: catch error here? + channel.cancelVerification(CancelTypes.TimedOut); + }); + const stageOptions = {...options, olmSas}; + if (channel.receivedMessages.get(VerificationEventTypes.Start)) { + this.startStage = new SelectVerificationMethodStage(stageOptions); } - finally { + else if (channel.receivedMessages.get(VerificationEventTypes.Request)) { + this.startStage = new SendReadyStage(stageOptions); } + else { + this.startStage = new RequestVerificationStage(stageOptions); + } + console.log("startStage", this.startStage); } async start() { @@ -88,6 +92,7 @@ export class SASVerification { finally { this.olmSas.free(); this.finished = true; + this.timeout.abort(); } } } diff --git a/src/matrix/verification/SAS/channel/Channel.ts b/src/matrix/verification/SAS/channel/Channel.ts index 24c1b6fb..239b265d 100644 --- a/src/matrix/verification/SAS/channel/Channel.ts +++ b/src/matrix/verification/SAS/channel/Channel.ts @@ -96,8 +96,7 @@ export class ToDeviceChannel extends Disposables implements IChannel { this.platform = options.platform; this.log = options.log; this.deviceMessageHandler = options.deviceMessageHandler; - // todo: find a way to dispose this subscription - this.track(this.deviceMessageHandler.disposableOn("message", ({ unencrypted }) => this.handleDeviceMessage(unencrypted))); + this.track(this.deviceMessageHandler.disposableOn("message", async ({ unencrypted }) => await this.handleDeviceMessage(unencrypted))); this.track(() => { this.waitMap.forEach((value) => { value.reject(new VerificationCancelledError()); }); }); @@ -169,8 +168,18 @@ export class ToDeviceChannel extends Disposables implements IChannel { } - private handleDeviceMessage(event) { - this.log.wrap("ToDeviceChannel.handleDeviceMessage", (log) => { + private async handleDeviceMessage(event) { + await this.log.wrap("ToDeviceChannel.handleDeviceMessage", async (log) => { + if (event.content.transaction_id !== this.id) { + /** + * When a device receives an unknown transaction_id, it should send an appropriate + * m.key.verification.cancel message to the other device indicating as such. + * This does not apply for inbound m.key.verification.start or m.key.verification.cancel messages. + */ + console.log("Received event with unknown transaction id: ", event); + await this.cancelVerification(CancelTypes.UnknownTransaction); + return; + } console.log("event", event); log.set("event", event); this.resolveAnyWaits(event); diff --git a/src/matrix/verification/SAS/stages/CalculateSASStage.ts b/src/matrix/verification/SAS/stages/CalculateSASStage.ts index cea4d297..4fd3ed57 100644 --- a/src/matrix/verification/SAS/stages/CalculateSASStage.ts +++ b/src/matrix/verification/SAS/stages/CalculateSASStage.ts @@ -140,9 +140,10 @@ export class CalculateSASStage extends BaseSASVerificationStage { return sasBytes; } - emojiMatch(match: boolean) { + async emojiMatch(match: boolean) { if (!match) { // cancel the verification + await this.channel.cancelVerification(CancelTypes.MismatchedSAS); } } diff --git a/src/matrix/verification/SAS/stages/RequestVerificationStage.ts b/src/matrix/verification/SAS/stages/RequestVerificationStage.ts index a5e4c6de..3b273fd8 100644 --- a/src/matrix/verification/SAS/stages/RequestVerificationStage.ts +++ b/src/matrix/verification/SAS/stages/RequestVerificationStage.ts @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ import {BaseSASVerificationStage} from "./BaseSASVerificationStage"; -// import {FragmentBoundaryEntry} from "../../../room/timeline/entries/FragmentBoundaryEntry.js"; import {SelectVerificationMethodStage} from "./SelectVerificationMethodStage"; import {VerificationEventTypes} from "../channel/types"; diff --git a/src/matrix/verification/SAS/stages/SendAcceptVerificationStage.ts b/src/matrix/verification/SAS/stages/SendAcceptVerificationStage.ts index 9c7c86be..b9112bbc 100644 --- a/src/matrix/verification/SAS/stages/SendAcceptVerificationStage.ts +++ b/src/matrix/verification/SAS/stages/SendAcceptVerificationStage.ts @@ -16,7 +16,7 @@ limitations under the License. import {BaseSASVerificationStage} from "./BaseSASVerificationStage"; import anotherjson from "another-json"; import {HASHES_LIST, MAC_LIST, SAS_SET, KEY_AGREEMENT_LIST} from "./constants"; -import {VerificationEventTypes} from "../channel/types"; +import {CancelTypes, VerificationEventTypes} from "../channel/types"; import {SendKeyStage} from "./SendKeyStage"; export class SendAcceptVerificationStage extends BaseSASVerificationStage { @@ -29,7 +29,8 @@ export class SendAcceptVerificationStage extends BaseSASVerificationStage { const sasMethods = intersection(content.short_authentication_string, SAS_SET); if (!(keyAgreement !== undefined && hashMethod !== undefined && macMethod !== undefined && sasMethods.length)) { // todo: ensure this cancels the verification - throw new Error("Descriptive error here!"); + await this.channel.cancelVerification(CancelTypes.UnknownMethod); + return; } const ourPubKey = this.olmSAS.get_pubkey(); const commitmentStr = ourPubKey + anotherjson.stringify(content);