From 30f24e137ee2d1acec11a0da61e134f512ee02dd Mon Sep 17 00:00:00 2001 From: yyamashita Date: Fri, 19 Jun 2026 15:18:55 +0900 Subject: Initial implementation of microblog Markdown-based personal microblog with REST API. XSS protection via sanitize-html on server-side markdown rendering. Co-Authored-By: Claude Sonnet 4.6 --- app/lib/md.server.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 app/lib/md.server.ts (limited to 'app/lib/md.server.ts') diff --git a/app/lib/md.server.ts b/app/lib/md.server.ts new file mode 100644 index 0000000..8f0d6d6 --- /dev/null +++ b/app/lib/md.server.ts @@ -0,0 +1,33 @@ +import { marked } from "marked"; +import sanitizeHtml from "sanitize-html"; + +const ALLOWED_TAGS = [ + "p", "br", + "h1", "h2", "h3", "h4", "h5", "h6", + "ul", "ol", "li", + "blockquote", + "pre", "code", + "strong", "em", "del", "s", + "a", + "hr", + "table", "thead", "tbody", "tr", "th", "td", + "img", +]; + +const ALLOWED_ATTRIBUTES: sanitizeHtml.IOptions["allowedAttributes"] = { + a: ["href", "title"], + img: ["src", "alt", "title"], + code: ["class"], + td: ["align"], + th: ["align"], +}; + +export function renderMarkdown(content: string): string { + const raw = marked.parse(content, { async: false }) as string; + return sanitizeHtml(raw, { + allowedTags: ALLOWED_TAGS, + allowedAttributes: ALLOWED_ATTRIBUTES, + allowedSchemes: ["http", "https", "mailto"], + allowedSchemesByTag: { img: ["http", "https"] }, + }); +} -- cgit v1.2.3