mirror of https://github.com/openclaw/openclaw.git
Matrix: retry SAS notice after verification start
This commit is contained in:
parent
a1604a668a
commit
8fd04a9075
|
|
@ -241,6 +241,68 @@ describe("registerMatrixMonitorEvents verification routing", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("retries SAS notice lookup when start arrives before SAS payload is available", async () => {
|
||||
vi.useFakeTimers();
|
||||
const verifications: Array<{
|
||||
id: string;
|
||||
transactionId?: string;
|
||||
otherUserId: string;
|
||||
updatedAt?: string;
|
||||
sas?: {
|
||||
decimal?: [number, number, number];
|
||||
emoji?: Array<[string, string]>;
|
||||
};
|
||||
}> = [
|
||||
{
|
||||
id: "verification-race",
|
||||
transactionId: "$req-race",
|
||||
updatedAt: new Date("2026-02-25T21:42:54.000Z").toISOString(),
|
||||
otherUserId: "@alice:example.org",
|
||||
},
|
||||
];
|
||||
const { sendMessage, roomEventListener } = createHarness({
|
||||
joinedMembersByRoom: {
|
||||
"!dm:example.org": ["@alice:example.org", "@bot:example.org"],
|
||||
},
|
||||
verifications,
|
||||
});
|
||||
|
||||
try {
|
||||
roomEventListener("!dm:example.org", {
|
||||
event_id: "$start-race",
|
||||
sender: "@alice:example.org",
|
||||
type: "m.key.verification.start",
|
||||
origin_server_ts: Date.now(),
|
||||
content: {
|
||||
"m.relates_to": { event_id: "$req-race" },
|
||||
},
|
||||
});
|
||||
|
||||
await vi.advanceTimersByTimeAsync(500);
|
||||
verifications[0] = {
|
||||
...verifications[0]!,
|
||||
sas: {
|
||||
decimal: [1234, 5678, 9012],
|
||||
emoji: [
|
||||
["🚀", "Rocket"],
|
||||
["🦋", "Butterfly"],
|
||||
["📕", "Book"],
|
||||
],
|
||||
},
|
||||
};
|
||||
await vi.advanceTimersByTimeAsync(500);
|
||||
|
||||
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 emoji:"))).toBe(true);
|
||||
});
|
||||
} finally {
|
||||
vi.useRealTimers();
|
||||
}
|
||||
});
|
||||
|
||||
it("ignores verification notices in unrelated non-DM rooms", async () => {
|
||||
const { sendMessage, roomEventListener } = createHarness({
|
||||
joinedMembersByRoom: {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import {
|
|||
} from "./verification-utils.js";
|
||||
|
||||
const MAX_TRACKED_VERIFICATION_EVENTS = 1024;
|
||||
const SAS_NOTICE_RETRY_DELAY_MS = 750;
|
||||
|
||||
type MatrixVerificationStage = "request" | "ready" | "start" | "cancel" | "done" | "other";
|
||||
|
||||
|
|
@ -225,6 +226,37 @@ async function resolveVerificationSummaryForSignal(
|
|||
return activeByUser.length === 1 ? (activeByUser[0] ?? null) : null;
|
||||
}
|
||||
|
||||
async function resolveVerificationSasNoticeForSignal(
|
||||
client: MatrixClient,
|
||||
params: {
|
||||
roomId: string;
|
||||
event: MatrixRawEvent;
|
||||
senderId: string;
|
||||
flowId: string | null;
|
||||
stage: MatrixVerificationStage;
|
||||
},
|
||||
): Promise<{ summary: MatrixVerificationSummaryLike | null; sasNotice: string | null }> {
|
||||
const summary = await resolveVerificationSummaryForSignal(client, params);
|
||||
const immediateNotice =
|
||||
summary && isActiveVerificationSummary(summary) ? formatVerificationSasNotice(summary) : null;
|
||||
if (immediateNotice || (params.stage !== "ready" && params.stage !== "start")) {
|
||||
return {
|
||||
summary,
|
||||
sasNotice: immediateNotice,
|
||||
};
|
||||
}
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, SAS_NOTICE_RETRY_DELAY_MS));
|
||||
const retriedSummary = await resolveVerificationSummaryForSignal(client, params);
|
||||
return {
|
||||
summary: retriedSummary,
|
||||
sasNotice:
|
||||
retriedSummary && isActiveVerificationSummary(retriedSummary)
|
||||
? formatVerificationSasNotice(retriedSummary)
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
function trackBounded(set: Set<string>, value: string): boolean {
|
||||
if (!value || set.has(value)) {
|
||||
return false;
|
||||
|
|
@ -298,16 +330,13 @@ export function createMatrixVerificationEventRouter(params: {
|
|||
}
|
||||
|
||||
const stageNotice = formatVerificationStageNotice({ stage: signal.stage, senderId, event });
|
||||
const summary = await resolveVerificationSummaryForSignal(params.client, {
|
||||
const { summary, sasNotice } = await resolveVerificationSasNoticeForSignal(params.client, {
|
||||
roomId,
|
||||
event,
|
||||
senderId,
|
||||
flowId,
|
||||
}).catch(() => null);
|
||||
const sasNotice =
|
||||
summary && isActiveVerificationSummary(summary)
|
||||
? formatVerificationSasNotice(summary)
|
||||
: null;
|
||||
stage: signal.stage,
|
||||
}).catch(() => ({ summary: null, sasNotice: null }));
|
||||
|
||||
const notices: string[] = [];
|
||||
if (stageNotice) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue