Files
Epicnabbo-Catalogus-Updated…/src/lib/sanitize.ts
T
2026-07-13 21:57:41 +02:00

77 lines
1.5 KiB
TypeScript

import sanitizeHtml from "sanitize-html";
/**
* Server-side HTML sanitiser for user/staff-authored rich content before it is
* injected via dangerouslySetInnerHTML — the AtomCMS HTMLPurifier equivalent.
* Allows a safe formatting subset (no <script>/<style>/<iframe>, no on* event
* handlers, no javascript: URLs); images/links are permitted with safe schemes.
*/
const OPTIONS: sanitizeHtml.IOptions = {
allowedTags: [
"a",
"b",
"i",
"em",
"strong",
"u",
"s",
"p",
"br",
"hr",
"span",
"div",
"ul",
"ol",
"li",
"blockquote",
"code",
"pre",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"img",
"figure",
"figcaption",
"table",
"thead",
"tbody",
"tr",
"th",
"td",
],
allowedAttributes: {
a: ["href", "title", "target", "rel"],
img: ["src", "alt", "title", "width", "height"],
"*": ["style", "class"],
},
allowedSchemes: ["http", "https", "mailto"],
allowedSchemesByTag: { img: ["http", "https", "data"] },
// Drop any style declarations that aren't simple, safe properties.
allowedStyles: {
"*": {
color: [/.*/],
"background-color": [/.*/],
"text-align": [/^left$|^right$|^center$|^justify$/],
"font-weight": [/.*/],
"font-style": [/.*/],
"text-decoration": [/.*/],
"font-size": [/.*/],
margin: [/.*/],
padding: [/.*/],
},
},
transformTags: {
a: sanitizeHtml.simpleTransform("a", {
rel: "noopener noreferrer nofollow",
}),
},
};
export function sanitize(html: string | null | undefined): string {
if (!html) return "";
return sanitizeHtml(html, OPTIONS);
}