feat: web UX overhaul — paste creation UI, browser viewing pipeline, homepage polish#129
Merged
Conversation
…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.
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
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
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)/api/textand/api/uploadendpoints.onmouseoverhandlers) honoringprefers-reduced-motionpreconnect+linkinstead of render-blocking@importclamp()responsive typography; terminal-window hero demo of the CLIBrowser viewing pipeline (
src/index.ts, newsrc/viewerTemplates.ts)?raw=true&download=trueforces attachment/e/<id>in a browser now shows a copy-ablededpaste get <url>command and install hint instead of raw ciphertext JSONcurlof a.mdpaste returns raw source"undefined"stringsSecurity hardening (post-review fixes)
sanitizeHtmlnow stripssvg/mathforeign-content tags,styleattributes, and unquotedjavascript:/vbscript:/data:URLsAccess-Control-Allow-OriginTest plan
npm run buildclean; prettier cleanmain(CLI crypto tests, unrelated)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, unquotedjavascript:href, style attr)Accept: */*, what the CLI sends) receives exact raw bytesKnown items deliberately deferred
'unsafe-inline'scripts (template-wide refactor)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