51 lines
1.9 KiB
JavaScript
51 lines
1.9 KiB
JavaScript
/**
|
|
* Inline rendering: the security model and the link bugs it hid.
|
|
*
|
|
* Escape-then-format is the whole defence, and it has one awkward consequence
|
|
* that produced real broken links: by the time a URL is captured it is already
|
|
* escaped, so it has to be decoded before it can be escaped again exactly once.
|
|
*/
|
|
import { describe, it, expect } from 'vitest'
|
|
import { renderInline } from './inline.js'
|
|
|
|
describe('renderInline', () => {
|
|
it('escapes markup an author pasted', () => {
|
|
expect(renderInline('<img src=x onerror=alert(1)>'))
|
|
.toBe('<img src=x onerror=alert(1)>')
|
|
})
|
|
|
|
it('keeps a multi-parameter URL intact', () => {
|
|
// Double-escaped, this became &amp; and the link opened the wrong
|
|
// record. Every ServiceNow and SharePoint link carries several parameters.
|
|
const html = renderInline('[ticket](https://x.example/nav?a=1&b=2&c=3)')
|
|
expect(html).toContain('href="https://x.example/nav?a=1&b=2&c=3"')
|
|
expect(html).not.toContain('&amp;')
|
|
})
|
|
|
|
it('does not let emphasis reach inside an href', () => {
|
|
const html = renderInline('[t](https://x.example/a*b*c)')
|
|
expect(html).toContain('href="https://x.example/a*b*c"')
|
|
expect(html).not.toContain('<em>')
|
|
})
|
|
|
|
it('refuses a protocol-relative URL dressed as an in-app path', () => {
|
|
// '//evil.example' starts with '/' but the browser reads it as off-site.
|
|
expect(renderInline('[evil](//evil.example/x)')).toBe('evil')
|
|
})
|
|
|
|
it('refuses javascript: and keeps the label', () => {
|
|
expect(renderInline('[bad](javascript:alert(1))')).toBe('bad')
|
|
})
|
|
|
|
it('allows an in-app link', () => {
|
|
expect(renderInline('[map](/map)')).toBe('<a href="/map">map</a>')
|
|
})
|
|
|
|
it('still renders bold, italic and code', () => {
|
|
expect(renderInline('**b**')).toBe('<strong>b</strong>')
|
|
expect(renderInline('*i*')).toBe('<em>i</em>')
|
|
expect(renderInline('`C:\\**temp**`'))
|
|
.toBe('<code>C:\\**temp**</code>')
|
|
})
|
|
})
|