fix: generateId() fallback for insecure-context origins
Problem The phone-preview path (http://192.168.1.167:5173) is a non-secure origin. `window.crypto.randomUUID` is gated behind secure contexts (HTTPS / localhost / 127.0.0.1 / file://) so it's undefined there, and every optimistic-id call site crashed handleAdd with `TypeError: crypto.randomUUID is not a function`. Fix apps/web/src/lib/utils/id.ts — generateId() uses crypto.randomUUID() when available, otherwise falls back to crypto.getRandomValues() + RFC 4122 §4.4 byte assembly. getRandomValues IS exposed on insecure contexts (unlike subtle), so the fallback is v4-compliant and cryptographically acceptable for client-side optimistic ids. Replaced crypto.randomUUID() at every call site: stores/lists.ts, stores/tasks.ts, sync/queue.ts, sync/undoQueue.ts routes/(app)/lists/[id]/+page.svelte routes/(app)/tasks/[id]/+page.svelte CLAUDE.md gotcha added: never call crypto.randomUUID() directly — always import generateId from $lib/utils/id. Tests (written first, confirmed failing on main) src/lib/utils/id.test.ts (4 tests) U-01 returns UUID v4 when randomUUID is available U-02 falls back when randomUUID is undefined U-03 50 fallback-generated ids are all unique U-04 prefers randomUUID when present (doesn't drop into fallback) tests/e2e/insecure-context.test.ts (1 test) INS-01 stubs crypto.randomUUID = undefined via addInitScript, drives the add-item flow, confirms the row renders (if the old call site were still there, handleAdd would throw). Verification just test-all → exit 0, 233 green, 2 skipped: 34 pgTAP (unchanged) 140 Vitest integration + 2 skipped presence (unchanged) 15 Vitest unit (was 11, +4 generateId) 44 Playwright (was 43, +1 INS-01) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
### Fase 5 — Rediseño UX Mobile ("Monolith Editorial")
|
||||
**Estado: ✅ Completa en scope automatizable. 228 tests verdes (34 pgTAP + 140 integration + 11 unit + 43 Playwright), 4 skipped. Diferido: M-series swipe gesture tests (WebKit install), SEL mobile long-press tests, card presence avatars, `max-w-2xl` reading-width.**
|
||||
**Estado: ✅ Completa en scope automatizable. 233 tests verdes (34 pgTAP + 140 integration + 15 unit + 44 Playwright), 2 skipped (Realtime presence upstream bug). Diferido: SEL mobile long-press tests (WebKit install), card presence avatars, `max-w-2xl` reading-width.**
|
||||
**Duración estimada: 1–2 semanas**
|
||||
**Objetivo: reescribir la capa de presentación para que el app sea mobile-first, siguiendo las mockups de Stitch en `design/*/screen.png` y la dirección "Monolith Editorial" de `design/slate_collective/DESIGN.md`.**
|
||||
|
||||
@@ -442,13 +442,28 @@ Doble tap corto (≤ 300 ms entre toques) en una fila (en modo normal) abre un o
|
||||
|
||||
---
|
||||
|
||||
#### 5.13 Resistencia a contextos no-seguros (HTTP LAN)
|
||||
|
||||
**Problema descubierto tras deploy de la preview mobile:** el usuario abrió `http://192.168.1.167:5173` en el móvil (origen no-seguro) y `handleAdd` lanzó `TypeError: crypto.randomUUID is not a function`. `crypto.randomUUID` solo está expuesto en HTTPS, localhost, 127.0.0.1 o file:// — fuera de eso queda `undefined`.
|
||||
|
||||
**Cambios:**
|
||||
|
||||
- [x] Nuevo helper `apps/web/src/lib/utils/id.ts` — `generateId()` usa `crypto.randomUUID()` cuando está disponible; cae en `crypto.getRandomValues()` + ensamblado RFC 4122 §4.4 cuando no (la API de bytes aleatorios SÍ está en contextos inseguros).
|
||||
- [x] Sustituidos todos los call sites: `stores/lists.ts`, `stores/tasks.ts`, `sync/queue.ts`, `sync/undoQueue.ts`, `lists/[id]/+page.svelte`, `tasks/[id]/+page.svelte`.
|
||||
- [x] Regla del repo (añadida a CLAUDE.md): nadie llama `crypto.randomUUID()` directamente — siempre `generateId()`.
|
||||
|
||||
**Tests:**
|
||||
|
||||
- [x] `src/lib/utils/id.test.ts` — U-01 devuelve UUID v4; U-02 fallback cuando `randomUUID` es `undefined`; U-03 50 IDs únicos bajo fallback; U-04 prefiere `randomUUID` cuando existe.
|
||||
- [x] `tests/e2e/insecure-context.test.ts` — INS-01: `addInitScript` anula `randomUUID`, `loginAs`, añadir ítem, verificar que no crashea y el row aparece.
|
||||
|
||||
#### 5.Z Verificación final — todos los tests verdes
|
||||
|
||||
- [x] `just test-all` → **228 verdes, 4 skipped**:
|
||||
- [x] `just test-all` → **233 verdes, 2 skipped**:
|
||||
- 34 pgTAP (sin cambios)
|
||||
- 140 Vitest integration + 2 skipped presence (sin cambios)
|
||||
- 11 Vitest unit (sin cambios)
|
||||
- 43 Playwright + 2 skipped swipe-touch (was 39, +1 mobile-shell M-08, +3 selection SEL-01/02/03; D-03 y D-04 reescritos para el nuevo overlay)
|
||||
- 15 Vitest unit (was 11, +4 generateId)
|
||||
- 44 Playwright (was 43, +1 INS-01)
|
||||
- [ ] Validación visual en DevTools iPhone 13 (390×844) + Pixel 7 (412×915) + Desktop (1280×800) — pendiente (manual, post-deploy).
|
||||
- [x] `loginAs(USERS.borja)` con `page.setViewportSize(MOBILE)` activa el shell mobile automáticamente (verificado en M-01..M-04).
|
||||
- [x] Seis commits incrementales (5.10.0 → 5.12 → 5.8 → 5.10 → 5.11) para facilitar revert o review por pasos.
|
||||
|
||||
Reference in New Issue
Block a user