Snippets · v0.7.3
markdown
markdown::to_html: CommonMark (tables, strikethrough) rendered by pulldown-cmark, sanitized by ammonia
- Commands
cargo offrails snippet show markdown # read it: the README, every file, every wire cargo offrails snippet add markdown # copy and wire it cargo offrails snippet remove markdown # take it back- Needs
- crates
pulldown-cmark,ammonia - Files
src/views/markdown.rs
- Wires into
src/views/mod.rsat samples: view mods
.offrails/template/snippets/markdown/README.md
Snippet: markdown
TL;DR
views::markdown::to_html(md): Markdown in, HTML a template may show unescaped out. pulldown-cmark renders it (CommonMark, tables, strikethrough), ammonia sanitizes it (no scripts, event handlers,javascript:URLs, iframes or styles; links getrel="noopener noreferrer nofollow ugc").- Render where the page struct is built, never in the template:
body_html: markdown::to_html(&post.body), then{{ body_html|safe }}.- Adds two crates,
pulldown-cmarkandammonia(cargo add, versions from Cargo.lock).
When to use it
- Posts, comments, descriptions, docs: text people format.
- Not for: one-line fields (titles stay text, escaped by Askama), or HTML you wrote yourself (a template).
Files
| Path | What it is |
|---|---|
src/views/markdown.rs | to_html, LINK_REL, with unit tests (rendering, the XSS vectors removed, links kept) |
Wiring
src/views/mod.rsatsamples: view mods:pub mod markdown; // markdowncargo add pulldown-cmark ammonia
After adding
- In the view struct (
src/views/<plural>.rs), addpub body_html: Stringand fill it withmarkdown::to_html(&r.body)infrom_model. - In the template:
<div class="prose dark:prose-invert">{{ body_html|safe }}</div>(or your own styles forh1,ul,code…). - A request test that markup in the body is gone from the page (
assert_not_contains("<script>alert(1)")), citing your AC.cargo offrails verify.
Adapting it
- More syntax (footnotes, task lists): add the
Options::ENABLE_*flag, then check what ammonia keeps (it drops<input>, so task-list checkboxes vanish unless you allow them). - Allow more tags or attributes (
classoncodefor syntax highlighting):.add_tag_attributes("code", &["class"])on the builder. Each one you allow is attack surface: add its XSS case toscripts_handlers_and_javascript_urls_are_removed. - Long bodies on hot pages: render once on save into a
body_htmlcolumn instead of on every view.
Remove it
cargo offrails snippet remove markdown (then cargo remove pulldown-cmark ammonia if nothing else uses them), or delete src/views/markdown.rs and the line marked // markdown.