Read a Markdown file as the document it is #192

Closed
opened 2026-09-02 03:33:11 +00:00 by jcoffey-dev · 0 comments
Owner

A .md previewed as its own source, which is reading the punctuation rather than the notes. It opens rendered now, with Rendered | Source in the dialog footer for anyone who wants what the file actually says. Markdown only — a .txt has nothing to toggle between.

Rendering is marked (a 9th runtime dependency, which is why I asked first), sanitised by DOMPurify — the one already here for mail. Markdown is not a safe subset of anything: raw HTML passes through it by design, so a <script> in a file someone uploaded or shared into the account is a script tag unless something takes it out. Tests cover the script, onerror, iframe and javascript: cases.

Images become links, not pictures. An image in a Markdown file is either a relative path with no base to resolve against here, or a URL somewhere else that fetches on open and tells that server the file was read — the tracking pixel this app already blocks in mail. The link keeps the alt text and the address visible, so nothing vanishes silently and the reader chooses.

Also: the PDF preview never worked

Found while testing this. securityHeaders sets X-Frame-Options: DENY on every response, the blob route included, so the PDF iframe rendered Chrome’s "refused to connect" instead of the file — in Files today, and in mail attachments since long before #191.

The middleware now leaves a header a route has already set (the pattern it already uses for Cache-Control), and a PDF served inline sets SAMEORIGIN. Nothing else on the server is framable, and securityHeadersFor is exported so the rule is pinned by a test in both directions rather than only the happy one.

Verified

Mock stack in a visible Chrome tab:

result
rich.md opens rendered — headings, bold, inline code, table, blockquote, fenced code, nested lists
image in it shows as a link, never fetched
Source toggle flips to the raw file and back
a real PDF renders in the viewer with thumbnails and zoom — this is the framing fix
the mock report.pdf loads the viewer, which then rejects it: it is 14 bytes of fixture, not a PDF

Print of rendered Markdown by headless print-to-PDF: 1 page, styling intact, nothing of the app around it.

typecheck clean, 596 web + 110 server tests, i18n:check clean, build clean.

Merged 2026-09-01 as coffey-labs/ihasmail@8d562628ff

Rebuilt from: git history, session transcript.

A `.md` previewed as its own source, which is reading the punctuation rather than the notes. It opens rendered now, with **Rendered | Source** in the dialog footer for anyone who wants what the file actually says. Markdown only — a `.txt` has nothing to toggle between. Rendering is `marked` (a 9th runtime dependency, which is why I asked first), sanitised by DOMPurify — the one already here for mail. Markdown is not a safe subset of anything: raw HTML passes through it by design, so a `<script>` in a file someone uploaded or shared into the account is a script tag unless something takes it out. Tests cover the script, `onerror`, `iframe` and `javascript:` cases. **Images become links, not pictures.** An image in a Markdown file is either a relative path with no base to resolve against here, or a URL somewhere else that fetches on open and tells that server the file was read — the tracking pixel this app already blocks in mail. The link keeps the alt text and the address visible, so nothing vanishes silently and the reader chooses. ## Also: the PDF preview never worked Found while testing this. `securityHeaders` sets `X-Frame-Options: DENY` on **every** response, the blob route included, so the PDF iframe rendered Chrome’s "refused to connect" instead of the file — in Files today, and in mail attachments since long before #191. The middleware now leaves a header a route has already set (the pattern it already uses for `Cache-Control`), and a PDF served inline sets `SAMEORIGIN`. Nothing else on the server is framable, and `securityHeadersFor` is exported so the rule is pinned by a test in both directions rather than only the happy one. ## Verified Mock stack in a visible Chrome tab: | | result | |---|---| | `rich.md` | opens rendered — headings, bold, inline code, table, blockquote, fenced code, nested lists | | image in it | shows as a link, never fetched | | Source toggle | flips to the raw file and back | | a real PDF | renders in the viewer with thumbnails and zoom — this is the framing fix | | the mock `report.pdf` | loads the viewer, which then rejects it: it is 14 bytes of fixture, not a PDF | Print of rendered Markdown by headless print-to-PDF: 1 page, styling intact, nothing of the app around it. `typecheck` clean, 596 web + 110 server tests, `i18n:check` clean, build clean. **Merged** 2026-09-01 as coffey-labs/ihasmail@8d562628ff4e <sub>Rebuilt from: git history, session transcript.</sub>
This repo is archived. You cannot comment on issues.