fix(extra) : preserve rich text colors
This commit is contained in:
@@ -15,6 +15,14 @@ describe("rich text sanitization", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("normalizes browser-generated RGB text colors to safe hex colors", () => {
|
||||
expect(sanitizeRichTextHtml(
|
||||
'<p><span style="color: rgb(0, 255, 0);">green</span> <span style="color: rgb(255, 204, 0)">yellow</span></p>',
|
||||
)).toBe(
|
||||
'<p><span style="color: #00FF00">green</span> <span style="color: #FFCC00">yellow</span></p>',
|
||||
);
|
||||
});
|
||||
|
||||
it("removes executable markup, unsafe links, and unsupported styles", () => {
|
||||
expect(sanitizeRichTextHtml(
|
||||
'<script>alert(1)</script><p onclick="bad()">Safe <span style="background:red;color:red">text</span><a href="javascript:bad()">link</a></p>',
|
||||
|
||||
+17
-3
@@ -22,6 +22,18 @@ const HTML_COMMENT = /<!--[\s\S]*?-->/g;
|
||||
const TAG = /<\/?([a-zA-Z][a-zA-Z0-9-]*)([^>]*)>/g;
|
||||
const ATTRIBUTE = /([a-zA-Z_:][a-zA-Z0-9_:.-]*)\s*=\s*("[^"]*"|'[^']*'|[^\s"'=<>`]+)/g;
|
||||
const HEX_COLOR = /^#[0-9a-fA-F]{6}$/;
|
||||
const RGB_COLOR = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i;
|
||||
|
||||
function normalizeRichTextColor(value: string): string | null {
|
||||
const color = value.trim();
|
||||
if (HEX_COLOR.test(color)) return color.toUpperCase();
|
||||
|
||||
const rgb = color.match(RGB_COLOR);
|
||||
if (!rgb) return null;
|
||||
const channels = rgb.slice(1).map(Number);
|
||||
if (channels.some((channel) => channel > 255)) return null;
|
||||
return `#${channels.map((channel) => channel.toString(16).padStart(2, "0")).join("")}`.toUpperCase();
|
||||
}
|
||||
|
||||
export function sanitizeRichTextUrl(value: string): string {
|
||||
const url = value.trim();
|
||||
@@ -75,9 +87,11 @@ export function sanitizeRichTextHtml(value: string): string {
|
||||
|
||||
if (name === "span") {
|
||||
const style = attributeValue(rawAttributes, "style");
|
||||
const color = style.match(/(?:^|;)\s*color\s*:\s*(#[0-9a-fA-F]{6})\s*(?:;|$)/)?.[1];
|
||||
return color && HEX_COLOR.test(color)
|
||||
? `<span style="color: ${color.toUpperCase()}">`
|
||||
const color = normalizeRichTextColor(
|
||||
style.match(/(?:^|;)\s*color\s*:\s*([^;]+?)\s*(?:;|$)/i)?.[1] ?? "",
|
||||
);
|
||||
return color
|
||||
? `<span style="color: ${color}">`
|
||||
: "<span>";
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user