Use data-mx[-bg]-color instead of stripping style

This has the benefit of not needing a spec for custom CSS. Instead we rigourously sanitise the values for custom data attributes that are transformed to CSS equivalents. `data-mx-color` translates to CSS `color` for example.
This commit is contained in:
Luke Barnard 2017-03-02 11:36:56 +00:00
parent 5fc828f24c
commit 36795fa192

View file

@ -96,8 +96,8 @@ var sanitizeHtmlParams = {
], ],
allowedAttributes: { allowedAttributes: {
// custom ones first: // custom ones first:
font: ['color', 'style'], // custom to matrix font: ['color', 'data-mx-bg-color', 'data-mx-color', 'style'], // custom to matrix
span: ['style'], span: ['data-mx-bg-color', 'data-mx-color', 'style'], // custom to matrix
a: ['href', 'name', 'target', 'rel'], // remote target: custom to matrix a: ['href', 'name', 'target', 'rel'], // remote target: custom to matrix
// We don't currently allow img itself by default, but this // We don't currently allow img itself by default, but this
// would make sense if we did // would make sense if we did
@ -143,28 +143,31 @@ var sanitizeHtmlParams = {
return { tagName: tagName, attribs : attribs }; return { tagName: tagName, attribs : attribs };
}, },
'*': function(tagName, attribs) { '*': function(tagName, attribs) {
// Only allow certain CSS attributes to avoid XSS attacks // Delete any style previously assigned
// Sanitizing values to avoid `url(...)` and `expression(...)` attacks delete attribs.style;
if (!attribs.style) {
return { tagName: tagName, attribs: attribs };
}
const pairs = attribs.style.split(';'); // Sanitise and transform data-mx-color and data-mx-bg-color to their CSS
let sanitisedStyle = ""; // equivalents
for (let i = 0; i < pairs.length; i++) { const customCSSMapper = {
const pair = pairs[i].split(':'); 'data-mx-color': 'color',
if (!Object.keys(ALLOWED_CSS).includes(pair[0]) || 'data-mx-bg-color': 'background-color',
!ALLOWED_CSS[pair[0]].test(pair[1]) // $customAttributeKey: $cssAttributeKey
};
let style = "";
Object.keys(customCSSMapper).forEach((customAttributeKey) => {
const cssAttributeKey = customCSSMapper[customAttributeKey];
const customAttributeValue = attribs[customAttributeKey];
if (customAttributeValue &&
typeof customAttributeValue === 'string' &&
/#[0-9a-fA-F]{6}/.test(customAttributeValue)
) { ) {
continue; style += cssAttributeKey + ":" + customAttributeValue + ";";
} }
sanitisedStyle += pair[0] + ":" + pair[1] + ";"; });
}
if (sanitisedStyle) { if (style) {
attribs.style = sanitisedStyle; attribs.style = style;
} else {
delete attribs.style;
} }
return { tagName: tagName, attribs: attribs }; return { tagName: tagName, attribs: attribs };