fix(webv2): work without crypto.randomUUID and crypto.subtle in insecure contexts - #212
Open
lstein wants to merge 2 commits into
Open
fix(webv2): work without crypto.randomUUID and crypto.subtle in insecure contexts#212lstein wants to merge 2 commits into
lstein wants to merge 2 commits into
Conversation
`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
lstein
requested review from
JPPhoto,
Pfannkuchensack and
blessedcoolant
as code owners
September 5, 2026 04:10
joshistoast
enabled auto-merge
September 5, 2026 04:52
joshistoast
reviewed
Sep 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.randomUUIDorcrypto.subtle. The durable persistence layer from #210 mints a writer token withcrypto.randomUUID()during startup, so the app crashed before first paint withcrypto.randomUUID is not a function. Once past that, the first paint-cache flush or canvas composite would have thrown oncrypto.subtle.digest.@platform/browser/randomUuid—createUuid()uses the native generator when present and otherwise assembles a v4 UUID fromcrypto.getRandomValues, which has no secure-context restriction. All twelve production call sites now go through it.@platform/browser/sha256—sha256()/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.src/architecture/secureContextApis.test.ts(wired intoarchitecture:check) fails CI on any directrandomUUIDorcrypto.subtlereference outside the two helpers and test files.Verification
pnpm lint(format, oxlint, tsc, architecture) andpnpm test(520 files / 7532 tests) pass.isSecureContext === false,crypto.randomUUIDandcrypto.subtleundefined): the app now boots cleanly there.Not in this PR
navigator.locksis also secure-context-only; the existingwebLockshelper already reports it asunavailableand 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