Skip to content

fix: guard crypto.randomUUID for insecure origins (toast store, message-id, contact uid) - #888

Open
texchi2 wants to merge 2 commits into
bulwarkmail:mainfrom
texchi2:fix/insecure-origin-randomuuid
Open

fix: guard crypto.randomUUID for insecure origins (toast store, message-id, contact uid)#888
texchi2 wants to merge 2 commits into
bulwarkmail:mainfrom
texchi2:fix/insecure-origin-randomuuid

Conversation

@texchi2

@texchi2 texchi2 commented Aug 22, 2026

Copy link
Copy Markdown

Fixes #887 (calendar Save reports failure while the event is created; duplicates on retry) and the same-class silent compose-Send failure.

Root cause

crypto.randomUUID is [SecureContext]-gated — on a plain-http LAN origin (a common self-hosted pilot deployment) it is undefined, and three call sites called it unguarded:

  • stores/toast-store.ts addToast() — every toast.success/toast.error threw TypeError: crypto.randomUUID is not a function. In handleSaveEvent the success toast runs before the dialog-close, so a successful CalendarEvent/set was followed by a throw; the catch's toast.error threw again uncaught; the dialog stayed open reporting failure while the server had the event, and user retries created duplicates.
  • lib/jmap/client.ts generateMessageId() — compose Send failed silently after the draft save, before EmailSubmission was ever issued (drafts piled up).
  • lib/jmap/client.ts createContact uid fallback — contact creation without a uid crashed pre-request.

Fix

All three now use the guarded generateUUID() already in lib/utils.ts (typeof-check, falling back to a v4 UUID built from crypto.getRandomValues, which insecure contexts do provide).

Verification

Headless-Chromium reproduction on an insecure origin (isSecureContext === false), logged into a real JMAP server (Stalwart 0.16):

  • Pre-fix: one Save click → uncaught TypeError at Object.addToast (via toast.error), dialog stays open, server has exactly 1 new event.
  • Post-fix: same click → dialog closes, "Event created" toast renders, no page errors, server has exactly 1 new event.
  • Compose Send on-device (iPhone/iPad PWA over LAN http): confirmed sending after the generateMessageId guard.

Not touched, flagged for a follow-up: unguarded crypto.subtle.digest in lib/oauth/pkce.ts and lib/plugin-sandbox/bundle-integrity.ts (same class, separate feature paths), and navigator.clipboard absence on insecure origins in the copy-link paths (try/caught; degrades gracefully once toasts work).

🤖 Generated with Claude Code

https://claude.ai/code/session_01MtFkcUA8VM2XAKZKzptpqy

texchi2 and others added 2 commits August 22, 2026 18:09
… undefined) — use guarded generateUUID(); send failed after draft save, before EmailSubmission
…ined), breaking every post-action acknowledgement

addToast() minted toast ids with crypto.randomUUID(), which only exists in
secure contexts (https/localhost). On a plain-http LAN origin every
toast.success/toast.error threw a TypeError, so e.g. calendar event Save
crashed AFTER a successful CalendarEvent/set — before the dialog-close ran —
leaving the dialog open reporting failure while the server had the event;
retries created duplicates. Same class as the generateMessageId send bug.

Also guards the same-class contact uid fallback in lib/jmap/client.ts
(createContact). Both now use the guarded generateUUID() from lib/utils.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MtFkcUA8VM2XAKZKzptpqy
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.

Create-event dialog reports failure although CalendarEvent/set succeeds (Stalwart 0.16.18) — duplicates on retry

1 participant