diff --git a/.changeset/empty-seals-join.md b/.changeset/empty-seals-join.md new file mode 100644 index 0000000000..d4a36d7e3f --- /dev/null +++ b/.changeset/empty-seals-join.md @@ -0,0 +1,5 @@ +--- +"@tiptap/extension-link": patch +--- + +Added checks for allowed protocols in link commands & exported isValidUri helper for manual checks outside of the extension diff --git a/demos/src/Marks/Link/React/index.jsx b/demos/src/Marks/Link/React/index.jsx index 4af6bcff67..39f9598361 100644 --- a/demos/src/Marks/Link/React/index.jsx +++ b/demos/src/Marks/Link/React/index.jsx @@ -105,8 +105,12 @@ export default () => { } // update link - editor.chain().focus().extendMarkRange('link').setLink({ href: url }) - .run() + try { + editor.chain().focus().extendMarkRange('link').setLink({ href: url }) + .run() + } catch (e) { + alert(e.message) + } }, [editor]) if (!editor) { diff --git a/packages/extension-link/src/link.ts b/packages/extension-link/src/link.ts index b9b882995b..811060a48d 100644 --- a/packages/extension-link/src/link.ts +++ b/packages/extension-link/src/link.ts @@ -160,7 +160,7 @@ declare module '@tiptap/core' { // eslint-disable-next-line no-control-regex const ATTR_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g -function isAllowedUri(uri: string | undefined, protocols?: LinkOptions['protocols']) { +export function isAllowedUri(uri: string | undefined, protocols?: LinkOptions['protocols']) { const allowedProtocols: string[] = [ 'http', 'https', @@ -322,11 +322,31 @@ export const Link = Mark.create({ return { setLink: attributes => ({ chain }) => { + const { href } = attributes + + if (!this.options.isAllowedUri(href, { + defaultValidate: url => !!isAllowedUri(url, this.options.protocols), + protocols: this.options.protocols, + defaultProtocol: this.options.defaultProtocol, + })) { + return false + } + return chain().setMark(this.name, attributes).setMeta('preventAutolink', true).run() }, toggleLink: attributes => ({ chain }) => { + const { href } = attributes + + if (!this.options.isAllowedUri(href, { + defaultValidate: url => !!isAllowedUri(url, this.options.protocols), + protocols: this.options.protocols, + defaultProtocol: this.options.defaultProtocol, + })) { + return false + } + return chain() .toggleMark(this.name, attributes, { extendEmptyMarkRange: true }) .setMeta('preventAutolink', true)