Skip to content

fix(webv2): work without crypto.randomUUID and crypto.subtle in insecure contexts - #212

Open
lstein wants to merge 2 commits into
mainfrom
fix/webv2-uuid-insecure-context
Open

fix(webv2): work without crypto.randomUUID and crypto.subtle in insecure contexts#212
lstein wants to merge 2 commits into
mainfrom
fix/webv2-uuid-insecure-context

Conversation

@lstein

@lstein lstein commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

Opening webv2 over plain HTTP from another device on the LAN (an iPad pointed at a workstation, for example) is an insecure context, where browsers do not expose crypto.randomUUID or crypto.subtle. The durable persistence layer from #210 mints a writer token with crypto.randomUUID() during startup, so the app crashed before first paint with crypto.randomUUID is not a function. Once past that, the first paint-cache flush or canvas composite would have thrown on crypto.subtle.digest.

  • @platform/browser/randomUuidcreateUuid() uses the native generator when present and otherwise assembles a v4 UUID from crypto.getRandomValues, which has no secure-context restriction. All twelve production call sites now go through it.
  • @platform/browser/sha256sha256() / sha256Hex() use Web Crypto when present and otherwise a pure-JavaScript SHA-256 that is byte-identical to the native digest (tested against it across the padding boundaries and the published vectors). The paint cache, composite-for-generation, and deterministic project id sites now go through it, so hash-derived ids stay stable regardless of which path computed them.
  • Architecture guardsrc/architecture/secureContextApis.test.ts (wired into architecture:check) fails CI on any direct randomUUID or crypto.subtle reference outside the two helpers and test files.
  • Performance baselines re-recorded for the two new bundled source files.

Verification

  • pnpm lint (format, oxlint, tsc, architecture) and pnpm test (520 files / 7532 tests) pass.
  • Both performance gates pass in check mode after re-recording.
  • Reproduced the insecure context in headless Chromium by loading the dev server via the LAN IP (isSecureContext === false, crypto.randomUUID and crypto.subtle undefined): the app now boots cleanly there.
  • Confirmed on the reporting iPad (Chrome/WebKit) that the startup crash is gone.

Not in this PR

navigator.locks is also secure-context-only; the existing webLocks helper already reports it as unavailable and callers tolerate that, so no change was needed. A separate "Queue recovery storage is unavailable" banner seen on the iPad is unrelated to secure contexts (it does not reproduce in an insecure-context Chromium); it is what the app shows when the workbench IndexedDB cannot be opened, e.g. when another tab still holds an older database version open.

🤖 Generated with Claude Code

https://claude.ai/code/session_019JTauFL2fzFopMq8VmQiE7

lstein and others added 2 commits September 4, 2026 23:52
`crypto.randomUUID` is only exposed in secure contexts (HTTPS or
localhost), so opening the app over plain HTTP from another device on
the LAN — an iPad pointed at a workstation, for example — left the
property undefined. The durable persistence layer introduced in #210
mints a writer token during startup, which turned that into a crash
before first paint: "crypto.randomUUID is not a function".

Add `createUuid` in `@platform/browser/randomUuid`, which uses the
native generator when present and otherwise assembles a v4 UUID from
`crypto.getRandomValues`, and route every production call site through
it. An architecture test now rejects any direct `randomUUID` reference
outside the helper so the crash cannot creep back in.

Re-record the architecture and browser performance baselines for the
new bundled source file.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019JTauFL2fzFopMq8VmQiE7
`crypto.subtle` is gated behind secure contexts exactly like
`crypto.randomUUID`, so after the UUID fix the same LAN-over-HTTP
session still threw on the first paint-cache flush, composite for
generation, or deterministic project id.

Add `@platform/browser/sha256` with a pure-JavaScript SHA-256 that is
byte-identical to the Web Crypto digest (verified against it across the
padding boundaries), route the three digest sites through it, and widen
the secure-context architecture test to reject direct `crypto.subtle`
use. Re-record the performance baselines for the new source file.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019JTauFL2fzFopMq8VmQiE7

@joshistoast joshistoast left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

There's a lot of unnecessary code narration on the sha256 and randomuuid files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants