Skip to content

fix(web): secure-context-safe UUIDs + HTTPS compose overlay for LAN deployments - #864

Draft
Poytr1 wants to merge 2 commits into
mainfrom
claude/crypto-randomuuid-secure-context-281557
Draft

fix(web): secure-context-safe UUIDs + HTTPS compose overlay for LAN deployments#864
Poytr1 wants to merge 2 commits into
mainfrom
claude/crypto-randomuuid-secure-context-281557

Conversation

@Poytr1

@Poytr1 Poytr1 commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Problem

Browsers expose crypto.randomUUID() only in secure contexts (HTTPS or localhost). A console served over plain HTTP from a LAN host — a stack on a NAS opened by IP is the typical case — crashed on Playground send, cron creation, and the Telegram wizard. The rest of the console was already hardened for insecure contexts (clipboard calls are try/caught, the webhook HMAC snippet degrades to a placeholder); the unguarded randomUUID call sites were the remaining hard failures.

Changes

packages/web: secure-context-safe randomUUID() (lib/random-id.ts)

  • Native crypto.randomUUID when available, otherwise a manual v4 UUID built from crypto.getRandomValues (not secure-context gated), with a Math.random last resort.
  • The fallback emits spec-valid v4 UUIDs because webchat frames validate turnId with z.string().uuid().
  • All six call sites now route through it (PlaygroundProvider ×3, Telegram wizard, AddCronModal, data-context); unit tests cover all three environments.

compose.https.yaml: opt-in TLS overlay for LAN deployments

  • Caddy + its internal CA in front of web / control-plane / relay, one HTTPS port per service (3443/8443/9443), keyed on a single AGENTCONNECT_HTTPS_HOST variable.
  • Overrides the browser-facing PUBLIC_* URLs, CORS origin, and setup-server passthroughs to the HTTPS origins. Daemons are Node processes and keep dialing the plain HTTP/WS ports unchanged.
  • Works with already-published images — no rebuild needed to adopt it.
  • README, compose.env.example, and the agentconnect-setup skill document the flow, including trusting the exported root certificate per device.

Verification

  • Web: full vitest suite passes (1448 tests, including new random-id.test.ts), tsc --noEmit, eslint, prettier, and a production next build all clean.
  • Overlay: docker compose config resolves the merged file with every URL override in place and fails with an actionable message when AGENTCONNECT_HTTPS_HOST is unset; the Caddyfile passes caddy validate.

🤖 Generated with Claude Code

Poytr1 and others added 2 commits August 11, 2026 23:49
Browsers expose crypto.randomUUID only on HTTPS or localhost, so a console
served over plain HTTP from a LAN host (e.g. a NAS reached by IP) crashed on
Playground send, cron creation, and the Telegram wizard. Route every call
through lib/random-id.ts, which falls back to a manual v4 UUID built from
getRandomValues (not secure-context gated) — the fallback must stay a real
UUID because webchat frames validate turnId with z.string().uuid().

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
compose.https.yaml fronts web, control-plane, and relay with Caddy and its
internal CA (one HTTPS port per service, keyed on AGENTCONNECT_HTTPS_HOST) and
rewrites the browser-facing PUBLIC_* URLs and CORS origin to match. Browsers
grant crypto.randomUUID, crypto.subtle, and clipboard access only to secure
contexts, so a console opened from another LAN device needs HTTPS; daemons are
Node processes and keep dialing the plain HTTP/WS ports unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@agentconnect-md-test agentconnect-md-test Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The secure-context UUID helper is well scoped and all six browser call sites now use it. The HTTPS overlay also renders the expected browser-facing Web/API/Relay URLs. However, the overlay currently breaks the normal daemon onboarding path: PUBLIC_CP_URL is also used to generate daemon WebSocket commands, so the generated command dials Caddy's private-CA wss:// endpoint even though the daemon transport has no way to trust that CA by default. The documented root-certificate export command also cannot be run as written because the required host assignment was only scoped to the earlier up invocation.

Verification: git diff --check passed; docker compose config passed with AGENTCONNECT_HTTPS_HOST and confirmed the HTTPS environment values; the unset-host invocation failed as configured. Focused Vitest/typecheck/lint could not be rerun because dependencies are absent and the pinned pnpm download was unavailable from this environment.

sent by review-bot (Codex · gpt-5.6-sol) · open in session

Comment thread compose.https.yaml

control-plane:
environment:
- PUBLIC_CP_URL=https://${AGENTCONNECT_HTTPS_HOST}:${AGENTCONNECT_CP_TLS_PORT:-8443}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Keep daemon onboarding usable with the internal CA. PUBLIC_CP_URL is not browser-only: daemonWsUrl() derives every Add/Regenerate daemon command from it, so this override produces wss://<host>:8443/daemon/ws. The shared ClientTransport supplies no CA option to ws, and the required Node 24 runtime uses bundled roots by default, so trusting Caddy's root in the browser or OS does not make that generated npx ... run command trust it. The daemon therefore reconnects forever in the advertised LAN setup. Please provide a separate plain daemon dial URL, generate/document the required Node CA configuration, or otherwise ensure the generated command can authenticate this endpoint.

Comment thread README.md
```

Open `https://<host>:3443` and trust the generated root certificate once per
device (export it with `docker compose -f compose.yaml -f compose.https.yaml cp

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Carry the required host into the certificate-export command. The preceding AGENTCONNECT_HTTPS_HOST=... assignment applies only to the up process; it is not present for this later docker compose ... cp. Compose interpolates the overlay before running cp and aborts because AGENTCONNECT_HTTPS_HOST is required. Please repeat the assignment here or show a persistent --env-file workflow. The analogous command in compose.https.yaml also needs the overlay file set (and the host value).

@Poytr1
Poytr1 marked this pull request as draft August 11, 2026 15:57
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