fix(import/markdown): unable to import code blocks with XML/HTML content if safe mode on (closes #1530)

This commit is contained in:
Elian Doran 2025-03-29 13:47:02 +02:00
parent fd76f8dac9
commit 9a3f765d42
No known key found for this signature in database
2 changed files with 28 additions and 2 deletions

View File

@ -43,7 +43,6 @@ describe("markdown", () => {
expect(result).toBe(`<h2>Hello</h2><h2>world</h2><h2>another one</h2><p>Hello, world</p>`); expect(result).toBe(`<h2>Hello</h2><h2>world</h2><h2>another one</h2><p>Hello, world</p>`);
}); });
it("parses duplicate title with escape correctly", () => { it("parses duplicate title with escape correctly", () => {
const result = markdownService.renderToHtml(trimIndentation`\ const result = markdownService.renderToHtml(trimIndentation`\
# What's new # What's new
@ -108,4 +107,24 @@ second line 2</code></pre><ul><li>Hello</li><li>world</li></ul><ol><li>Hello</li
expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected); expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
}); });
it("maintains code blocks with XML/HTML", () => {
const input = trimIndentation`\
Before
\`\`\`
<application
...
android:testOnly="false">
...
</application>
\`\`\`
After`;
const expected = trimIndentation`\
<p>Before</p><pre><code class="language-text-x-trilium-auto">&lt;application
...
android:testOnly="false"&gt;
...
&lt;/application&gt;</code></pre><p>After</p>`;
expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
});
}); });

View File

@ -20,6 +20,12 @@ class CustomMarkdownRenderer extends Renderer {
return ""; return "";
} }
// Escape the HTML.
text = utils.escapeHtml(text);
// Unescape &quot
text = text.replace(/&quot;/g, '"');
const ckEditorLanguage = getNormalizedMimeFromMarkdownLanguage(lang); const ckEditorLanguage = getNormalizedMimeFromMarkdownLanguage(lang);
return `<pre><code class="language-${ckEditorLanguage}">${text}</code></pre>`; return `<pre><code class="language-${ckEditorLanguage}">${text}</code></pre>`;
} }
@ -66,6 +72,7 @@ import htmlSanitizer from "../html_sanitizer.js";
import importUtils from "./utils.js"; import importUtils from "./utils.js";
import { getMimeTypeFromHighlightJs, MIME_TYPE_AUTO, normalizeMimeTypeForCKEditor } from "./mime_type_definitions.js"; import { getMimeTypeFromHighlightJs, MIME_TYPE_AUTO, normalizeMimeTypeForCKEditor } from "./mime_type_definitions.js";
import { ADMONITION_TYPE_MAPPINGS } from "../export/markdown.js"; import { ADMONITION_TYPE_MAPPINGS } from "../export/markdown.js";
import utils from "../utils.js";
function renderToHtml(content: string, title: string) { function renderToHtml(content: string, title: string) {
let html = parse(content, { let html = parse(content, {
@ -75,7 +82,7 @@ function renderToHtml(content: string, title: string) {
// h1 handling needs to come before sanitization // h1 handling needs to come before sanitization
html = importUtils.handleH1(html, title); html = importUtils.handleH1(html, title);
html = htmlSanitizer.sanitize(html); // html = htmlSanitizer.sanitize(html);
// Remove slash for self-closing tags to match CKEditor's approach. // Remove slash for self-closing tags to match CKEditor's approach.
html = html.replace(/<(\w+)([^>]*)\s+\/>/g, "<$1$2>"); html = html.replace(/<(\w+)([^>]*)\s+\/>/g, "<$1$2>");