diff --git a/src/services/html_sanitizer.spec.ts b/src/services/html_sanitizer.spec.ts
new file mode 100644
index 000000000..7f5888380
--- /dev/null
+++ b/src/services/html_sanitizer.spec.ts
@@ -0,0 +1,53 @@
+import { describe, expect, it } from "vitest";
+import html_sanitizer from "./html_sanitizer.js";
+import { trimIndentation } from "../../spec/support/utils.js";
+
+describe("sanitize", () => {
+ it("filters out position inline CSS", () => {
+ const dirty = `
`;
+ const clean = ``;
+ expect(html_sanitizer.sanitize(dirty)).toBe(clean);
+ });
+
+ it("keeps inline styles defined in CKEDitor", () => {
+ const dirty = trimIndentation`\
+
+
+ Hi
+
+
+
+ there
+
+
+
+
+ `;
+ const clean = trimIndentation`\
+
+
+ Hi
+
+
+
+ there
+
+
+
+
+ `;
+ expect(html_sanitizer.sanitize(dirty)) .toBe(clean);
+ });
+});
diff --git a/src/services/html_sanitizer.ts b/src/services/html_sanitizer.ts
index 3acfde469..35e04c0b7 100644
--- a/src/services/html_sanitizer.ts
+++ b/src/services/html_sanitizer.ts
@@ -141,6 +141,9 @@ function sanitize(dirtyHtml: string) {
allowedTags = DEFAULT_ALLOWED_TAGS;
}
+ const colorRegex = [/^#(0x)?[0-9a-f]+$/i, /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/, /^hsl\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*\)$/];
+ const sizeRegex = [/^\d+(?:px|em|%)$/];
+
// to minimize document changes, compress H
return sanitizeHtml(dirtyHtml, {
allowedTags,
@@ -148,6 +151,24 @@ function sanitize(dirtyHtml: string) {
"*": ["class", "style", "title", "src", "href", "hash", "disabled", "align", "alt", "center", "data-*"],
input: ["type", "checked"]
},
+ allowedStyles: {
+ "*": {
+ "color": colorRegex,
+ "background-color": colorRegex
+ },
+ "figure": {
+ "float": [ /^\s*(left|right|none)\s*$/ ],
+ "width": sizeRegex,
+ "height": sizeRegex
+ },
+ "table": {
+ "border-color": colorRegex,
+ "border-style": [ /^\s*(none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset)\s*$/ ]
+ },
+ "td": {
+ "border": [ /^\s*\d+(?:px|em|%)\s*(none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset)\s*(#(0x)?[0-9a-fA-F]+|rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)|hsl\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\))\s*$/ ]
+ }
+ },
allowedSchemes: ALLOWED_PROTOCOLS,
nonTextTags: ["head"],
transformTags