fix: sanitize v-html inputs with DOMPurify (#573)

This commit is contained in:
Makito
2025-09-11 13:33:12 +08:00
committed by GitHub
parent 1ad5d50e8d
commit 3315634903
9 changed files with 51 additions and 8 deletions
@@ -1,6 +1,8 @@
<script setup lang="ts">
import type { AiriCard } from '@proj-airi/stage-ui/stores/modules/airi-card'
import DOMPurify from 'dompurify'
import { Button } from '@proj-airi/stage-ui/components'
import { useAiriCardStore } from '@proj-airi/stage-ui/stores/modules/airi-card'
import { storeToRefs } from 'pinia'
@@ -84,7 +86,7 @@ function handleActivate() {
}
function highlightTagToHtml(text: string) {
return text?.replace(/\{\{(.*?)\}\}/g, '<span class="bg-primary-500/20 inline-block">{{ $1 }}</span>').trim()
return DOMPurify.sanitize(text?.replace(/\{\{(.*?)\}\}/g, '<span class="bg-primary-500/20 inline-block">{{ $1 }}</span>').trim())
}
// Delete confirmation
+1
View File
@@ -56,6 +56,7 @@
"colorjs.io": "^0.5.2",
"culori": "^4.0.2",
"date-fns": "^4.1.0",
"dompurify": "^3.2.6",
"drizzle-kit": "^0.31.4",
"drizzle-orm": "^0.44.5",
"jszip": "^3.10.1",
@@ -1,6 +1,8 @@
<script setup lang="ts">
import type { AiriCard } from '@proj-airi/stage-ui/stores/modules/airi-card'
import DOMPurify from 'dompurify'
import { Button } from '@proj-airi/stage-ui/components'
import { useAiriCardStore } from '@proj-airi/stage-ui/stores/modules/airi-card'
import { storeToRefs } from 'pinia'
@@ -84,7 +86,7 @@ function handleActivate() {
}
function highlightTagToHtml(text: string) {
return text?.replace(/\{\{(.*?)\}\}/g, '<span class="bg-primary-500/20 inline-block">{{ $1 }}</span>').trim()
return DOMPurify.sanitize(text?.replace(/\{\{(.*?)\}\}/g, '<span class="bg-primary-500/20 inline-block">{{ $1 }}</span>').trim())
}
// Delete confirmation
+1
View File
@@ -55,6 +55,7 @@
"colorjs.io": "^0.5.2",
"culori": "^4.0.2",
"date-fns": "^4.1.0",
"dompurify": "^3.2.6",
"driver.js": "^1.3.6",
"drizzle-kit": "^0.31.4",
"drizzle-orm": "^0.44.5",
@@ -1,6 +1,8 @@
<script setup lang="ts">
import type { AiriCard } from '@proj-airi/stage-ui/stores/modules/airi-card'
import DOMPurify from 'dompurify'
import { Button } from '@proj-airi/stage-ui/components'
import { useAiriCardStore } from '@proj-airi/stage-ui/stores/modules/airi-card'
import { storeToRefs } from 'pinia'
@@ -84,7 +86,7 @@ function handleActivate() {
}
function highlightTagToHtml(text: string) {
return text?.replace(/\{\{(.*?)\}\}/g, '<span class="bg-primary-500/20 inline-block">{{ $1 }}</span>').trim()
return DOMPurify.sanitize(text?.replace(/\{\{(.*?)\}\}/g, '<span class="bg-primary-500/20 inline-block">{{ $1 }}</span>').trim())
}
// Delete confirmation
+1
View File
@@ -71,6 +71,7 @@ words:
- devlogs
- directml
- dokidoki
- dompurify
- dotenvx
- DownloadLive2DSDK
- dreamlog
+1
View File
@@ -93,6 +93,7 @@
"animejs": "^4.1.3",
"culori": "^4.0.2",
"date-fns": "^4.1.0",
"dompurify": "^3.2.6",
"gpuu": "^1.0.4",
"jszip": "^3.10.1",
"localforage": "^1.10.0",
@@ -1,4 +1,6 @@
<script setup lang="ts">
import DOMPurify from 'dompurify'
import { onMounted, ref, watch } from 'vue'
import { useMarkdown } from '../composables/markdown'
@@ -20,11 +22,11 @@ async function processContent() {
}
try {
processedContent.value = await process(props.content)
processedContent.value = DOMPurify.sanitize(await process(props.content))
}
catch (error) {
console.warn('Failed to process markdown with syntax highlighting, using fallback:', error)
processedContent.value = processSync(props.content)
processedContent.value = DOMPurify.sanitize(processSync(props.content))
}
}
+34 -3
View File
@@ -284,7 +284,7 @@ importers:
version: rolldown-vite@7.1.5(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)
vite-plugin-vue-devtools:
specifier: ^8.0.1
version: 8.0.1(@nuxt/kit@4.0.3(magicast@0.3.5))(rolldown-vite@7.1.5(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
version: 8.0.1(rolldown-vite@7.1.5(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
vite-plugin-vue-layouts:
specifier: ^0.11.0
version: 0.11.0(rolldown-vite@7.1.5(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(vue-router@4.5.1(vue@3.5.21(typescript@5.9.2)))(vue@3.5.21(typescript@5.9.2))
@@ -454,6 +454,9 @@ importers:
date-fns:
specifier: ^4.1.0
version: 4.1.0
dompurify:
specifier: ^3.2.6
version: 3.2.6
drizzle-kit:
specifier: ^0.31.4
version: 0.31.4
@@ -1164,6 +1167,9 @@ importers:
date-fns:
specifier: ^4.1.0
version: 4.1.0
dompurify:
specifier: ^3.2.6
version: 3.2.6
driver.js:
specifier: ^1.3.6
version: 1.3.6
@@ -1768,6 +1774,9 @@ importers:
date-fns:
specifier: ^4.1.0
version: 4.1.0
dompurify:
specifier: ^3.2.6
version: 3.2.6
gpuu:
specifier: ^1.0.4
version: 1.0.4
@@ -2023,7 +2032,7 @@ importers:
version: rolldown-vite@7.1.5(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)
vite-plugin-vue-devtools:
specifier: ^8.0.1
version: 8.0.1(@nuxt/kit@4.0.3(magicast@0.3.5))(rolldown-vite@7.1.5(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
version: 8.0.1(rolldown-vite@7.1.5(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
vue-router:
specifier: ^4.5.1
version: 4.5.1(vue@3.5.21(typescript@5.9.2))
@@ -2057,7 +2066,7 @@ importers:
version: rolldown-vite@7.1.5(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)
vite-plugin-vue-devtools:
specifier: ^8.0.1
version: 8.0.1(@nuxt/kit@4.0.3(magicast@0.3.5))(rolldown-vite@7.1.5(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
version: 8.0.1(rolldown-vite@7.1.5(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
vue-router:
specifier: ^4.5.1
version: 4.5.1(vue@3.5.21(typescript@5.9.2))
@@ -9588,6 +9597,9 @@ packages:
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
engines: {node: '>= 4'}
dompurify@3.2.6:
resolution: {integrity: sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==}
domutils@2.8.0:
resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==}
@@ -25071,6 +25083,10 @@ snapshots:
dependencies:
domelementtype: 2.3.0
dompurify@3.2.6:
optionalDependencies:
'@types/trusted-types': 2.0.7
domutils@2.8.0:
dependencies:
dom-serializer: 1.4.1
@@ -33075,6 +33091,21 @@ snapshots:
- supports-color
- vue
vite-plugin-vue-devtools@8.0.1(rolldown-vite@7.1.5(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2)):
dependencies:
'@vue/devtools-core': 8.0.1(rolldown-vite@7.1.5(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
'@vue/devtools-kit': 8.0.1
'@vue/devtools-shared': 8.0.1
execa: 9.6.0
sirv: 3.0.1
vite: rolldown-vite@7.1.5(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)
vite-plugin-inspect: 11.3.3(@nuxt/kit@3.18.1(magicast@0.3.5))(rolldown-vite@7.1.5(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))
vite-plugin-vue-inspector: 5.3.2(rolldown-vite@7.1.5(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1))
transitivePeerDependencies:
- '@nuxt/kit'
- supports-color
- vue
vite-plugin-vue-inspector@5.3.2(rolldown-vite@7.1.5(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1)):
dependencies:
'@babel/core': 7.28.3