From ab15c7e20e3da12221191e9107450e977c2042c8 Mon Sep 17 00:00:00 2001 From: rattatwinko Date: Tue, 17 Jun 2025 17:44:01 +0200 Subject: [PATCH] Refactor markdown processing in posts API; replace unified with marked and DOMPurify for improved HTML sanitization and performance. --- src/app/api/posts/route.ts | 46 +++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/app/api/posts/route.ts b/src/app/api/posts/route.ts index 6adc5ce..336343c 100644 --- a/src/app/api/posts/route.ts +++ b/src/app/api/posts/route.ts @@ -2,13 +2,9 @@ import { NextResponse } from 'next/server'; import fs from 'fs'; import path from 'path'; import matter from 'gray-matter'; - -import { unified } from 'unified'; -import remarkParse from 'remark-parse'; -import remarkGfm from 'remark-gfm'; -import remarkRehype from 'remark-rehype'; -import rehypeRaw from 'rehype-raw'; -import rehypeStringify from 'rehype-stringify'; +import { marked } from 'marked'; +import DOMPurify from 'dompurify'; +import { JSDOM } from 'jsdom'; const postsDirectory = path.join(process.cwd(), 'posts'); @@ -35,17 +31,35 @@ async function getPostByPath(filePath: string, relPath: string) { let processedContent = ''; try { - const file = await unified() - .use(remarkParse as any) - .use(remarkGfm) - .use(remarkRehype, { allowDangerousHtml: true }) - .use(rehypeRaw) - .use(rehypeStringify) - .process(content); - - processedContent = file.toString(); + marked.setOptions({ + gfm: true, + breaks: true + }); + const rawHtml = marked.parse(content); + const window = new JSDOM('').window; + const purify = DOMPurify(window); + processedContent = purify.sanitize(rawHtml as string, { + ALLOWED_TAGS: [ + 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', + 'p', 'a', 'ul', 'ol', 'li', 'blockquote', + 'pre', 'code', 'em', 'strong', 'del', + 'hr', 'br', 'img', 'table', 'thead', 'tbody', + 'tr', 'th', 'td', 'div', 'span', 'iframe' + ], + ALLOWED_ATTR: [ + 'class', 'id', 'style', + 'href', 'target', 'rel', + 'src', 'alt', 'title', 'width', 'height', + 'frameborder', 'allowfullscreen' + ], + ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i + }); } catch (err) { console.error(`Error processing markdown for ${relPath}:`, err); + processedContent = `
+

Error processing markdown content. Please check the console for details.

+
${err instanceof Error ? err.message : 'Unknown error'}
+
`; } return {