Skip to content

fix(lib): stop depending on a secure-context API for ids - #1283

Open
joepio wants to merge 1 commit into
developfrom
fix/random-uuid-insecure-context
Open

fix(lib): stop depending on a secure-context API for ids#1283
joepio wants to merge 1 commit into
developfrom
fix/random-uuid-insecure-context

Conversation

@joepio

@joepio joepio commented Aug 18, 2026

Copy link
Copy Markdown
Member

crypto.randomUUID is gated on a secure context, so over plain HTTP it is undefined on anything but localhost — which is exactly how a self-hosted server on a LAN gets reached (http://homeassistant.local, http://192.168.1.x).

DrivePresenceManager's constructor called it bare:

// browser/lib/src/presence.ts
this.sessionId = crypto.randomUUID();

and that runs on every drive load. So the app did not degrade a feature — it threw before first paint and rendered "Error loading resource". This is the Home Assistant add-on needing HTTPS or hard-crashing.

What was there

The data-browser entrypoint carried a global window.crypto.randomUUID = ... patch to paper over it. That works, but it hides the constraint from every future caller and puts a monkey-patch in the app's first statement.

What changed

An explicit randomUUID() in @tomic/lib — real crypto.randomUUID when it exists, getRandomValues otherwise. getRandomValues carries no secure-context gate, so the fallback is as random as the real thing; only the convenience wrapper is absent.

All fifteen call sites migrated, so nothing relies on the patch that is now gone.

Two had already grown their own guards, which suggests this had bitten before — and both fallbacks were worse than they look:

Site Old fallback Problem
client-db.ts tab id Math.random().toString(36) neither a UUID nor cryptographically random; collides for tabs opened in the same millisecond
OpenRouterLoginButton randomString(32) it is a PKCE verifier

Testing

random-uuid.test.ts stubs an insecure context where crypto.randomUUID is absent — the case the whole thing exists for, and one that cannot be observed on localhost. Plus v4 shape and a collision check.

  • lib 283, data-browser 591, svelte 3 — pass
  • workspace lint exit 0 (the polyfill was also the one file failing oxfmt)
  • typecheck clean

Checklist

  • Add or update tests if needed
  • Update docs if needed

Note

Medium Risk
Touches core init paths (presence, client-db tab RPC) and auth (OpenRouter PKCE); behavior change is intentional and low blast radius outside HTTP/insecure contexts, but incorrect UUID generation would affect session/tab identity.

Overview
Fixes first-paint crashes on plain HTTP (e.g. LAN self-host) where crypto.randomUUID is missing because it is secure-context-only. DrivePresenceManager called it on every drive load, which surfaced as “Error loading resource” instead of a degraded feature.

Adds an explicit randomUUID() in @tomic/lib: native crypto.randomUUID when present, otherwise RFC 4122 v4 via crypto.getRandomValues. It is exported from the package and wired through @tomic/react.

Replaces the data-browser entrypoint window.crypto.randomUUID polyfill and migrates ~15 call sites (AI context IDs, MCP config, canvas branches, device IDs, OpenRouter PKCE verifier, ClientDbWorker tab IDs, etc.). Ad-hoc fallbacks (Math.random() tab ids, non-UUID PKCE verifiers) go away in favor of one helper.

Adds random-uuid.test.ts for v4 shape, insecure-context stubbing, and collision checks.

Reviewed by Cursor Bugbot for commit bdecf66. Bugbot is set up for automated code reviews on this repo. Configure here.

`crypto.randomUUID` is gated on a secure context, so over plain HTTP it
is undefined on anything but localhost — which is exactly how a
self-hosted server on a LAN gets reached (`http://homeassistant.local`,
`http://192.168.1.x`). `DrivePresenceManager`'s constructor called it
bare, and that runs on every drive load, so the app did not degrade a
feature: it threw before first paint and rendered "Error loading
resource". That is the Home Assistant add-on needing HTTPS or hard-
crashing.

The data-browser entrypoint had been carrying a global
`window.crypto.randomUUID = ...` patch to paper over this. A polyfill
hides the constraint from every future caller and put a monkey-patch in
the app's first statement, so replace it with an explicit `randomUUID()`
in `@tomic/lib`: `crypto.randomUUID` when it exists, `getRandomValues`
otherwise. `getRandomValues` carries no secure-context gate, so the
fallback is as random as the real thing — only the convenience wrapper
is missing.

Migrated all fifteen call sites so nothing relies on the patch that is
now gone. Two had already grown their own guards, which is a sign this
had bitten before: `client-db.ts` fell back to
`Math.random().toString(36)` for its tab id — neither a UUID nor
cryptographically random, and colliding for tabs opened in the same
millisecond — and `OpenRouterLoginButton` fell back to `randomString(32)`
for a PKCE verifier.

Tested against a stubbed insecure context where `crypto.randomUUID` is
absent, since that is the case the whole thing exists for and it cannot
be observed on localhost.
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