summaryrefslogtreecommitdiff
path: root/app/lib/md.server.ts
diff options
context:
space:
mode:
authoryyamashita <yyamashita@hetzner.yyamashita.com>2026-06-19 15:18:55 +0900
committeryyamashita <yyamashita@hetzner.yyamashita.com>2026-06-19 15:18:55 +0900
commit30f24e137ee2d1acec11a0da61e134f512ee02dd (patch)
tree28bd91bde3ad883f9f8fa543fca4b25ed50d05e9 /app/lib/md.server.ts
parentda4934ae84f8a81fe3f4f8b392a4a3dc3d566f30 (diff)
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 <noreply@anthropic.com>
Diffstat (limited to 'app/lib/md.server.ts')
-rw-r--r--app/lib/md.server.ts33
1 files changed, 33 insertions, 0 deletions
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"] },
+ });
+}