feat(editor): link insertion full UI and flow
This commit is contained in:
1 parent
03b39e64f2
commit
6f9ae6207a
16 files changed
+2865
-14
No files matched your search
@@ -0,0 +1,91 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { isStoredHrefSafe, neutralizeUnsafeLinks, normalizeLinkUrl } from '../articleLinkUrl'
|
||||
|
||||
describe('normalizeLinkUrl accepts', () => {
|
||||
it.each([
|
||||
['https://example.org/a?b=1#c', 'https://example.org/a?b=1#c'],
|
||||
['HTTP://Example.org', 'HTTP://Example.org'],
|
||||
['mailto:hello@example.org', 'mailto:hello@example.org'],
|
||||
['/articles/winter-checklist', '/articles/winter-checklist'],
|
||||
['#measuring', '#measuring'],
|
||||
[' /page ', '/page'],
|
||||
])('%s', (raw, href) => {
|
||||
expect(normalizeLinkUrl(raw)).toBe(href)
|
||||
})
|
||||
})
|
||||
|
||||
describe('normalizeLinkUrl rejects', () => {
|
||||
it.each([
|
||||
'www.example',
|
||||
'example.com',
|
||||
'javascript:alert(1)',
|
||||
'JaVaScRiPt:alert(1)',
|
||||
' javascript:alert(1)',
|
||||
'javascript:alert(1)',
|
||||
'\u0001javascript:alert(1)',
|
||||
'java\tscript:alert(1)',
|
||||
'data:text/html;base64,PHA+',
|
||||
'vbscript:msgbox(1)',
|
||||
'file:///etc/passwd',
|
||||
'ftp://example.org/a',
|
||||
'tel:+33123456789',
|
||||
'//evil.example',
|
||||
'/\\evil.example',
|
||||
'page.html',
|
||||
'../x',
|
||||
'http://',
|
||||
'https://exa mple.org',
|
||||
'',
|
||||
'#',
|
||||
'https://exa\u0001mple.org',
|
||||
'/\u0001evil',
|
||||
'#\u0001',
|
||||
'/a\u007fb',
|
||||
'/a\u0085b',
|
||||
])('%j', (raw) => {
|
||||
expect(normalizeLinkUrl(raw)).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('isStoredHrefSafe', () => {
|
||||
it.each([
|
||||
'/a',
|
||||
'#a',
|
||||
'page.html',
|
||||
'../x',
|
||||
'https://a.example',
|
||||
'mailto:a@b.example',
|
||||
'tel:+3312',
|
||||
])('keeps %s', (href) => {
|
||||
expect(isStoredHrefSafe(href)).toBe(true)
|
||||
})
|
||||
|
||||
it.each([
|
||||
'javascript:alert(1)',
|
||||
' JavaScript:alert(1)',
|
||||
'java\nscript:alert(1)',
|
||||
'\u0001javascript:alert(1)',
|
||||
'data:text/html,<b>',
|
||||
'vbscript:msgbox(1)',
|
||||
'file:///etc/passwd',
|
||||
'',
|
||||
])('neutralises %s', (href) => {
|
||||
expect(isStoredHrefSafe(href)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('neutralizeUnsafeLinks', () => {
|
||||
it('unwraps unsafe anchors and keeps their text', () => {
|
||||
const html = neutralizeUnsafeLinks(
|
||||
'<p>a <a href="javascript:alert(1)">x</a> <a href="data:text/html,b">y</a> <a href="vbscript:z">w</a></p>',
|
||||
)
|
||||
|
||||
expect(html).toBe('<p>a x y w</p>')
|
||||
})
|
||||
|
||||
it('keeps safe anchors untouched', () => {
|
||||
const html = neutralizeUnsafeLinks('<p><a href="/a" target="_blank">x</a></p>')
|
||||
|
||||
expect(html).toBe('<p><a href="/a" target="_blank">x</a></p>')
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user