mirror of
https://github.com/ueberdosis/tiptap.git
synced 2025-06-07 17:43:49 +08:00
When [we fixed a XSS vuln](https://github.com/ueberdosis/tiptap/pull/5160), we inadvertently broke the ability to use custom protocols, this resolves that by allowing additional custom protocols to be considered valid and not stripped out
This commit is contained in:
parent
6a0f4f30f8
commit
593f1070a8
5
.changeset/fluffy-bears-remember.md
Normal file
5
.changeset/fluffy-bears-remember.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@tiptap/extension-link": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Respect custom protocols for links again, custom protocols are supported in additional to the default set #5468
|
@ -106,11 +106,24 @@ declare module '@tiptap/core' {
|
|||||||
|
|
||||||
// From DOMPurify
|
// From DOMPurify
|
||||||
// https://github.com/cure53/DOMPurify/blob/main/src/regexp.js
|
// https://github.com/cure53/DOMPurify/blob/main/src/regexp.js
|
||||||
const ATTR_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
|
// eslint-disable-next-line no-control-regex
|
||||||
const IS_ALLOWED_URI = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
|
const ATTR_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g
|
||||||
|
|
||||||
function isAllowedUri(uri: string | undefined) {
|
function isAllowedUri(uri: string | undefined, protocols?: LinkOptions['protocols']) {
|
||||||
return !uri || uri.replace(ATTR_WHITESPACE, '').match(IS_ALLOWED_URI)
|
const allowedProtocols: string[] = ['http', 'https', 'ftp', 'ftps', 'mailto', 'tel', 'callto', 'sms', 'cid', 'xmpp']
|
||||||
|
|
||||||
|
if (protocols) {
|
||||||
|
protocols.forEach(protocol => {
|
||||||
|
const nextProtocol = (typeof protocol === 'string' ? protocol : protocol.scheme)
|
||||||
|
|
||||||
|
if (nextProtocol) {
|
||||||
|
allowedProtocols.push(nextProtocol)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-useless-escape
|
||||||
|
return !uri || uri.replace(ATTR_WHITESPACE, '').match(new RegExp(`^(?:(?:${allowedProtocols.join('|')}):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))`, 'i'))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -187,7 +200,7 @@ export const Link = Mark.create<LinkOptions>({
|
|||||||
const href = (dom as HTMLElement).getAttribute('href')
|
const href = (dom as HTMLElement).getAttribute('href')
|
||||||
|
|
||||||
// prevent XSS attacks
|
// prevent XSS attacks
|
||||||
if (!href || !isAllowedUri(href)) {
|
if (!href || !isAllowedUri(href, this.options.protocols)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
@ -197,7 +210,7 @@ export const Link = Mark.create<LinkOptions>({
|
|||||||
|
|
||||||
renderHTML({ HTMLAttributes }) {
|
renderHTML({ HTMLAttributes }) {
|
||||||
// prevent XSS attacks
|
// prevent XSS attacks
|
||||||
if (!isAllowedUri(HTMLAttributes.href)) {
|
if (!isAllowedUri(HTMLAttributes.href, this.options.protocols)) {
|
||||||
// strip out the href
|
// strip out the href
|
||||||
return ['a', mergeAttributes(this.options.HTMLAttributes, { ...HTMLAttributes, href: '' }), 0]
|
return ['a', mergeAttributes(this.options.HTMLAttributes, { ...HTMLAttributes, href: '' }), 0]
|
||||||
}
|
}
|
||||||
|
@ -250,4 +250,29 @@ describe('extension-link', () => {
|
|||||||
getEditorEl()?.remove()
|
getEditorEl()?.remove()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('custom protocols', () => {
|
||||||
|
it('allows using additional custom protocols', () => {
|
||||||
|
['custom://test.css', 'another-custom://protocol.html', ...validUrls].forEach(url => {
|
||||||
|
editor = new Editor({
|
||||||
|
element: createEditorEl(),
|
||||||
|
extensions: [
|
||||||
|
Document,
|
||||||
|
Text,
|
||||||
|
Paragraph,
|
||||||
|
Link.configure({
|
||||||
|
protocols: ['custom', { scheme: 'another-custom' }],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
content: `<p><a href="${url}">hello world!</a></p>`,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(editor.getHTML()).to.include(url)
|
||||||
|
expect(JSON.stringify(editor.getJSON())).to.include(url)
|
||||||
|
|
||||||
|
editor?.destroy()
|
||||||
|
getEditorEl()?.remove()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user