diff --git a/src-ui/src/app/pipes/markdown.pipe.spec.ts b/src-ui/src/app/pipes/markdown.pipe.spec.ts index 102e58065..a0655486e 100644 --- a/src-ui/src/app/pipes/markdown.pipe.spec.ts +++ b/src-ui/src/app/pipes/markdown.pipe.spec.ts @@ -42,7 +42,7 @@ describe('MarkdownPipe', () => { it('should render safe links with target and rel', () => { const html = pipe.transform('[docs](https://docs.paperless-ngx.com "Docs")') expect(html).toContain( - 'docs' + 'docs' ) expect(pipe.transform('[mail](mailto:a@b.c)')).toContain( 'href="mailto:a@b.c"' @@ -77,7 +77,7 @@ describe('MarkdownPipe', () => { it('should omit the hostname label for mailto links', () => { expect(pipe.transform('[mail](mailto:a@b.c)')).toBe( - '
\n' + '\n' ) }) diff --git a/src-ui/src/app/pipes/markdown.pipe.ts b/src-ui/src/app/pipes/markdown.pipe.ts index fbfb1d0e6..992714c14 100644 --- a/src-ui/src/app/pipes/markdown.pipe.ts +++ b/src-ui/src/app/pipes/markdown.pipe.ts @@ -3,43 +3,34 @@ import { Marked, Renderer, Tokens } from 'marked' const ALLOWED_LINK_PROTOCOLS = new Set(['http:', 'https:', 'mailto:']) -function escapeHtml(text: string): string { - return text - .replaceAll('&', '&') - .replaceAll('<', '<') - .replaceAll('>', '>') - .replaceAll('"', '"') - .replaceAll("'", ''') -} - -function safeHref(href: string): string | null { +function allowedUrl(href: string): URL | null { try { const url = new URL(href) - return ALLOWED_LINK_PROTOCOLS.has(url.protocol) ? url.href : null + return ALLOWED_LINK_PROTOCOLS.has(url.protocol) ? url : null } catch { return null } } // Treat chat content as untrusted: no raw HTML, no images, and only -// absolute links. Angular sanitizer runs on top of this as well. +// absolute links. All escaping is done by marked's default renderer, and +// Angular's sanitizer runs on top of this as well. const renderer: Partial