diff --git a/apps/server/src/services/html_sanitizer.ts b/apps/server/src/services/html_sanitizer.ts index 52e24a691..7e2e41b15 100644 --- a/apps/server/src/services/html_sanitizer.ts +++ b/apps/server/src/services/html_sanitizer.ts @@ -1,7 +1,8 @@ -import sanitizeHtml from "sanitize-html"; import { sanitizeUrl } from "@braintree/sanitize-url"; -import optionService from "./options.js"; import { ALLOWED_PROTOCOLS, SANITIZER_DEFAULT_ALLOWED_TAGS } from "@triliumnext/commons"; +import sanitizeHtml from "sanitize-html"; + +import optionService from "./options.js"; // intended mainly as protection against XSS via import // secondarily, it (partly) protects against "CSS takeover" @@ -25,7 +26,7 @@ function sanitize(dirtyHtml: string) { } // Get allowed tags from options, with fallback to default list if option not yet set - let allowedTags; + let allowedTags: readonly string[]; try { allowedTags = JSON.parse(optionService.getOption("allowedHtmlTags")); } catch (e) { @@ -38,11 +39,12 @@ function sanitize(dirtyHtml: string) { // to minimize document changes, compress H return sanitizeHtml(dirtyHtml, { - allowedTags, + allowedTags: allowedTags as string[], allowedAttributes: { "*": ["class", "style", "title", "src", "href", "hash", "disabled", "align", "alt", "center", "data-*"], input: ["type", "checked"], - img: ["width", "height"] + img: ["width", "height"], + code: [ "spellcheck" ] }, allowedStyles: { "*": { diff --git a/apps/server/src/services/import/markdown.spec.ts b/apps/server/src/services/import/markdown.spec.ts index 501cc54c7..1ac49f613 100644 --- a/apps/server/src/services/import/markdown.spec.ts +++ b/apps/server/src/services/import/markdown.spec.ts @@ -308,4 +308,10 @@ $$`; expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected); }); + it("adds spellcheck=false to inline code", () => { + const input = `This is some inline code: \`const x = 10;\``; + const expected = /*html*/`

This is some inline code: const x = 10;

`; + expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected); + }); + }); diff --git a/apps/server/src/services/import/markdown.ts b/apps/server/src/services/import/markdown.ts index 94bf928a5..e91670df6 100644 --- a/apps/server/src/services/import/markdown.ts +++ b/apps/server/src/services/import/markdown.ts @@ -1,14 +1,17 @@ -"use strict"; -import { parse, Renderer, use, type Tokens } from "marked"; -import htmlSanitizer from "../html_sanitizer.js"; -import importUtils from "./utils.js"; + import { getMimeTypeFromMarkdownName, MIME_TYPE_AUTO } from "@triliumnext/commons"; -import { ADMONITION_TYPE_MAPPINGS } from "../export/markdown.js"; -import utils from "../utils.js"; import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons"; -import wikiLinkTransclusion from "./markdown/wikilink_transclusion.js"; +import { parse, Renderer, type Tokens,use } from "marked"; + +import { ADMONITION_TYPE_MAPPINGS } from "../export/markdown.js"; +import htmlSanitizer from "../html_sanitizer.js"; +import utils from "../utils.js"; import wikiLinkInternalLink from "./markdown/wikilink_internal_link.js"; +import wikiLinkTransclusion from "./markdown/wikilink_transclusion.js"; +import importUtils from "./utils.js"; + +const escape = utils.escapeHtml; /** * Keep renderer code up to date with https://github.com/markedjs/marked/blob/master/src/Renderer.ts. @@ -34,7 +37,7 @@ class CustomMarkdownRenderer extends Renderer { } // Escape the HTML. - text = utils.escapeHtml(text); + text = escape(text); // Unescape " text = text.replace(/"/g, '"'); @@ -57,9 +60,9 @@ class CustomMarkdownRenderer extends Renderer { } override checkbox({ checked }: Tokens.Checkbox): string { - return ''; + return ``; } override listitem(item: Tokens.ListItem): string { @@ -117,6 +120,10 @@ class CustomMarkdownRenderer extends Renderer { return `
${body}
`; } + codespan({ text }: Tokens.Codespan): string { + return `${escape(text)}`; + } + } function renderToHtml(content: string, title: string) { @@ -136,7 +143,7 @@ function renderToHtml(content: string, title: string) { let html = parse(processedText, { async: false, - renderer: renderer + renderer }) as string; // After rendering, replace placeholders back with the formula HTML