Skip to content

Commit de92225

Browse files
authored
feat: santinize url input (#1808)
* feat: santinize url input * chore: adjust
1 parent f0efe86 commit de92225

File tree

7 files changed

+48
-10
lines changed

7 files changed

+48
-10
lines changed

Diff for: packages/components/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@
118118
"@types/lodash.throttle": "^4.1.9",
119119
"atomico": "^1.75.1",
120120
"clsx": "^2.0.0",
121+
"dompurify": "^3.2.5",
121122
"lodash.debounce": "^4.0.8",
122123
"lodash.throttle": "^4.1.1",
123124
"nanoid": "^5.0.9",

Diff for: packages/components/src/__internal__/components/icon.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import clsx from 'clsx'
2+
import DOMPurify from 'dompurify'
23
import { h } from 'vue'
34

45
h
@@ -16,7 +17,7 @@ export function Icon({ icon, class: className, onClick }: IconProps) {
1617
onPointerdown={onClick}
1718
ref={(el) => {
1819
if (el && icon) {
19-
;(el as HTMLElement).innerHTML = icon.trim()
20+
;(el as HTMLElement).innerHTML = DOMPurify.sanitize(icon.trim())
2021
}
2122
}}
2223
/>

Diff for: packages/components/src/code-block/view/components/preview-panel.tsx

+6-4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
} from 'vue'
1010
import type { CodeBlockProps } from './code-block'
1111
import clsx from 'clsx'
12+
import DOMPurify from 'dompurify'
1213

1314
h
1415
Fragment
@@ -58,10 +59,11 @@ export const PreviewPanel = defineComponent<PreviewPanelProps>({
5859

5960
const previewContent = preview.value
6061

61-
if (typeof previewContent === 'string') {
62-
previewContainer.innerHTML = previewContent
63-
} else if (previewContent instanceof HTMLElement) {
64-
previewContainer.appendChild(previewContent)
62+
if (
63+
typeof previewContent === 'string' ||
64+
previewContent instanceof Element
65+
) {
66+
previewContainer.innerHTML = DOMPurify.sanitize(previewContent)
6567
}
6668
})
6769

Diff for: packages/components/src/image-block/view/index.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { imageBlockConfig } from '../config'
66
import { withMeta } from '../../__internal__/meta'
77
import { createApp, ref, watchEffect } from 'vue'
88
import { MilkdownImageBlock } from './components/image-block'
9+
import DOMPurify from 'dompurify'
910

1011
export const imageBlockView = $view(
1112
imageBlockSchema.node,
@@ -19,7 +20,13 @@ export const imageBlockView = $view(
1920
const setAttr = (attr: string, value: unknown) => {
2021
const pos = getPos()
2122
if (pos == null) return
22-
view.dispatch(view.state.tr.setNodeAttribute(pos, attr, value))
23+
view.dispatch(
24+
view.state.tr.setNodeAttribute(
25+
pos,
26+
attr,
27+
attr === 'src' ? DOMPurify.sanitize(value as string) : value
28+
)
29+
)
2330
}
2431
const config = ctx.get(imageBlockConfig.key)
2532
const app = createApp(MilkdownImageBlock, {

Diff for: packages/components/src/image-inline/view.ts

+11-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import { $view } from '@milkdown/utils'
22
import type { NodeViewConstructor } from '@milkdown/prose/view'
33
import { imageSchema } from '@milkdown/preset-commonmark'
44
import type { Node } from '@milkdown/prose/model'
5+
import { createApp, ref, watchEffect } from 'vue'
6+
import DOMPurify from 'dompurify'
7+
58
import { withMeta } from '../__internal__/meta'
69
import { inlineImageConfig } from './config'
7-
import { createApp, ref, watchEffect } from 'vue'
810
import { MilkdownImageInline } from './components/image-inline'
911

1012
export const inlineImageView = $view(
@@ -19,8 +21,15 @@ export const inlineImageView = $view(
1921
const setAttr = (attr: string, value: unknown) => {
2022
const pos = getPos()
2123
if (pos == null) return
22-
view.dispatch(view.state.tr.setNodeAttribute(pos, attr, value))
24+
view.dispatch(
25+
view.state.tr.setNodeAttribute(
26+
pos,
27+
attr,
28+
attr === 'src' ? DOMPurify.sanitize(value as string) : value
29+
)
30+
)
2331
}
32+
2433
const config = ctx.get(inlineImageConfig.key)
2534
const app = createApp(MilkdownImageInline, {
2635
src,

Diff for: packages/components/src/link-tooltip/edit/edit-view.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
} from '../slices'
1515
import { createApp, ref, type App, type Ref } from 'vue'
1616
import { EditLink } from './component'
17+
import DOMPurify from 'dompurify'
1718

1819
interface Data {
1920
from: number
@@ -80,15 +81,16 @@ export class LinkEditTooltip implements PluginView {
8081
const view = this.ctx.get(editorViewCtx)
8182
const { from, to, mark } = this.#data
8283
const type = linkSchema.type(this.ctx)
83-
if (mark && mark.attrs.href === href) {
84+
const link = DOMPurify.sanitize(href)
85+
if (mark && mark.attrs.href === link) {
8486
this.#reset()
8587
return
8688
}
8789

8890
const tr = view.state.tr
8991
if (mark) tr.removeMark(from, to, mark)
9092

91-
tr.addMark(from, to, type.create({ href }))
93+
tr.addMark(from, to, type.create({ href: link }))
9294
view.dispatch(tr)
9395

9496
this.#reset()

Diff for: pnpm-lock.yaml

+16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)