diff --git a/extensions/matrix/src/cli.test.ts b/extensions/matrix/src/cli.test.ts index 5c79f519d3b..144e8d8e17d 100644 --- a/extensions/matrix/src/cli.test.ts +++ b/extensions/matrix/src/cli.test.ts @@ -373,17 +373,18 @@ describe("matrix CLI verification commands", () => { roomId: undefined, }); expect(consoleLogMock).toHaveBeenCalledWith("Verification id: self-verify-1"); + expect(consoleLogMock).toHaveBeenCalledWith("Transaction id: txn-1"); expect(consoleLogMock).toHaveBeenCalledWith( "- Accept the verification request in another Matrix client for this account.", ); expect(consoleLogMock).toHaveBeenCalledWith( - "- Then run 'openclaw matrix verify start self-verify-1 --account ops' to start SAS verification.", + "- Then run 'openclaw matrix verify start txn-1 --account ops' to start SAS verification.", ); expect(consoleLogMock).toHaveBeenCalledWith( - "- Run 'openclaw matrix verify sas self-verify-1 --account ops' to display the SAS emoji or decimals.", + "- Run 'openclaw matrix verify sas txn-1 --account ops' to display the SAS emoji or decimals.", ); expect(consoleLogMock).toHaveBeenCalledWith( - "- When the SAS matches, run 'openclaw matrix verify confirm-sas self-verify-1 --account ops'.", + "- When the SAS matches, run 'openclaw matrix verify confirm-sas txn-1 --account ops'.", ); }); @@ -470,6 +471,22 @@ describe("matrix CLI verification commands", () => { ); }); + it("prints stable transaction ids in follow-up commands after accepting verification", async () => { + acceptMatrixVerificationMock.mockResolvedValue( + mockMatrixVerificationSummary({ + id: "verification-1", + transactionId: "txn-stable", + }), + ); + const program = buildProgram(); + + await program.parseAsync(["matrix", "verify", "accept", "verification-1"], { from: "user" }); + + expect(consoleLogMock).toHaveBeenCalledWith( + "- Run 'openclaw matrix verify start txn-stable' to start SAS verification.", + ); + }); + it("confirms, rejects, accepts, starts, and cancels Matrix verification requests", async () => { acceptMatrixVerificationMock.mockResolvedValue(mockMatrixVerificationSummary({ id: "in-1" })); startMatrixVerificationMock.mockResolvedValue(mockMatrixVerificationSummary({ id: "in-1" })); diff --git a/extensions/matrix/src/cli.ts b/extensions/matrix/src/cli.ts index 31ac8371636..537f7085b31 100644 --- a/extensions/matrix/src/cli.ts +++ b/extensions/matrix/src/cli.ts @@ -764,6 +764,10 @@ function printMatrixVerificationSasGuidance(requestId: string, accountId?: strin ]); } +function getMatrixVerificationCommandId(summary: MatrixCliVerificationSummary): string { + return sanitizeMatrixCliText(summary.transactionId ?? summary.id); +} + async function promptMatrixVerificationSasMatch(): Promise { const { createInterface } = await import("node:readline/promises"); const prompt = createInterface({ @@ -1261,7 +1265,10 @@ export function registerMatrixCli(params: { program: Command }): void { onText: (summary) => { printAccountLabel(accountId); printMatrixVerificationSummary(summary); - printMatrixVerificationRequestGuidance(summary.id, accountId); + printMatrixVerificationRequestGuidance( + getMatrixVerificationCommandId(summary), + accountId, + ); }, errorPrefix: "Verification request failed", }); @@ -1280,7 +1287,7 @@ export function registerMatrixCli(params: { program: Command }): void { run: async (accountId, cfg) => await acceptMatrixVerification(id, { accountId, cfg }), afterText: (summary, accountId) => { printGuidance([ - `Run '${formatMatrixCliCommand(`verify start ${summary.id}`, accountId)}' to start SAS verification.`, + `Run '${formatMatrixCliCommand(`verify start ${getMatrixVerificationCommandId(summary)}`, accountId)}' to start SAS verification.`, ]); }, errorPrefix: "Verification accept failed", @@ -1299,7 +1306,7 @@ export function registerMatrixCli(params: { program: Command }): void { run: async (accountId, cfg) => await startMatrixVerification(id, { accountId, cfg, method: "sas" }), afterText: (summary, accountId) => - printMatrixVerificationSasGuidance(summary.id, accountId), + printMatrixVerificationSasGuidance(getMatrixVerificationCommandId(summary), accountId), errorPrefix: "Verification start failed", }); }); diff --git a/extensions/matrix/src/matrix/actions/verification.test.ts b/extensions/matrix/src/matrix/actions/verification.test.ts index a3d6ba1f597..e94a8e56fbd 100644 --- a/extensions/matrix/src/matrix/actions/verification.test.ts +++ b/extensions/matrix/src/matrix/actions/verification.test.ts @@ -420,6 +420,54 @@ describe("matrix verification actions", () => { expect(crypto.startVerification).not.toHaveBeenCalled(); }); + it("allows completed self-verification when only backup health remains degraded", async () => { + const requested = { + completed: false, + hasSas: false, + id: "verification-1", + phaseName: "requested", + transactionId: "tx-self", + }; + const sas = { + ...requested, + hasSas: true, + phaseName: "started", + sas: { + decimal: [1, 2, 3], + }, + }; + const completed = { + ...sas, + completed: true, + phaseName: "done", + }; + const crypto = { + confirmVerificationSas: vi.fn(async () => completed), + listVerifications: vi.fn(async () => [sas]), + requestVerification: vi.fn(async () => requested), + startVerification: vi.fn(async () => sas), + }; + const bootstrapOwnDeviceVerification = vi.fn(async () => ({ + success: false, + error: "Matrix room key backup is not trusted by this device", + verification: mockVerifiedOwnerStatus(), + })); + withStartedActionClientMock.mockImplementation(async (_opts, run) => { + return await run({ + bootstrapOwnDeviceVerification, + crypto, + getOwnDeviceVerificationStatus: vi.fn(async () => mockVerifiedOwnerStatus()), + }); + }); + + await expect( + runMatrixSelfVerification({ confirmSas: vi.fn(async () => true), timeoutMs: 500 }), + ).resolves.toMatchObject({ + completed: true, + deviceOwnerVerified: true, + }); + }); + it("fails self-verification if SAS completes but full identity trust cannot be established", async () => { const requested = { completed: false, diff --git a/extensions/matrix/src/matrix/actions/verification.ts b/extensions/matrix/src/matrix/actions/verification.ts index 7b05d9a13dc..575b84d63bb 100644 --- a/extensions/matrix/src/matrix/actions/verification.ts +++ b/extensions/matrix/src/matrix/actions/verification.ts @@ -239,7 +239,7 @@ export async function runMatrixSelfVerification( allowAutomaticCrossSigningReset: false, verifyOwnIdentity: true, }); - if (!bootstrap.success) { + if (!bootstrap.verification.verified) { throw new Error( `Matrix self-verification completed, but full Matrix identity trust is still incomplete: ${ bootstrap.error ?? formatMatrixOwnerVerificationDiagnostics(bootstrap.verification)