From 7a21a26166761d103a265b5b022be54a6c75fd6b Mon Sep 17 00:00:00 2001 From: Erik Michelson Date: Sun, 11 Apr 2021 22:48:31 +0200 Subject: [PATCH] Disallow data and javascript URIs (#1186) * Disallow data and javascript URIs Signed-off-by: Erik Michelson --- cypress/integration/linkSchemes.ts | 93 +++++++++++++++++++ .../link-replacer/link-replacer.tsx | 8 +- 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 cypress/integration/linkSchemes.ts diff --git a/cypress/integration/linkSchemes.ts b/cypress/integration/linkSchemes.ts new file mode 100644 index 000000000..ba1deebde --- /dev/null +++ b/cypress/integration/linkSchemes.ts @@ -0,0 +1,93 @@ +/* + * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +describe('markdown formatted links to', () => { + beforeEach(() => { + cy.loadConfig() + cy.visitTestEditor() + }) + + it('external domains render as external link', () => { + cy.codemirrorFill('[external](https://hedgedoc.org/)') + cy.getMarkdownBody() + .find('a') + .should('have.attr', 'href', 'https://hedgedoc.org/') + .should('have.attr', 'rel', 'noreferer noopener') + .should('have.attr', 'target', '_blank') + }) + + it('note anchor references render as anchor link', () => { + cy.codemirrorFill('[anchor](#anchor)') + cy.getMarkdownBody() + .find('a') + .should('have.attr', 'href', 'http://127.0.0.1:3001/n/test#anchor') + }) + + it('internal pages render as internal link', () => { + cy.codemirrorFill('[internal](other-note)') + cy.getMarkdownBody() + .find('a') + .should('have.attr', 'href', 'http://127.0.0.1:3001/n/other-note') + }) + + it('data URIs do not render', () => { + cy.codemirrorFill('[data](data:text/plain,evil)') + cy.getMarkdownBody() + .find('a') + .should('not.exist') + }) + + it('javascript URIs do not render', () => { + cy.codemirrorFill('[js](javascript:alert("evil"))') + cy.getMarkdownBody() + .find('a') + .should('not.exist') + }) +}) + +describe('HTML anchor element links to', () => { + beforeEach(() => { + cy.loadConfig() + cy.visitTestEditor() + }) + + it('external domains render as external link', () => { + cy.codemirrorFill('external') + cy.getMarkdownBody() + .find('a') + .should('have.attr', 'href', 'https://hedgedoc.org/') + .should('have.attr', 'rel', 'noreferer noopener') + .should('have.attr', 'target', '_blank') + }) + + it('note anchor references render as anchor link', () => { + cy.codemirrorFill('anchor') + cy.getMarkdownBody() + .find('a') + .should('have.attr', 'href', 'http://127.0.0.1:3001/n/test#anchor') + }) + + it('internal pages render as internal link', () => { + cy.codemirrorFill('internal') + cy.getMarkdownBody() + .find('a') + .should('have.attr', 'href', 'http://127.0.0.1:3001/n/other-note') + }) + + it('data URIs do not render', () => { + cy.codemirrorFill('data') + cy.getMarkdownBody() + .find('a') + .should('not.exist') + }) + + it('javascript URIs do not render', () => { + cy.codemirrorFill('js') + cy.getMarkdownBody() + .find('a') + .should('not.exist') + }) +}) diff --git a/src/components/markdown-renderer/replace-components/link-replacer/link-replacer.tsx b/src/components/markdown-renderer/replace-components/link-replacer/link-replacer.tsx index c3b5e4b80..4cd71c052 100644 --- a/src/components/markdown-renderer/replace-components/link-replacer/link-replacer.tsx +++ b/src/components/markdown-renderer/replace-components/link-replacer/link-replacer.tsx @@ -25,7 +25,13 @@ export class LinkReplacer extends ComponentReplacer { return undefined } - const url = node.attribs.href + const url = node.attribs.href.trim() + + // eslint-disable-next-line no-script-url + if (url.startsWith('data:') || url.startsWith('javascript:')) { + return { node.attribs.href } + } + const isJumpMark = url.substr(0, 1) === '#' const id = url.substr(1)