fix(matrix): close owner-side device verification loop on SAS confirm#74542
fix(matrix): close owner-side device verification loop on SAS confirm#74542steipete merged 2 commits intoopenclaw:mainfrom
Conversation
|
Codex review: found issues before merge. What this changes: The PR updates Matrix SAS self-verification confirmation and auto-confirm handling to wait for verifier completion, cross-sign own device/identity paths, add regression tests, and document the fix in the Matrix changelog. Maintainer follow-up before merge: This is an open implementation PR that needs normal maintainer review and a small author-side changelog fix, not a separate automated repair branch. Security review: Security review cleared: The diff changes Matrix self-verification trust flow and tests only; it does not add dependencies, CI execution, permissions, secrets handling, or package-resolution changes, and the new trust calls remain gated to self-verification. Review findings:
Review detailsBest possible solution: Keep the PR open, add the required changelog credit, then review and validate the Matrix self-verification behavior with the targeted Matrix extension tests and, if available, a live self-verification smoke. Full review comments:
Overall correctness: patch is incorrect Acceptance criteria:
What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 68912111cfea. |
After SAS confirm via the `openclaw matrix verify confirm-sas` CLI, the
operator's Element X stayed in "Verifying…" because three things on the
bot side did not happen before the verb returned:
1. confirmVerificationSas didn't await the rust-crypto verifier promise.
`Verifier.verify()` resolves only after both sides exchange MACs and
the protocol fully settles, including cross-signing-key uploads
triggered by `crossSignDevice`. Returning early meant Element X's
next /keys/query saw an inconsistent state and the prompt persisted.
2. The 30s auto-confirm path (used when the operator initiates from
their phone) explicitly passed `{ trustOwnDevice: false }`, so the
bot never cross-signed its own device on this path. The check inside
trustOwnDeviceAfterConfirmedSas already gates on isSelfVerification,
so flipping the flag is safe — non-self requests remain a no-op.
3. The standalone `confirmMatrixVerificationSas` action did not call
`trustOwnIdentityAfterSelfVerification` (only the higher-level
`runMatrixSelfVerification` path did). Without that call, the bot
had not signed the operator's master key, so Element X had no path
to clear the prompt without a passive sync tick.
Three additive edits:
- verification-manager.ts (confirmVerificationSas): await
session.verifyPromise after confirmSasForSession returns.
verifyPromise is the .then().catch() chain set by
ensureVerificationStarted, which already routes rejections into
session.error, so awaiting it cannot double-throw.
- verification-manager.ts (maybeAutoConfirmSas): pass
{ trustOwnDevice: true } so the auto-confirm path also cross-signs
the bot device for self-verifications.
- actions/verification.ts (confirmMatrixVerificationSas): mirror the
trustOwnIdentityAfterSelfVerification call from
completeMatrixSelfVerification when the returned summary indicates
isSelfVerification.
Tests:
- verification-manager.test.ts: flipped the existing "auto-confirmed
self-verification" assertion (now expects trustOwnDeviceAfterSas to
be called); added two new tests for verifyPromise await and
rejection-on-summary.error.
- actions/verification.test.ts: two new tests asserting
confirmMatrixVerificationSas calls trustOwnIdentityAfterSelfVerification
on self-verifications and not on remote verifications.
Verified end-to-end against matrix.thepolycule.ca (Synapse 1.145.0+ess.1,
MAS-fronted): after `verify confirm-sas`, Element X's device-list view
shows the bot device with a green shield and no pending Verify prompt.
2be24f3 to
f65e937
Compare
|
Landed in 86956f7. I kept the contributor fix and added one maintainer-side guard before landing: Local proof on the rebased head:
Thanks @nklock. |
Adds six missing entries for commits that landed without their own CHANGELOG.md update, picked from the last six hours of origin/main and attributed to the original contributors. Changes: - Control UI/i18n locale registry expansion + new docs glossaries (297f4c6, 0126692 by @vincentkoc). - Gateway/diagnostics opt-in startup timeline (097eed8, d001c34, e69da9d by @shakkernerd). Fixes: - Matrix `verify confirm-sas` cross-signing close (86956f7 by @nklock; #74542). - `openclaw status` channel context-window overrides (eb7d89f by @HemantSudarshan). - Sandbox Docker daemon graceful when sandbox mode is off (2dadc82 by @kaseonedge; #73671). - Control UI mobile chat settings persisted via Lit state (b1c5152 by @BunsDev). Skipped Peter-only commits with no external collaborator (per the maintainer-attribution rule against thanking @steipete) and the model list auth-index series (already covered by the existing "Models/UI: hide unauthenticated providers" entry).
…openclaw#74542) * fix(matrix): close owner-side device verification loop on SAS confirm After SAS confirm via the `openclaw matrix verify confirm-sas` CLI, the operator's Element X stayed in "Verifying…" because three things on the bot side did not happen before the verb returned: 1. confirmVerificationSas didn't await the rust-crypto verifier promise. `Verifier.verify()` resolves only after both sides exchange MACs and the protocol fully settles, including cross-signing-key uploads triggered by `crossSignDevice`. Returning early meant Element X's next /keys/query saw an inconsistent state and the prompt persisted. 2. The 30s auto-confirm path (used when the operator initiates from their phone) explicitly passed `{ trustOwnDevice: false }`, so the bot never cross-signed its own device on this path. The check inside trustOwnDeviceAfterConfirmedSas already gates on isSelfVerification, so flipping the flag is safe — non-self requests remain a no-op. 3. The standalone `confirmMatrixVerificationSas` action did not call `trustOwnIdentityAfterSelfVerification` (only the higher-level `runMatrixSelfVerification` path did). Without that call, the bot had not signed the operator's master key, so Element X had no path to clear the prompt without a passive sync tick. Three additive edits: - verification-manager.ts (confirmVerificationSas): await session.verifyPromise after confirmSasForSession returns. verifyPromise is the .then().catch() chain set by ensureVerificationStarted, which already routes rejections into session.error, so awaiting it cannot double-throw. - verification-manager.ts (maybeAutoConfirmSas): pass { trustOwnDevice: true } so the auto-confirm path also cross-signs the bot device for self-verifications. - actions/verification.ts (confirmMatrixVerificationSas): mirror the trustOwnIdentityAfterSelfVerification call from completeMatrixSelfVerification when the returned summary indicates isSelfVerification. Tests: - verification-manager.test.ts: flipped the existing "auto-confirmed self-verification" assertion (now expects trustOwnDeviceAfterSas to be called); added two new tests for verifyPromise await and rejection-on-summary.error. - actions/verification.test.ts: two new tests asserting confirmMatrixVerificationSas calls trustOwnIdentityAfterSelfVerification on self-verifications and not on remote verifications. Verified end-to-end against matrix.thepolycule.ca (Synapse 1.145.0+ess.1, MAS-fronted): after `verify confirm-sas`, Element X's device-list view shows the bot device with a green shield and no pending Verify prompt. * fix(matrix): guard owner trust after failed SAS verification --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
Adds six missing entries for commits that landed without their own CHANGELOG.md update, picked from the last six hours of origin/main and attributed to the original contributors. Changes: - Control UI/i18n locale registry expansion + new docs glossaries (297f4c6, 0126692 by @vincentkoc). - Gateway/diagnostics opt-in startup timeline (097eed8, d001c34, e69da9d by @shakkernerd). Fixes: - Matrix `verify confirm-sas` cross-signing close (86956f7 by @nklock; openclaw#74542). - `openclaw status` channel context-window overrides (eb7d89f by @HemantSudarshan). - Sandbox Docker daemon graceful when sandbox mode is off (2dadc82 by @kaseonedge; openclaw#73671). - Control UI mobile chat settings persisted via Lit state (b1c5152 by @BunsDev). Skipped Peter-only commits with no external collaborator (per the maintainer-attribution rule against thanking @steipete) and the model list auth-index series (already covered by the existing "Models/UI: hide unauthenticated providers" entry).
…openclaw#74542) * fix(matrix): close owner-side device verification loop on SAS confirm After SAS confirm via the `openclaw matrix verify confirm-sas` CLI, the operator's Element X stayed in "Verifying…" because three things on the bot side did not happen before the verb returned: 1. confirmVerificationSas didn't await the rust-crypto verifier promise. `Verifier.verify()` resolves only after both sides exchange MACs and the protocol fully settles, including cross-signing-key uploads triggered by `crossSignDevice`. Returning early meant Element X's next /keys/query saw an inconsistent state and the prompt persisted. 2. The 30s auto-confirm path (used when the operator initiates from their phone) explicitly passed `{ trustOwnDevice: false }`, so the bot never cross-signed its own device on this path. The check inside trustOwnDeviceAfterConfirmedSas already gates on isSelfVerification, so flipping the flag is safe — non-self requests remain a no-op. 3. The standalone `confirmMatrixVerificationSas` action did not call `trustOwnIdentityAfterSelfVerification` (only the higher-level `runMatrixSelfVerification` path did). Without that call, the bot had not signed the operator's master key, so Element X had no path to clear the prompt without a passive sync tick. Three additive edits: - verification-manager.ts (confirmVerificationSas): await session.verifyPromise after confirmSasForSession returns. verifyPromise is the .then().catch() chain set by ensureVerificationStarted, which already routes rejections into session.error, so awaiting it cannot double-throw. - verification-manager.ts (maybeAutoConfirmSas): pass { trustOwnDevice: true } so the auto-confirm path also cross-signs the bot device for self-verifications. - actions/verification.ts (confirmMatrixVerificationSas): mirror the trustOwnIdentityAfterSelfVerification call from completeMatrixSelfVerification when the returned summary indicates isSelfVerification. Tests: - verification-manager.test.ts: flipped the existing "auto-confirmed self-verification" assertion (now expects trustOwnDeviceAfterSas to be called); added two new tests for verifyPromise await and rejection-on-summary.error. - actions/verification.test.ts: two new tests asserting confirmMatrixVerificationSas calls trustOwnIdentityAfterSelfVerification on self-verifications and not on remote verifications. Verified end-to-end against matrix.thepolycule.ca (Synapse 1.145.0+ess.1, MAS-fronted): after `verify confirm-sas`, Element X's device-list view shows the bot device with a green shield and no pending Verify prompt. * fix(matrix): guard owner trust after failed SAS verification --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
Adds six missing entries for commits that landed without their own CHANGELOG.md update, picked from the last six hours of origin/main and attributed to the original contributors. Changes: - Control UI/i18n locale registry expansion + new docs glossaries (3562a87, ffe547a by @vincentkoc). - Gateway/diagnostics opt-in startup timeline (b6df431, e7119aa, ca63cda by @shakkernerd). Fixes: - Matrix `verify confirm-sas` cross-signing close (6dda69a by @nklock; openclaw#74542). - `openclaw status` channel context-window overrides (1b3a248 by @HemantSudarshan). - Sandbox Docker daemon graceful when sandbox mode is off (0336aa2 by @kaseonedge; openclaw#73671). - Control UI mobile chat settings persisted via Lit state (25b2db8 by @BunsDev). Skipped Peter-only commits with no external collaborator (per the maintainer-attribution rule against thanking @steipete) and the model list auth-index series (already covered by the existing "Models/UI: hide unauthenticated providers" entry).
Close owner-side device verification loop on SAS confirm
What this PR does
After running
openclaw matrix verify confirm-sason a self-verification, the operator's Element X stayed in "Verifying…" because three things on the bot side did not happen before the verb returned:confirmVerificationSasdid not await the rust-crypto verifier promise.Verifier.verify()in matrix-js-sdk resolves only after both sides exchange MACs and the protocol fully settles, including the cross-signing-key uploads triggered bycrossSignDevice. Returning early meant the operator's next/keys/querysaw an inconsistent state and the prompt persisted.The 30-second auto-confirm path explicitly skipped device cross-signing. When the operator initiated SAS from their phone (
initiatedByMe === false), the bot's auto-confirm timer fired but calledconfirmSasForSessionwith{ trustOwnDevice: false }. The bot's own device was never cross-signed on this path. The check insidetrustOwnDeviceAfterConfirmedSasalready gates onisSelfVerification, so flipping the flag is safe — non-self requests remain a no-op.The standalone
confirmMatrixVerificationSasaction did not calltrustOwnIdentityAfterSelfVerification. Only the higher-levelrunMatrixSelfVerificationpath called it (atcompleteMatrixSelfVerification). The standalone CLI verb skipped cross-signing the operator's master key from the bot side, so Element X had no path to clear the prompt without a passive sync tick.After this change,
verify confirm-sason a self-verification settles all three before returning, and Element X's device-list view shows the bot device with a green shield with no remaining "Verify" prompt.Changes
extensions/matrix/src/matrix/sdk/verification-manager.tsconfirmVerificationSas(line 725) — afterconfirmSasForSession, awaitsession.verifyPromiseif defined.verifyPromiseis the.then().catch()chain set byensureVerificationStarted, which already routes rejections intosession.error, so awaiting it cannot double-throw.maybeAutoConfirmSas(line 507) — pass{ trustOwnDevice: true }toconfirmSasForSession. The check insidetrustOwnDeviceAfterConfirmedSas(gates onisSelfVerification) keeps non-self verifications unaffected.extensions/matrix/src/matrix/actions/verification.tsconfirmMatrixVerificationSas(line 433) — aftercrypto.confirmVerificationSasresolves, if the returned summary hasisSelfVerification: true, callclient.trustOwnIdentityAfterSelfVerification?.(). Mirrors the pattern already incompleteMatrixSelfVerificationat line 224.Tests
extensions/matrix/src/matrix/sdk/verification-manager.test.ts:trustOwnDeviceAfterSasIS called (was: NOT called).confirmVerificationSas awaits the verifier's verify promise before resolving— uses a deferred verifyPromise to assert the verb blocks until the verifier settles.confirmVerificationSas surfaces a verifier-promise rejection on session.error— asserts a rejectingverify()lands the error insummary.errorrather than throwing.extensions/matrix/src/matrix/actions/verification.test.ts:confirmMatrixVerificationSas calls trustOwnIdentityAfterSelfVerification on a self-verification.confirmMatrixVerificationSas does not call trustOwnIdentityAfterSelfVerification on a non-self verification.pnpm test:extension matrix— 117 test files green; 23 tests inactions/verification.test.ts, 20 inverification-manager.test.ts.What this PR explicitly does not do
generateVerificationQr,scanVerificationQr,confirmVerificationReciprocateQr) but adding CLI surface for them is a separate change. SAS is sufficient for the failure mode addressed here.Verified end-to-end
Confirmed against
matrix.thepolycule.ca(Synapse 1.145.0+ess.1, MAS-fronted). After bootstrap and a SAS round-trip with an Element X session, the bot device shows the green shield in the operator's device list and encrypted DMs decrypt round-trip without UTD warnings.AI-assisted disclosure
This change was authored with AI assistance (Claude). The author reviewed every line, ran
pnpm test:extension matrixlocally, and verified the closure end-to-end against a MAS-fronted Synapse 1.145.0+ess.1 deployment.