matrix-js: show local-time verification timestamps via shared formatter

This commit is contained in:
Gustavo Madeira Santana
2026-02-25 15:26:00 -05:00
parent 7a44a6370d
commit 950fd1913f
3 changed files with 94 additions and 3 deletions

View File

@@ -1,4 +1,5 @@
import { Command } from "commander";
import { formatZonedTimestamp } from "openclaw/plugin-sdk";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const bootstrapMatrixVerificationMock = vi.fn();
@@ -19,6 +20,10 @@ function buildProgram(): Command {
return program;
}
function formatExpectedLocalTimestamp(value: string): string {
return formatZonedTimestamp(new Date(value), { displaySeconds: true }) ?? value;
}
describe("matrix-js CLI verification commands", () => {
beforeEach(async () => {
vi.resetModules();
@@ -79,4 +84,65 @@ describe("matrix-js CLI verification commands", () => {
expect(process.exitCode).toBe(0);
});
it("prints local timezone timestamps for verify status output", async () => {
const recoveryCreatedAt = "2026-02-25T20:10:11.000Z";
getMatrixVerificationStatusMock.mockResolvedValue({
verified: true,
userId: "@bot:example.org",
deviceId: "DEVICE123",
backupVersion: "1",
recoveryKeyStored: true,
recoveryKeyCreatedAt: recoveryCreatedAt,
pendingVerifications: 0,
});
const program = buildProgram();
await program.parseAsync(["matrix-js", "verify", "status"], { from: "user" });
expect(console.log).toHaveBeenCalledWith(
`Recovery key created at: ${formatExpectedLocalTimestamp(recoveryCreatedAt)}`,
);
});
it("prints local timezone timestamps for verify bootstrap and device output", async () => {
const recoveryCreatedAt = "2026-02-25T20:10:11.000Z";
const verifiedAt = "2026-02-25T20:14:00.000Z";
bootstrapMatrixVerificationMock.mockResolvedValue({
success: true,
verification: {
verified: true,
userId: "@bot:example.org",
deviceId: "DEVICE123",
recoveryKeyCreatedAt: recoveryCreatedAt,
},
crossSigning: {
published: true,
masterKeyPublished: true,
selfSigningKeyPublished: true,
userSigningKeyPublished: true,
},
pendingVerifications: 0,
cryptoBootstrap: {},
});
verifyMatrixRecoveryKeyMock.mockResolvedValue({
success: true,
userId: "@bot:example.org",
deviceId: "DEVICE123",
backupVersion: "1",
recoveryKeyCreatedAt: recoveryCreatedAt,
verifiedAt,
});
const program = buildProgram();
await program.parseAsync(["matrix-js", "verify", "bootstrap"], { from: "user" });
await program.parseAsync(["matrix-js", "verify", "device", "valid-key"], { from: "user" });
expect(console.log).toHaveBeenCalledWith(
`Recovery key created at: ${formatExpectedLocalTimestamp(recoveryCreatedAt)}`,
);
expect(console.log).toHaveBeenCalledWith(
`Verified at: ${formatExpectedLocalTimestamp(verifiedAt)}`,
);
});
});

View File

@@ -1,4 +1,5 @@
import type { Command } from "commander";
import { formatZonedTimestamp } from "openclaw/plugin-sdk";
import {
bootstrapMatrixVerification,
getMatrixVerificationStatus,
@@ -22,6 +23,24 @@ function markCliFailure(): void {
process.exitCode = 1;
}
function formatLocalTimestamp(value: string | null | undefined): string | null {
if (!value) {
return null;
}
const parsed = new Date(value);
if (!Number.isFinite(parsed.getTime())) {
return value;
}
return formatZonedTimestamp(parsed, { displaySeconds: true }) ?? value;
}
function printTimestamp(label: string, value: string | null | undefined): void {
const formatted = formatLocalTimestamp(value);
if (formatted) {
console.log(`${label}: ${formatted}`);
}
}
function printVerificationStatus(status: {
verified: boolean;
userId: string | null;
@@ -45,9 +64,7 @@ function printVerificationStatus(status: {
console.log("Run 'openclaw matrix-js verify device <key>' to verify this device.");
}
console.log(`Recovery key stored: ${status.recoveryKeyStored ? "yes" : "no"}`);
if (status.recoveryKeyCreatedAt) {
console.log(`Recovery key created at: ${status.recoveryKeyCreatedAt}`);
}
printTimestamp("Recovery key created at", status.recoveryKeyCreatedAt);
console.log(`Pending verifications: ${status.pendingVerifications}`);
}
@@ -126,6 +143,7 @@ export function registerMatrixJsCli(params: { program: Command }): void {
console.log(
`Cross-signing published: ${result.crossSigning.published ? "yes" : "no"} (master=${result.crossSigning.masterKeyPublished ? "yes" : "no"}, self=${result.crossSigning.selfSigningKeyPublished ? "yes" : "no"}, user=${result.crossSigning.userSigningKeyPublished ? "yes" : "no"})`,
);
printTimestamp("Recovery key created at", result.verification.recoveryKeyCreatedAt);
console.log(`Pending verifications: ${result.pendingVerifications}`);
if (!result.success) {
markCliFailure();
@@ -164,6 +182,8 @@ export function registerMatrixJsCli(params: { program: Command }): void {
if (result.backupVersion) {
console.log(`Backup version: ${result.backupVersion}`);
}
printTimestamp("Recovery key created at", result.recoveryKeyCreatedAt);
printTimestamp("Verified at", result.verifiedAt);
} else {
console.error(`Verification failed: ${result.error ?? "unknown error"}`);
markCliFailure();

View File

@@ -244,6 +244,11 @@ export type {
PersistentDedupeOptions,
} from "./persistent-dedupe.js";
export { formatErrorMessage } from "../infra/errors.js";
export {
formatUtcTimestamp,
formatZonedTimestamp,
resolveTimezone,
} from "../infra/format-time/format-datetime.js";
export {
DEFAULT_WEBHOOK_BODY_TIMEOUT_MS,
DEFAULT_WEBHOOK_MAX_BODY_BYTES,