77 lines
1.5 KiB
TypeScript
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);
|
|
}
|