Improve rich text rendering to more closely match the recommendations from the spec
This commit is contained in:
parent
1a8427925c
commit
f46f9abe6e
1 changed files with 50 additions and 10 deletions
|
@ -4,28 +4,68 @@ const {resolveMxc} = require("../functions")
|
||||||
const {Event} = require("./event")
|
const {Event} = require("./event")
|
||||||
|
|
||||||
const purifier = DOMPurify()
|
const purifier = DOMPurify()
|
||||||
|
|
||||||
|
purifier.setConfig({
|
||||||
|
ALLOWED_URI_REGEXP: /^mxc:\/\/[a-zA-Z0-9\.]+\/[a-zA-Z0-9]+$/, // As per the spec we only allow mxc uris
|
||||||
|
ALLOWED_TAGS: ['font', 'del', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol', 'sup', 'sub', 'li', 'b', 'i', 'u', 'strong', 'em', 'strike', 'code', 'hr', 'br', 'div', 'table', 'thead', 'tbody', 'tr', 'th', 'td', 'caption', 'pre', 'span', 'img'],
|
||||||
|
|
||||||
|
// In case we mess up none of those attributes should read to XSS
|
||||||
|
ALLOWED_ATTR: ["data-mx-bg-color", "data-mx-color", "color",
|
||||||
|
"name", "target", "href",
|
||||||
|
"width", "height", "alt", "title", "src", "data-mx-emoticon",
|
||||||
|
"start", "class"],
|
||||||
|
//Custom config option that allows the array of attributes for a given tag
|
||||||
|
ALLOWED_ATTR_CUSTOM: {
|
||||||
|
"FONT": ["data-mx-bg-color", "data-mx-color", "color"],
|
||||||
|
"SPAN": ["data-mx-bg-color", "data-mx-color", "color"],
|
||||||
|
"A": ["name", "target", "href"],
|
||||||
|
"IMG": ["width", "height", "alt", "title", "src", "data-mx-emoticon"],
|
||||||
|
"OL": ["start"],
|
||||||
|
"CODE": ["class"],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
//Handle our custom tag
|
||||||
|
purifier.addHook("uponSanitizeAttribute", (node, hookevent, config) => {
|
||||||
|
//If purifier already rejected an attribute there is no point in checking it
|
||||||
|
if (hookevent.keepAttr === false) return;
|
||||||
|
|
||||||
|
const allowed_attributes = config.ALLOWED_ATTR_CUSTOM[node.tagName] || []
|
||||||
|
hookevent.keepAttr = allowed_attributes.indexOf(hookevent.attrName) > -1;
|
||||||
|
})
|
||||||
|
|
||||||
|
//Remove bad classes from our code element
|
||||||
|
purifier.addHook("uponSanitizeElement", (node, hookevent, config) => {
|
||||||
|
if (node.tagName != "CODE") return
|
||||||
|
node.classList.forEach(c => {
|
||||||
|
if (!c.startsWith("language-")) {
|
||||||
|
node.classList.remove(c)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return node
|
||||||
|
})
|
||||||
|
|
||||||
purifier.addHook("afterSanitizeAttributes", (node, hookevent, config) => {
|
purifier.addHook("afterSanitizeAttributes", (node, hookevent, config) => {
|
||||||
if (node.tagName == "img") {
|
if (node.tagName == "IMG") {
|
||||||
let src = node.getAttribute("src")
|
let src = node.getAttribute("src")
|
||||||
if (src) src = resolveMxc(src)
|
if (src) src = resolveMxc(src)
|
||||||
|
|
||||||
node.setAttribute("src", src)
|
node.setAttribute("src", src)
|
||||||
|
} else if (node.tagName == "A") {
|
||||||
}
|
|
||||||
if (node.tagName = "a") {
|
|
||||||
node.setAttribute("rel", "noopener")
|
node.setAttribute("rel", "noopener")
|
||||||
|
} else if (node.tagName == "FONT" || node.tagName == "SPAN") {
|
||||||
|
const color = node.getAttribute("data-mx-color")
|
||||||
|
const bgColor = node.getAttribute("data-mx-bg-color")
|
||||||
|
if (color) node.style.color = color;
|
||||||
|
if (bgColor) node.style.backgroundColor = bgColor;
|
||||||
}
|
}
|
||||||
return node
|
return node
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
function sanitize(html) {
|
function sanitize(html) {
|
||||||
return purifier.sanitize(html, DOMPURIFY_CONFIG)
|
return purifier.sanitize(html)
|
||||||
}
|
}
|
||||||
const DOMPURIFY_CONFIG = {
|
|
||||||
ALLOWED_URI_REGEXP: /^mxc:\/\/[a-zA-Z0-9\.]+\/[a-zA-Z0-9]+$/, // As per the spec we only allow mxc uris
|
|
||||||
ALLOWED_TAGS: ['font', 'del', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol', 'sup', 'sub', 'li', 'b', 'i', 'u', 'strong', 'em', 'strike', 'code', 'hr', 'br', 'div', 'table', 'thead', 'tbody', 'tr', 'th', 'td', 'caption', 'pre', 'span', 'img'],
|
|
||||||
};
|
|
||||||
|
|
||||||
class HTMLMessage extends Event {
|
class HTMLMessage extends Event {
|
||||||
render() {
|
render() {
|
||||||
|
|
Loading…
Reference in a new issue