Skip to content

fix(desktop): canonicalize mesh connect-request #p target before signing#835

Closed
tlongwell-block wants to merge 1 commit into
mainfrom
eva/mesh-connect-ptag-hardening
Closed

fix(desktop): canonicalize mesh connect-request #p target before signing#835
tlongwell-block wants to merge 1 commit into
mainfrom
eva/mesh-connect-ptag-hardening

Conversation

@tlongwell-block

Copy link
Copy Markdown
Collaborator

What

Canonicalize the mesh connect-request (kind:24621) #p target at the single signing boundary, and stop the e2e mock relay from masking a missing-#p regression.

Why

Starting a mesh-powered agent can fail with the relay error:

Mesh client failed to start: invalid: mesh connect request missing #p target

Today publishMeshConnectRequest signs ["p", input.targetPubkey] verbatim from discovery. A non-canonical value (uppercase, surrounding whitespace, or an npub1…) would be signed as-is and then mishandled downstream. We harden the boundary so the desktop always emits a canonical ["p", <64-hex>] tag — or fails locally with a clear invalid pubkey error — instead of producing an event the relay rejects opaquely.

Changes

  • pubkey.ts — new canonicalPubkeyOrThrow(value): accepts hex (any case, padded) or npub1…, returns canonical 64-char lowercase hex, throws a clear error otherwise. Reuses the already-present nostr-tools/nip19 decoder.
  • relayMeshSignaling.tspublishMeshConnectRequest runs the target through canonicalPubkeyOrThrow before signing.
  • e2eBridge.ts — the mock relay now rejects a 24621 with no #p tag (mirroring the real relay) instead of blindly ACKing it, so the missing-#p shape is actually exercised.
  • pubkey.test.mjs — 9 cases: hex passthrough, uppercase, whitespace, npub→hex, and the throw paths (empty / short / garbage / malformed npub).

Verification

  • pnpm test (full desktop suite): 479/479 pass
  • tsc --noEmit: clean
  • biome check: clean
  • All pre-commit hooks (rust-fmt, desktop/web/mobile) green

Scope / honesty

This is defense-in-depth + test-harness hardening, not a confirmed fix for a specific reported "missing #p" error. That exact error requires a genuinely tagless 24621, which no current source emits — investigation (Eva + Max) points to a stale desktop build as the likely cause of the live report, pending build-SHA confirmation. This PR makes the class of failure impossible-by-construction and adds the missing regression coverage regardless of that root cause.

The relay rejects a kind:24621 connect request whose target is unusable
with "mesh connect request missing #p target". Today the desktop signs
`["p", input.targetPubkey]` verbatim from discovery; a non-canonical
value (uppercase, whitespace, or an npub) would be signed as-is.

Harden the single signing boundary in publishMeshConnectRequest with a
new canonicalPubkeyOrThrow() that accepts hex (any case, padded) or
npub1…, returns canonical 64-char lowercase hex, and throws a clear
local error otherwise — instead of emitting an event the relay rejects
opaquely. Also make the e2e mock relay reject a tagless 24621 rather
than blindly ACK it, so the missing-#p shape is covered in tests.

Defense-in-depth + test-harness hardening. NOT a confirmed fix for a
specific reported "missing #p" — that error requires a genuinely
tagless 24621, which no current source emits; root cause there is most
likely a stale desktop build (pending build-SHA confirmation).

Signed-off-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@sprout-oss.stage.blox.sqprod.co>
@tlongwell-block tlongwell-block requested a review from a team as a code owner June 3, 2026 19:19
@tlongwell-block

Copy link
Copy Markdown
Collaborator Author

Closing in favor of #834 (Max's) — we both built this in parallel (my fault for not locking the lane). His is the better diff: a real e2e Playwright test that captures the signed 24621 and asserts the #p tag end-to-end, vs my unit tests on an extracted helper. His normalizePubkey (trim+lowercase+64-hex) is also correctly scoped — the reporterPubkey from discovery is always hex, so my npub-decoding path was speculative dead code. #834 it is.

@tlongwell-block tlongwell-block deleted the eva/mesh-connect-ptag-hardening branch June 3, 2026 19:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant