2024-04-07 06:16:54 +02:00
|
|
|
import { config } from "config-manager";
|
2024-05-03 02:21:09 +02:00
|
|
|
import DOMPurify from "dompurify";
|
2024-05-03 02:44:49 +02:00
|
|
|
import { Window } from "happy-dom";
|
|
|
|
|
|
|
|
|
|
const window = new Window();
|
2023-10-17 00:03:29 +02:00
|
|
|
|
2024-05-03 01:53:10 +02:00
|
|
|
export const sanitizeHtml = async (
|
|
|
|
|
html: string,
|
|
|
|
|
extraConfig?: DOMPurify.Config,
|
|
|
|
|
) => {
|
2024-05-03 02:44:49 +02:00
|
|
|
// @ts-expect-error Types clash but it works i swear
|
|
|
|
|
const sanitizedHtml = DOMPurify(window).sanitize(html, {
|
2024-04-07 07:30:49 +02:00
|
|
|
ALLOWED_TAGS: [
|
|
|
|
|
"a",
|
|
|
|
|
"p",
|
|
|
|
|
"br",
|
|
|
|
|
"b",
|
|
|
|
|
"i",
|
|
|
|
|
"em",
|
|
|
|
|
"strong",
|
|
|
|
|
"del",
|
|
|
|
|
"code",
|
|
|
|
|
"u",
|
|
|
|
|
"pre",
|
|
|
|
|
"ul",
|
|
|
|
|
"ol",
|
|
|
|
|
"li",
|
|
|
|
|
"blockquote",
|
|
|
|
|
],
|
|
|
|
|
ALLOWED_ATTR: [
|
|
|
|
|
"href",
|
|
|
|
|
"target",
|
|
|
|
|
"title",
|
|
|
|
|
"rel",
|
|
|
|
|
"class",
|
|
|
|
|
"start",
|
|
|
|
|
"reversed",
|
|
|
|
|
"value",
|
|
|
|
|
],
|
|
|
|
|
ALLOWED_URI_REGEXP: new RegExp(
|
|
|
|
|
`/^(?:(?:${config.validation.url_scheme_whitelist.join(
|
|
|
|
|
"|",
|
|
|
|
|
)}):|[^a-z]|[a-z+.-]+(?:[^a-z+.-:]|$))/i`,
|
|
|
|
|
),
|
|
|
|
|
USE_PROFILES: {
|
|
|
|
|
mathMl: true,
|
|
|
|
|
},
|
2024-05-03 01:25:32 +02:00
|
|
|
...extraConfig,
|
|
|
|
|
}) as string;
|
2023-10-17 00:03:29 +02:00
|
|
|
|
2024-04-07 07:30:49 +02:00
|
|
|
// Check text to only allow h-*, p-*, u-*, dt-*, e-*, mention, hashtag, ellipsis, invisible classes
|
|
|
|
|
const allowedClasses = [
|
|
|
|
|
"h-",
|
|
|
|
|
"p-",
|
|
|
|
|
"u-",
|
|
|
|
|
"dt-",
|
|
|
|
|
"e-",
|
|
|
|
|
"mention",
|
|
|
|
|
"hashtag",
|
|
|
|
|
"ellipsis",
|
|
|
|
|
"invisible",
|
|
|
|
|
];
|
2023-10-17 00:03:29 +02:00
|
|
|
|
2024-04-07 07:30:49 +02:00
|
|
|
return await new HTMLRewriter()
|
|
|
|
|
.on("*[class]", {
|
|
|
|
|
element(element) {
|
|
|
|
|
const classes = element.getAttribute("class")?.split(" ") ?? [];
|
2023-10-17 00:03:29 +02:00
|
|
|
|
2024-04-07 07:30:49 +02:00
|
|
|
for (const className of classes) {
|
|
|
|
|
if (
|
|
|
|
|
!allowedClasses.some((allowedClass) =>
|
|
|
|
|
className.startsWith(allowedClass),
|
|
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
element.removeAttribute("class");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
.transform(new Response(sanitizedHtml))
|
2024-05-03 01:25:32 +02:00
|
|
|
.text();
|
2023-10-17 00:03:29 +02:00
|
|
|
};
|