diff --git a/src/app/utils/sanitize.test.ts b/src/app/utils/sanitize.test.ts new file mode 100644 index 000000000..170d3ff8f --- /dev/null +++ b/src/app/utils/sanitize.test.ts @@ -0,0 +1,52 @@ +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { sanitizeCustomHtml, sanitizeText } from './sanitize'; + +test('sanitizeText escapes HTML metacharacters', () => { + assert.equal(sanitizeText('hello'); + assert.ok(!out.includes('alert')); + assert.ok(out.includes('hello')); +}); + +test('sanitizeCustomHtml strips event-handler attributes', () => { + const out = sanitizeCustomHtml('hi'); + assert.ok(!out.includes('onclick')); + assert.ok(out.includes('hi')); +}); + +test('sanitizeCustomHtml drops disallowed tags, keeps allowed ones', () => { + assert.ok(!sanitizeCustomHtml('').includes('iframe')); + assert.ok(sanitizeCustomHtml('bold').includes('')); +}); + +test('sanitizeCustomHtml neutralizes javascript: links', () => { + const out = sanitizeCustomHtml('x'); + // eslint-disable-next-line no-script-url -- asserting the scheme was stripped + assert.ok(!out.includes('javascript:')); +}); + +test('sanitizeCustomHtml hardens anchors (noreferrer/noopener/_blank)', () => { + const out = sanitizeCustomHtml('x'); + assert.ok(out.includes('rel="noreferrer noopener"')); + assert.ok(out.includes('target="_blank"')); +}); + +test('sanitizeCustomHtml converts a non-mxc into a link', () => { + const out = sanitizeCustomHtml('pic'); + assert.ok(!out.includes(' class is restricted to the language-* whitelist', () => { + assert.ok(sanitizeCustomHtml('
x
').includes('language-js')); + assert.ok( + !sanitizeCustomHtml('
x
').includes('evil-site-class'), + ); +});