mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-11-05 23:10:28 +03:00
153 lines
3.3 KiB
JavaScript
153 lines
3.3 KiB
JavaScript
import sanitizeHtml from 'sanitize-html';
|
|
import initMatrix from '../../../client/initMatrix';
|
|
|
|
function sanitizeColorizedTag(tagName, attributes) {
|
|
const attribs = { ...attributes };
|
|
const styles = [];
|
|
if (attributes['data-mx-color']) {
|
|
styles.push(`color: ${attributes['data-mx-color']};`);
|
|
}
|
|
if (attributes['data-mx-bg-color']) {
|
|
styles.push(`background-color: ${attributes['data-mx-bg-color']};`);
|
|
}
|
|
attribs.style = styles.join(' ');
|
|
|
|
return { tagName, attribs };
|
|
}
|
|
|
|
function sanitizeLinkTag(tagName, attribs) {
|
|
const userLink = attribs.href.match(/^https?:\/\/matrix.to\/#\/(@.+:.+)/);
|
|
if (userLink !== null) {
|
|
// convert user link to pill
|
|
const userId = userLink[1];
|
|
return {
|
|
tagName: 'span',
|
|
attribs: {
|
|
'data-mx-pill': userId,
|
|
},
|
|
};
|
|
}
|
|
|
|
return {
|
|
tagName,
|
|
attribs: {
|
|
...attribs,
|
|
target: '_blank',
|
|
rel: 'noreferrer noopener',
|
|
},
|
|
};
|
|
}
|
|
|
|
function sanitizeCodeTag(tagName, attributes) {
|
|
const attribs = { ...attributes };
|
|
let classes = [];
|
|
if (attributes.class) {
|
|
classes = attributes.class.split(/\s+/).filter((className) => className.match(/^language-(\w+)/));
|
|
}
|
|
|
|
return {
|
|
tagName,
|
|
attribs: {
|
|
...attribs,
|
|
class: classes.join(' '),
|
|
},
|
|
};
|
|
}
|
|
|
|
function sanitizeImgTag(tagName, attributes) {
|
|
const mx = initMatrix.matrixClient;
|
|
const { src } = attributes;
|
|
const attribs = { ...attributes };
|
|
delete attribs.src;
|
|
|
|
if (src.match(/^mxc:\/\//)) {
|
|
attribs.src = mx.mxcUrlToHttp(src);
|
|
}
|
|
|
|
return { tagName, attribs };
|
|
}
|
|
|
|
export function sanitizeCustomHtml(body) {
|
|
return sanitizeHtml(body, {
|
|
allowedTags: [
|
|
'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',
|
|
'details',
|
|
'summary',
|
|
],
|
|
allowedClasses: {},
|
|
allowedAttributes: {
|
|
ol: ['start'],
|
|
img: ['width', 'height', 'alt', 'title', 'src', 'data-mx-emoticon'],
|
|
a: ['name', 'target', 'href', 'rel'],
|
|
code: ['class'],
|
|
font: ['data-mx-bg-color', 'data-mx-color', 'color', 'style'],
|
|
span: ['data-mx-bg-color', 'data-mx-color', 'data-mx-spoiler', 'style', 'data-mx-pill'],
|
|
},
|
|
allowProtocolRelative: false,
|
|
allowedSchemesByTag: {
|
|
a: ['https', 'http', 'ftp', 'mailto', 'magnet'],
|
|
img: ['https', 'http'],
|
|
},
|
|
allowedStyles: {
|
|
'*': {
|
|
color: [/^#(0x)?[0-9a-f]+$/i],
|
|
'background-color': [/^#(0x)?[0-9a-f]+$/i],
|
|
},
|
|
},
|
|
nestingLimit: 100,
|
|
nonTextTags: [
|
|
'style', 'script', 'textarea', 'option', 'mx-reply',
|
|
],
|
|
transformTags: {
|
|
a: sanitizeLinkTag,
|
|
img: sanitizeImgTag,
|
|
code: sanitizeCodeTag,
|
|
font: sanitizeColorizedTag,
|
|
span: sanitizeColorizedTag,
|
|
},
|
|
});
|
|
}
|
|
|
|
export function sanitizeText(body) {
|
|
const tagsToReplace = {
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>',
|
|
};
|
|
return body.replace(/[&<>]/g, (tag) => tagsToReplace[tag] || tag);
|
|
}
|