| … | … | @@ -0,0 +1,38 @@ |
| 1 | import test from 'brittle' |
| 2 | import { renderMarkdown } from '../../lib/markdown.js' |
| 3 | |
| 4 | test('renderMarkdown - javascript: link scheme is neutralized', async (t) => { |
| 5 | const html = renderMarkdown('[click me](javascript:alert(document.cookie))') |
| 6 | t.absent(html.toLowerCase().includes('javascript:'), 'no javascript: scheme survives') |
| 7 | t.ok(html.includes('<a href="">click me</a>'), 'href emptied by safeUrl, label preserved') |
| 8 | }) |
| 9 | |
| 10 | test('renderMarkdown - data:/vbscript: link schemes are neutralized', async (t) => { |
| 11 | t.absent(renderMarkdown('[x](data:text/html,<script>1</script>)').toLowerCase().includes('data:'), 'data: blocked') |
| 12 | t.absent(renderMarkdown('[x](vbscript:msgbox)').toLowerCase().includes('vbscript:'), 'vbscript: blocked') |
| 13 | }) |
| 14 | |
| 15 | test('renderMarkdown - normal https link is preserved', async (t) => { |
| 16 | const html = renderMarkdown('see [example](https://example.com/p)') |
| 17 | t.ok(html.includes('<a href="https://example.com/p">example</a>'), 'safe http(s) link intact') |
| 18 | }) |
| 19 | |
| 20 | test('renderMarkdown - raw <video> event-handler attributes are stripped', async (t) => { |
| 21 | const html = renderMarkdown('<video onloadstart="alert(1)" onerror="alert(2)"><source src="/api/x.mp4"></video>') |
| 22 | t.absent(html.includes('onloadstart'), 'onloadstart attribute dropped') |
| 23 | t.absent(html.includes('onerror'), 'onerror attribute dropped') |
| 24 | t.absent(html.toLowerCase().includes('alert'), 'no inline JS survives') |
| 25 | t.ok(html.includes('<source src="/api/x.mp4">'), 'legitimate source URL preserved') |
| 26 | t.ok(html.includes('<video controls'), 'clean <video controls> emitted') |
| 27 | }) |
| 28 | |
| 29 | test('renderMarkdown - raw <video> with javascript: source is dropped', async (t) => { |
| 30 | const html = renderMarkdown('<video><source src="javascript:alert(1)"></video>') |
| 31 | t.absent(html.toLowerCase().includes('javascript:'), 'malicious source filtered by safeUrl') |
| 32 | }) |
| 33 | |
| 34 | test('renderMarkdown - markdown image still renders safely', async (t) => { |
| 35 | const html = renderMarkdown('') |
| 36 | t.ok(html.includes('<img'), 'image rendered') |
| 37 | t.ok(html.includes('src="/api/notebooks/x/media/abc.png"'), 'image src preserved') |
| 38 | }) |