Checkpoint React frontend migration
This commit is contained in:
64
frontend/src/components/SafeHtml.tsx
Normal file
64
frontend/src/components/SafeHtml.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
import DOMPurify from 'dompurify'
|
||||
import type { Config, UponSanitizeElementHook } from 'dompurify'
|
||||
|
||||
type SafeHtmlProps = {
|
||||
html: string | null | undefined
|
||||
className?: string
|
||||
allowEmbeds?: boolean
|
||||
}
|
||||
|
||||
const ALLOWED_EMBED_HOSTS = new Set(['videos.cdn.spotlightr.com'])
|
||||
|
||||
function isAllowedEmbedSrc(src: string | null) {
|
||||
if (!src) return false
|
||||
|
||||
try {
|
||||
const url = new URL(src, 'https://invalid.local')
|
||||
return url.protocol === 'https:' && ALLOWED_EMBED_HOSTS.has(url.hostname)
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function sanitizeHtml(html: string | null | undefined, allowEmbeds: boolean) {
|
||||
const config: Config = {
|
||||
USE_PROFILES: { html: true },
|
||||
ADD_ATTR: allowEmbeds
|
||||
? ['style', 'allow', 'allowfullscreen', 'allowtransparency', 'frameborder', 'scrolling', 'name', 'src']
|
||||
: ['style'],
|
||||
}
|
||||
|
||||
if (!allowEmbeds) {
|
||||
return DOMPurify.sanitize(html ?? '', config)
|
||||
}
|
||||
|
||||
const removeUntrustedIframe: UponSanitizeElementHook = (currentNode) => {
|
||||
if (
|
||||
currentNode instanceof HTMLIFrameElement &&
|
||||
!isAllowedEmbedSrc(currentNode.getAttribute('src'))
|
||||
) {
|
||||
currentNode.remove()
|
||||
}
|
||||
}
|
||||
|
||||
DOMPurify.addHook('uponSanitizeElement', removeUntrustedIframe)
|
||||
try {
|
||||
return DOMPurify.sanitize(html ?? '', {
|
||||
...config,
|
||||
ADD_TAGS: ['iframe'],
|
||||
})
|
||||
} finally {
|
||||
DOMPurify.removeHook('uponSanitizeElement', removeUntrustedIframe)
|
||||
}
|
||||
}
|
||||
|
||||
export function SafeHtml({ html, className, allowEmbeds = false }: SafeHtmlProps) {
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: sanitizeHtml(html, allowEmbeds),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user