fix(frontend): remove isomorphic-dompurify for Cloudflare Workers compatibility

This commit is contained in:
2026-03-11 21:52:22 +08:00
parent cbe44ffd36
commit c0f7ad7458
2 changed files with 32 additions and 56 deletions

View File

@@ -18,8 +18,7 @@
"agentation": "^2.1.1",
"agentation-mcp": "^1.1.0",
"astro": "6.0.0-beta.17",
"better-auth": "^1.3.13",
"isomorphic-dompurify": "^3.0.0"
"better-auth": "^1.3.13"
},
"devDependencies": {
"@astrojs/check": "^0.9.6",

View File

@@ -1,64 +1,41 @@
/**
* SVG sanitization utilities
* Prevents XSS attacks from user-provided SVG content
*
* Note: Uses basic regex-based sanitization for Cloudflare Workers compatibility
* DOMPurify doesn't work in Workers due to lack of DOM APIs
*/
import DOMPurify from 'isomorphic-dompurify'
/**
* Basic SVG sanitization for environments without DOM
* Removes dangerous tags and attributes
*/
const basicSanitize = (svg: string): string => {
// Remove script tags and their content
let sanitized = svg.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
// Remove dangerous attributes
sanitized = sanitized.replace(/\s*on\w+\s*=\s*["'][^"']*["']/gi, '')
// Remove other dangerous tags
sanitized = sanitized.replace(/<(iframe|object|embed|style)[^>]*>.*?<\/\1>/gi, '')
return sanitized
}
/**
* Sanitize SVG content to prevent XSS attacks
* Only allows safe SVG elements and attributes
* SVG sanitization - removes dangerous tags and attributes
* Suitable for Cloudflare Workers environment
*/
export const sanitizeSvg = (svg: string): string => {
// Check if DOMPurify is available (has sanitize method)
if (typeof DOMPurify?.sanitize === 'function') {
try {
return DOMPurify.sanitize(svg, {
USE_PROFILES: { svg: true, svgFilters: true },
ADD_TAGS: ['use', 'defs', 'symbol'],
ADD_ATTR: [
'viewBox',
'fill',
'class',
'stroke',
'stroke-width',
'd',
'cx',
'cy',
'r',
'x',
'y',
'width',
'height',
'transform',
'xmlns',
'xmlns:xlink',
'xlink:href',
'preserveAspectRatio',
'clip-rule',
'fill-rule',
],
FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'style'],
FORBID_ATTR: ['onload', 'onerror', 'onclick', 'onmouseover'],
})
} catch {
// Fallback to basic sanitization if DOMPurify fails
return basicSanitize(svg)
}
if (!svg || typeof svg !== 'string') {
return ''
}
// Fallback for non-browser environments (Cloudflare Workers)
return basicSanitize(svg)
let sanitized = svg
// Remove script tags and their content
sanitized = sanitized.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
// Remove dangerous tags and their content
sanitized = sanitized.replace(/<(iframe|object|embed|style|link|meta|base)[^>]*>.*?<\/\1>/gi, '')
sanitized = sanitized.replace(/<(iframe|object|embed|style|link|meta|base)[^>]*\/?>/gi, '')
// Remove event handlers (onclick, onload, onerror, etc.)
sanitized = sanitized.replace(/\s+on\w+\s*=\s*["'][^"']*["']/gi, '')
sanitized = sanitized.replace(/\s+on\w+\s*=\s*[^\s>]+/gi, '')
// Remove javascript: URLs
sanitized = sanitized.replace(/javascript\s*:/gi, '')
// Remove data: URLs (except for images which are safe in SVGs)
sanitized = sanitized.replace(/(?<!image\/)data\s*:/gi, '')
// Remove style attributes that could contain expressions
sanitized = sanitized.replace(/\s+style\s*=\s*["'][^"']*expression[^"']*["']/gi, '')
return sanitized
}