fix(frontend): add fallback for DOMPurify in Cloudflare Workers

This commit is contained in:
2026-03-11 21:47:16 +08:00
parent acc23b13b6
commit cbe44ffd36

View File

@@ -4,37 +4,61 @@
*/ */
import DOMPurify from 'isomorphic-dompurify' 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 * Sanitize SVG content to prevent XSS attacks
* Only allows safe SVG elements and attributes * Only allows safe SVG elements and attributes
*/ */
export const sanitizeSvg = (svg: string): string => { export const sanitizeSvg = (svg: string): string => {
return DOMPurify.sanitize(svg, { // Check if DOMPurify is available (has sanitize method)
USE_PROFILES: { svg: true, svgFilters: true }, if (typeof DOMPurify?.sanitize === 'function') {
ADD_TAGS: ['use', 'defs', 'symbol'], try {
ADD_ATTR: [ return DOMPurify.sanitize(svg, {
'viewBox', USE_PROFILES: { svg: true, svgFilters: true },
'fill', ADD_TAGS: ['use', 'defs', 'symbol'],
'class', ADD_ATTR: [
'stroke', 'viewBox',
'stroke-width', 'fill',
'd', 'class',
'cx', 'stroke',
'cy', 'stroke-width',
'r', 'd',
'x', 'cx',
'y', 'cy',
'width', 'r',
'height', 'x',
'transform', 'y',
'xmlns', 'width',
'xmlns:xlink', 'height',
'xlink:href', 'transform',
'preserveAspectRatio', 'xmlns',
'clip-rule', 'xmlns:xlink',
'fill-rule', 'xlink:href',
], 'preserveAspectRatio',
FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'style'], 'clip-rule',
FORBID_ATTR: ['onload', 'onerror', 'onclick', 'onmouseover'], '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)
}
}
// Fallback for non-browser environments (Cloudflare Workers)
return basicSanitize(svg)
} }