diff --git a/.changeset/clever-hounds-brake.md b/.changeset/clever-hounds-brake.md new file mode 100644 index 000000000..a3634467d --- /dev/null +++ b/.changeset/clever-hounds-brake.md @@ -0,0 +1,20 @@ +--- +'@object-ui/console': patch +--- + +Console: restore `crypto.randomUUID` on insecure origins so list views stop crashing on LAN IPs + +`crypto.randomUUID` is exposed only in secure contexts (HTTPS or +`http://localhost`). Reaching a dev box over plain HTTP from another machine — +`http://192.168.x.x:4001/_console/`, the ordinary second-device flow — left the +method undefined, and every unguarded caller threw +`TypeError: crypto.randomUUID is not a function`, taking the console's list +views into the ErrorBoundary. + +The console's HTML entry now installs an RFC 4122 v4 fallback built on +`crypto.getRandomValues` (which is not secure-context-gated, so the entropy +stays cryptographic). It runs as an inline classic script, synchronously during +parse, so it precedes every bundled chunk. It is guarded on absence and never +replaces a native implementation, so secure origins are unaffected; with no +entropy source available it installs nothing rather than degrading to +`Math.random`. diff --git a/apps/console/index.html b/apps/console/index.html index 9d5037c90..4337b6796 100644 --- a/apps/console/index.html +++ b/apps/console/index.html @@ -46,6 +46,78 @@ + +
diff --git a/apps/console/src/__tests__/insecure-origin-crypto.placement.test.ts b/apps/console/src/__tests__/insecure-origin-crypto.placement.test.ts new file mode 100644 index 000000000..25d5d62a4 --- /dev/null +++ b/apps/console/src/__tests__/insecure-origin-crypto.placement.test.ts @@ -0,0 +1,92 @@ +/** + * objectui#4563 — the shim's PLACEMENT is the fix, not just its code. + * + * A `crypto.randomUUID` fallback that runs after a consumer has already called + * the missing method fixes nothing, so what this file defends is ORDER. + * + * The guarantee relied upon is that a CLASSIC inline script executes + * synchronously during parse, before any module script and therefore before any + * bundled chunk. The weaker guarantee — document order between two + * `type="module"` scripts — was tried first and MEASURED to fail: Vite merges + * multiple HTML module entries into one chunk, whose static imports are hoisted + * above the merged body, so 16 chunks (`vendor-react`, `ui-components` and + * `RecordDetailView` among them) evaluated before the shim installed. Document + * order is real in the browser but it does not survive bundling. + * + * Hence the assertions below: the shim must stay a classic inline script, and + * it must stay ahead of every script that carries a `src`. + */ +// Read through Vite's `?raw` rather than `node:fs`: this app's tsconfig is +// browser-only (`lib: ES2020, DOM`, and `types` without `node`), so a +// `node:fs`/`node:path` import fails `tsc` in the console's build even while +// the test itself passes under Vitest. +import html from '../../index.html?raw'; +import { describe, it, expect } from 'vitest'; + +const SHIM_MARKER = 'installInsecureOriginRandomUuid'; +const APP_ENTRY = '/src/main.tsx'; + +/** + * Every `