fix(matrix): guard startup verification timestamps

This commit is contained in:
Peter Steinberger
2026-05-30 08:38:06 -04:00
parent cf60e83118
commit 0840fea50d
2 changed files with 38 additions and 3 deletions

View File

@@ -1,7 +1,7 @@
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { describe, expect, it, vi } from "vitest";
import { afterEach, describe, expect, it, vi } from "vitest";
import { ensureMatrixStartupVerification } from "./startup-verification.js";
function createTempStateDir(): string {
@@ -80,6 +80,10 @@ function createHarness(params?: {
}
describe("ensureMatrixStartupVerification", () => {
afterEach(() => {
vi.restoreAllMocks();
});
it("skips automatic requests when the device is already verified", async () => {
const tempHome = createTempStateDir();
const harness = createHarness({ verified: true });
@@ -203,6 +207,27 @@ describe("ensureMatrixStartupVerification", () => {
expect(fs.existsSync(createStateFilePath(tempHome))).toBe(true);
});
it("falls back when startup verification nowMs is outside Date range", async () => {
vi.spyOn(Date, "now").mockReturnValue(Date.parse("2026-05-30T12:00:00.000Z"));
const tempHome = createTempStateDir();
const stateFilePath = createStateFilePath(tempHome);
const harness = createHarness();
const result = await ensureMatrixStartupVerification({
client: harness.client as never,
auth: createAuth(),
accountConfig: {},
stateFilePath,
nowMs: 8_640_000_000_000_001,
});
expect(result.kind).toBe("requested");
const state = JSON.parse(fs.readFileSync(stateFilePath, "utf-8")) as {
attemptedAt?: string;
};
expect(state.attemptedAt).toBe("2026-05-30T12:00:00.000Z");
});
it("keeps startup verification failures non-fatal", async () => {
const tempHome = createTempStateDir();
const harness = createHarness({

View File

@@ -1,6 +1,7 @@
import fs from "node:fs/promises";
import path from "node:path";
import { readJsonFileWithFallback, writeJsonFileAtomically } from "openclaw/plugin-sdk/json-store";
import { timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
import type { MatrixConfig } from "../../types.js";
import { resolveMatrixStoragePaths } from "../client/storage.js";
import type { MatrixAuth } from "../client/types.js";
@@ -95,6 +96,14 @@ function resolveRetryAfterMs(params: {
return remaining > 0 ? remaining : undefined;
}
function resolveStartupVerificationTimestamp(nowMs: unknown): string {
return (
timestampMsToIsoString(nowMs) ??
timestampMsToIsoString(Date.now()) ??
"1970-01-01T00:00:00.000Z"
);
}
function shouldHonorCooldown(params: {
state: MatrixStartupVerificationState | null;
verification: MatrixOwnDeviceVerificationStatus;
@@ -189,6 +198,7 @@ export async function ensureMatrixStartupVerification(params: {
);
const cooldownMs = cooldownHours * 60 * 60 * 1000;
const nowMs = params.nowMs ?? Date.now();
const attemptedAt = resolveStartupVerificationTimestamp(nowMs);
const state = await readStartupVerificationState(statePath);
const stateCooldownMs = resolveStateCooldownMs(state, cooldownMs);
if (shouldHonorCooldown({ state, verification, stateCooldownMs, nowMs })) {
@@ -208,7 +218,7 @@ export async function ensureMatrixStartupVerification(params: {
await writeJsonFileAtomically(statePath, {
userId: verification.userId,
deviceId: verification.deviceId,
attemptedAt: new Date(nowMs).toISOString(),
attemptedAt,
outcome: "requested",
requestId: request.id,
transactionId: request.transactionId,
@@ -224,7 +234,7 @@ export async function ensureMatrixStartupVerification(params: {
await writeJsonFileAtomically(statePath, {
userId: verification.userId,
deviceId: verification.deviceId,
attemptedAt: new Date(nowMs).toISOString(),
attemptedAt,
outcome: "failed",
error,
} satisfies MatrixStartupVerificationState).catch(() => {});