Skip to content

Commit

Permalink
Fixed Link extension's commands not respecting XSS prevention via una…
Browse files Browse the repository at this point in the history
…llowed protocols (#5945)

* fixed link commands not respecting allowed protocols

* added changesets

* refactor(link): don't use throw for invalid uri handling
  • Loading branch information
bdbch authored Dec 19, 2024
1 parent 7567ace commit 1c2fefe
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/empty-seals-join.md
Original file line number Diff line number Diff line change
@@ -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
8 changes: 6 additions & 2 deletions demos/src/Marks/Link/React/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
22 changes: 21 additions & 1 deletion packages/extension-link/src/link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -322,11 +322,31 @@ export const Link = Mark.create<LinkOptions>({
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)
Expand Down

0 comments on commit 1c2fefe

Please sign in to comment.