From 4e05790695e5bfd48fa3c97a058f19a9ae02fd11 Mon Sep 17 00:00:00 2001 From: Gustavo Madeira Santana Date: Fri, 13 Mar 2026 02:23:40 +0000 Subject: [PATCH] Matrix: scope verification fallback by DM room --- .../matrix/src/matrix/monitor/events.test.ts | 68 +++++++++++++++++++ .../src/matrix/monitor/verification-events.ts | 10 ++- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/extensions/matrix/src/matrix/monitor/events.test.ts b/extensions/matrix/src/matrix/monitor/events.test.ts index 894880abb9c..47a89e17426 100644 --- a/extensions/matrix/src/matrix/monitor/events.test.ts +++ b/extensions/matrix/src/matrix/monitor/events.test.ts @@ -26,6 +26,7 @@ function createHarness(params?: { verifications?: Array<{ id: string; transactionId?: string; + roomId?: string; otherUserId: string; updatedAt?: string; completed?: boolean; @@ -457,6 +458,73 @@ describe("registerMatrixMonitorEvents verification routing", () => { expect(bodies.some((body) => body.includes("SAS decimal: 1111 2222 3333"))).toBe(false); }); + it("prefers the active verification for the current DM when multiple active summaries exist", async () => { + const { sendMessage, roomEventListener } = createHarness({ + joinedMembersByRoom: { + "!dm-current:example.org": ["@alice:example.org", "@bot:example.org"], + }, + verifications: [ + { + id: "verification-other-room", + roomId: "!dm-other:example.org", + transactionId: "$different-flow-other", + otherUserId: "@alice:example.org", + updatedAt: new Date("2026-02-25T21:44:54.000Z").toISOString(), + phaseName: "started", + phase: 3, + pending: true, + sas: { + decimal: [1111, 2222, 3333], + emoji: [ + ["🚀", "Rocket"], + ["🦋", "Butterfly"], + ["📕", "Book"], + ], + }, + }, + { + id: "verification-current-room", + roomId: "!dm-current:example.org", + transactionId: "$different-flow-current", + otherUserId: "@alice:example.org", + updatedAt: new Date("2026-02-25T21:43:54.000Z").toISOString(), + phaseName: "started", + phase: 3, + pending: true, + sas: { + decimal: [6158, 1986, 3513], + emoji: [ + ["🎁", "Gift"], + ["🌍", "Globe"], + ["🐴", "Horse"], + ], + }, + }, + ], + }); + + roomEventListener("!dm-current:example.org", { + event_id: "$start-room-scoped", + sender: "@alice:example.org", + type: "m.key.verification.start", + origin_server_ts: Date.now(), + content: { + "m.relates_to": { event_id: "$req-room-scoped" }, + }, + }); + + await vi.waitFor(() => { + const bodies = (sendMessage.mock.calls as unknown[][]).map((call) => + String((call[1] as { body?: string } | undefined)?.body ?? ""), + ); + expect(bodies.some((body) => body.includes("SAS decimal: 6158 1986 3513"))).toBe(true); + }); + const bodies = (sendMessage.mock.calls as unknown[][]).map((call) => + String((call[1] as { body?: string } | undefined)?.body ?? ""), + ); + expect(bodies.some((body) => body.includes("SAS decimal: 1111 2222 3333"))).toBe(false); + }); + it("does not emit SAS notices for cancelled verification events", async () => { const { sendMessage, roomEventListener } = createHarness({ joinedMembersByRoom: { diff --git a/extensions/matrix/src/matrix/monitor/verification-events.ts b/extensions/matrix/src/matrix/monitor/verification-events.ts index 624fcc4e176..2c5eabcdaed 100644 --- a/extensions/matrix/src/matrix/monitor/verification-events.ts +++ b/extensions/matrix/src/matrix/monitor/verification-events.ts @@ -16,6 +16,7 @@ type MatrixVerificationStage = "request" | "ready" | "start" | "cancel" | "done" type MatrixVerificationSummaryLike = { id: string; transactionId?: string; + roomId?: string; otherUserId: string; updatedAt?: string; completed?: boolean; @@ -223,7 +224,14 @@ async function resolveVerificationSummaryForSignal( const activeByUser = list .filter((entry) => entry.otherUserId === params.senderId && isActiveVerificationSummary(entry)) .sort((a, b) => resolveSummaryRecency(b) - resolveSummaryRecency(a)); - return activeByUser.length === 1 ? (activeByUser[0] ?? null) : null; + const activeInRoom = activeByUser.filter((entry) => { + const roomId = trimMaybeString(entry.roomId); + return roomId === params.roomId; + }); + if (activeInRoom.length > 0) { + return activeInRoom[0] ?? null; + } + return activeByUser[0] ?? null; } async function resolveVerificationSasNoticeForSignal(