Skip to content

feat: web UX overhaul — paste creation UI, browser viewing pipeline, homepage polish#129

Merged
anoncam merged 7 commits into
mainfrom
feat/web-ux-overhaul
Jun 10, 2026
Merged

feat: web UX overhaul — paste creation UI, browser viewing pipeline, homepage polish#129
anoncam merged 7 commits into
mainfrom
feat/web-ux-overhaul

Conversation

@anoncam

@anoncam anoncam commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Summary

Comprehensive UX overhaul of the worker hosting paste.d3d.dev. All new browser experiences are gated on Accept: text/html, so CLI/curl/API behavior is byte-for-byte unchanged.

Homepage (src/muiStyles.ts)

  • Restores the paste-creation UI (the previous redesign deleted the markup but left ~200 lines of orphaned JS that crashed on load, leaving browser users with no way to create pastes). New centerpiece card: Share Text / Upload File tabs, drag-and-drop with visual feedback, one-time checkboxes, client-side 25 MB validation, result panel with clipboard-first URL copy — wired to the existing /api/text and /api/upload endpoints.
  • CSS-only feature-card hovers (replacing inline onmouseover handlers) honoring prefers-reduced-motion
  • Font loading via preconnect + link instead of render-blocking @import
  • Open Graph / Twitter meta tags; clamp() responsive typography; terminal-window hero demo of the CLI
  • Footer corrected to Version 1.24.8 • © 2026

Browser viewing pipeline (src/index.ts, new src/viewerTemplates.ts)

  • Syntax-highlighted viewer for all text-like pastes (text/*, JSON, XML, JS): line numbers, filename/type/size header, Copy All / View Raw / Download actions; ?raw=true&download=true forces attachment
  • Encrypted-paste landing page: /e/<id> in a browser now shows a copy-able dedpaste get <url> command and install hint instead of raw ciphertext JSON
  • One-time paste interstitial: browser GETs no longer consume — a confirmation page requires an explicit reveal click (the reveal fetch consumes via the existing flow). This also stops Slack/iMessage link-preview bots from burning one-time pastes before the recipient opens them
  • Styled 404/error pages for browsers (plain text preserved for CLI)
  • Markdown viewer: title-based header, clipboard-API-first copying; markdown rendering now also Accept-gated so curl of a .md paste returns raw source
  • Removed the 600-line dead commented-out Tailwind homepage block
  • R2 metadata no longer stores literal "undefined" strings

Security hardening (post-review fixes)

  • sanitizeHtml now strips svg/math foreign-content tags, style attributes, and unquoted javascript:/vbscript:/data: URLs
  • Viewer memory buffering capped at 1 MB (was 5 MB)
  • Homepage no longer sets a wildcard Access-Control-Allow-Origin

Test plan

  • npm run build clean; prettier clean
  • Test suite: 21 passing / 2 failing — the 2 failures are pre-existing on main (CLI crypto tests, unrelated)
  • Live integration matrix against wrangler dev (15/15): browser viewer, raw curl bytes, one-time interstitial → reveal → destroyed, second-GET-not-consumed, encrypted landing vs raw JSON, markdown both lenses, styled vs plain 404, download disposition, homepage form, sanitizer XSS probes (svg/script, unquoted javascript: href, style attr)
  • Node-fetch with default headers (Accept: */*, what the CLI sends) receives exact raw bytes

Known items deliberately deferred

  • Cross-isolate one-time double-serve race (pre-existing; needs R2 conditional writes or a Durable Object lock)
  • Nonce-based CSP to drop 'unsafe-inline' scripts (template-wide refactor)
  • Pre-existing CLI bug discovered during testing: dedpaste get <url> rejects current paste URLs because its regex requires 8-char IDs (cli/index.ts:1633,1639) while the server issues 16-char IDs

anoncam added 7 commits June 10, 2026 10:00
…ding, one-time interstitial

- Universal paste viewer: browsers (Accept: text/html) get a styled,
  server-side syntax-highlighted page with line numbers, copy/raw/download
  toolbar for any text-like paste (text/*, JSON, XML, JavaScript).
  Highlighting skipped above 500 KB; pastes above 5 MB stream raw.
- Encrypted landing page: /e/<id> in a browser shows a CLI usage page
  instead of raw ciphertext; CLI/curl and ?raw=true keep the raw JSON.
- One-time interstitial: browser GETs no longer consume one-time pastes;
  a confirmation page reveals via JS fetch (?confirm=true&raw=true) that
  runs the existing consume-and-delete flow. Fixes link-unfurl bots
  burning one-time pastes.
- download=true forces Content-Disposition: attachment on raw responses.
- Styled 404 / already-viewed pages for browsers; plain text for CLI.
- Markdown viewer: header shows document title, clipboard API tried
  before execCommand fallback, hljs theme shared with new text viewer.
- R2 custom metadata: omit undefined values on write and normalize
  literal "undefined" strings on read.
- Remove dead commented-out Tailwind homepage block (~290 lines).
- Restore the create-paste panel on the homepage: Share Text and Upload
  File tabs wired to /api/text and /api/upload, one-time checkboxes,
  drag-and-drop with drag-over state, client-side 25 MB size validation,
  loading spinner, and a result panel with copyable paste URL (async
  Clipboard API with execCommand fallback)
- Replace inline onmouseover/onmouseout handlers on feature cards with a
  .feature-card CSS hover/focus-within rule gated behind
  prefers-reduced-motion: no-preference
- Load Google Fonts via preconnect + stylesheet link tags on the homepage
  instead of a render-blocking CSS @import; getMuiCSS() keeps the @import
  by default for existing inline consumers
- Add Open Graph and Twitter card meta tags to the homepage head
- Use clamp() for h1-h3 typography so the hero scales on phones; let the
  app bar wrap on narrow viewports
- Add a static terminal-window hero element showing example CLI usage
- Fix stale footer: version now sourced from a PACKAGE_VERSION constant
  (1.24.8) and copyright year updated to 2026
…zer hardening, viewer memory cap

- Gate markdown HTML rendering on Accept: text/html so CLI/curl clients
  receive raw markdown source instead of a rendered page
- Harden sanitizeHtml: strip svg/math foreign-content tags, style
  attributes, unquoted javascript:/vbscript:/data: URLs, and event
  handlers not preceded by whitespace
- Lower viewer buffering cap from 5MB to 1MB (worker memory safety)
- Stop setting wildcard CORS header on the homepage response
- sanitizeHtml now loops to a fixpoint so removals cannot reconstruct
  dangerous markup from nested fragments (js/incomplete-multi-character-
  sanitization)
- end-tag patterns match </tag > and </tag attr> forms (js/bad-tag-filter)
- stray unpaired open/close dangerous tags are stripped
- sanitizeFilename replaces path separators outright instead of deleting
  ../ sequences, so traversal cannot survive or be reconstructed
The dangerousTags loop already applies identical pair and stray-tag
removal for script/style; the dedicated replace lines duplicated it and
re-triggered CodeQL's incomplete-sanitization heuristic, which cannot
see the fixpoint loop in the caller.
@anoncam anoncam merged commit 6ef7a14 into main Jun 10, 2026
3 checks passed
@anoncam anoncam deleted the feat/web-ux-overhaul branch June 10, 2026 17:45
github-actions Bot added a commit that referenced this pull request Jun 10, 2026
Version bump type: minor
PR: #129
Title: feat: web UX overhaul — paste creation UI, browser viewing pipeline, homepage polish
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.

1 participant