mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-30 03:56:45 +00:00
Matrix: delay inbound SAS auto-confirm
This commit is contained in:
@@ -165,7 +165,7 @@ describe("MatrixVerificationManager", () => {
|
||||
expect(sas.emoji?.length).toBe(3);
|
||||
|
||||
await manager.confirmVerificationSas(tracked.id);
|
||||
expect(confirm).toHaveBeenCalledTimes(2);
|
||||
expect(confirm).toHaveBeenCalledTimes(1);
|
||||
|
||||
manager.mismatchVerificationSas(tracked.id);
|
||||
expect(mismatch).toHaveBeenCalledTimes(1);
|
||||
@@ -256,7 +256,8 @@ describe("MatrixVerificationManager", () => {
|
||||
expect(manager.getVerificationSas(tracked.id).decimal).toEqual([1234, 5678, 9012]);
|
||||
});
|
||||
|
||||
it("auto-confirms inbound SAS when callbacks are available", async () => {
|
||||
it("auto-confirms inbound SAS after a short delay", async () => {
|
||||
vi.useFakeTimers();
|
||||
const confirm = vi.fn(async () => {});
|
||||
const verifier = new MockVerifier(
|
||||
{
|
||||
@@ -280,12 +281,18 @@ describe("MatrixVerificationManager", () => {
|
||||
initiatedByMe: false,
|
||||
verifier,
|
||||
});
|
||||
const manager = new MatrixVerificationManager();
|
||||
manager.trackVerificationRequest(request);
|
||||
try {
|
||||
const manager = new MatrixVerificationManager();
|
||||
manager.trackVerificationRequest(request);
|
||||
|
||||
await vi.waitFor(() => {
|
||||
await vi.advanceTimersByTimeAsync(1000);
|
||||
expect(confirm).not.toHaveBeenCalled();
|
||||
|
||||
await vi.advanceTimersByTimeAsync(600);
|
||||
expect(confirm).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
} finally {
|
||||
vi.useRealTimers();
|
||||
}
|
||||
});
|
||||
|
||||
it("does not auto-confirm SAS for verifications initiated by this device", async () => {
|
||||
@@ -324,6 +331,46 @@ describe("MatrixVerificationManager", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("cancels a pending auto-confirm when SAS is explicitly mismatched", async () => {
|
||||
vi.useFakeTimers();
|
||||
const confirm = vi.fn(async () => {});
|
||||
const mismatch = vi.fn();
|
||||
const verifier = new MockVerifier(
|
||||
{
|
||||
sas: {
|
||||
decimal: [444, 555, 666],
|
||||
emoji: [
|
||||
["panda", "Panda"],
|
||||
["rocket", "Rocket"],
|
||||
["crown", "Crown"],
|
||||
],
|
||||
},
|
||||
confirm,
|
||||
mismatch,
|
||||
cancel: vi.fn(),
|
||||
},
|
||||
null,
|
||||
async () => {},
|
||||
);
|
||||
const request = new MockVerificationRequest({
|
||||
transactionId: "txn-mismatch-cancels-auto-confirm",
|
||||
initiatedByMe: false,
|
||||
verifier,
|
||||
});
|
||||
try {
|
||||
const manager = new MatrixVerificationManager();
|
||||
const tracked = manager.trackVerificationRequest(request);
|
||||
|
||||
manager.mismatchVerificationSas(tracked.id);
|
||||
await vi.advanceTimersByTimeAsync(2000);
|
||||
|
||||
expect(mismatch).toHaveBeenCalledTimes(1);
|
||||
expect(confirm).not.toHaveBeenCalled();
|
||||
} finally {
|
||||
vi.useRealTimers();
|
||||
}
|
||||
});
|
||||
|
||||
it("prunes stale terminal sessions during list operations", () => {
|
||||
const now = new Date("2026-02-08T15:00:00.000Z").getTime();
|
||||
const nowSpy = vi.spyOn(Date, "now");
|
||||
|
||||
@@ -102,12 +102,14 @@ type MatrixVerificationSession = {
|
||||
verifyStarted: boolean;
|
||||
startRequested: boolean;
|
||||
sasAutoConfirmStarted: boolean;
|
||||
sasAutoConfirmTimer?: ReturnType<typeof setTimeout>;
|
||||
sasCallbacks?: MatrixShowSasCallbacks;
|
||||
reciprocateQrCallbacks?: MatrixShowQrCodeCallbacks;
|
||||
};
|
||||
|
||||
const MAX_TRACKED_VERIFICATION_SESSIONS = 256;
|
||||
const TERMINAL_SESSION_RETENTION_MS = 24 * 60 * 60 * 1000;
|
||||
const SAS_AUTO_CONFIRM_DELAY_MS = 1500;
|
||||
|
||||
export class MatrixVerificationManager {
|
||||
private readonly verificationSessions = new Map<string, MatrixVerificationSession>();
|
||||
@@ -175,6 +177,14 @@ export class MatrixVerificationManager {
|
||||
session.updatedAtMs = Date.now();
|
||||
}
|
||||
|
||||
private clearSasAutoConfirmTimer(session: MatrixVerificationSession): void {
|
||||
if (!session.sasAutoConfirmTimer) {
|
||||
return;
|
||||
}
|
||||
clearTimeout(session.sasAutoConfirmTimer);
|
||||
session.sasAutoConfirmTimer = undefined;
|
||||
}
|
||||
|
||||
private buildVerificationSummary(session: MatrixVerificationSession): MatrixVerificationSummary {
|
||||
const request = session.request;
|
||||
const phase = this.readRequestValue(request, () => request.phase, VerificationPhase.Requested);
|
||||
@@ -329,6 +339,7 @@ export class MatrixVerificationManager {
|
||||
this.touchVerificationSession(session);
|
||||
});
|
||||
verifier.on(VerifierEvent.Cancel, (err) => {
|
||||
this.clearSasAutoConfirmTimer(session);
|
||||
session.error = err instanceof Error ? err.message : String(err);
|
||||
this.touchVerificationSession(session);
|
||||
});
|
||||
@@ -336,7 +347,7 @@ export class MatrixVerificationManager {
|
||||
}
|
||||
|
||||
private maybeAutoConfirmSas(session: MatrixVerificationSession): void {
|
||||
if (session.sasAutoConfirmStarted) {
|
||||
if (session.sasAutoConfirmStarted || session.sasAutoConfirmTimer) {
|
||||
return;
|
||||
}
|
||||
if (this.readRequestValue(session.request, () => session.request.initiatedByMe, true)) {
|
||||
@@ -347,16 +358,29 @@ export class MatrixVerificationManager {
|
||||
return;
|
||||
}
|
||||
session.sasCallbacks = callbacks;
|
||||
session.sasAutoConfirmStarted = true;
|
||||
void callbacks
|
||||
.confirm()
|
||||
.then(() => {
|
||||
this.touchVerificationSession(session);
|
||||
})
|
||||
.catch((err) => {
|
||||
session.error = err instanceof Error ? err.message : String(err);
|
||||
this.touchVerificationSession(session);
|
||||
});
|
||||
// Give the remote client a moment to surface the compare-emoji UI before
|
||||
// we send our MAC and finish our side of the SAS flow.
|
||||
session.sasAutoConfirmTimer = setTimeout(() => {
|
||||
session.sasAutoConfirmTimer = undefined;
|
||||
const phase = this.readRequestValue(
|
||||
session.request,
|
||||
() => session.request.phase,
|
||||
VerificationPhase.Requested,
|
||||
);
|
||||
if (phase >= VerificationPhase.Cancelled) {
|
||||
return;
|
||||
}
|
||||
session.sasAutoConfirmStarted = true;
|
||||
void callbacks
|
||||
.confirm()
|
||||
.then(() => {
|
||||
this.touchVerificationSession(session);
|
||||
})
|
||||
.catch((err) => {
|
||||
session.error = err instanceof Error ? err.message : String(err);
|
||||
this.touchVerificationSession(session);
|
||||
});
|
||||
}, SAS_AUTO_CONFIRM_DELAY_MS);
|
||||
}
|
||||
|
||||
private ensureVerificationStarted(session: MatrixVerificationSession): void {
|
||||
@@ -535,7 +559,9 @@ export class MatrixVerificationManager {
|
||||
if (!callbacks) {
|
||||
throw new Error("Matrix SAS confirmation is not available for this verification request");
|
||||
}
|
||||
this.clearSasAutoConfirmTimer(session);
|
||||
session.sasCallbacks = callbacks;
|
||||
session.sasAutoConfirmStarted = true;
|
||||
await callbacks.confirm();
|
||||
this.touchVerificationSession(session);
|
||||
return this.buildVerificationSummary(session);
|
||||
@@ -547,6 +573,7 @@ export class MatrixVerificationManager {
|
||||
if (!callbacks) {
|
||||
throw new Error("Matrix SAS mismatch is not available for this verification request");
|
||||
}
|
||||
this.clearSasAutoConfirmTimer(session);
|
||||
session.sasCallbacks = callbacks;
|
||||
callbacks.mismatch();
|
||||
this.touchVerificationSession(session);
|
||||
|
||||
Reference in New Issue
Block a user