do less rewriting for composer quote to prevent breaking pills
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
8bb08b1b75
commit
19e5dc5799
2 changed files with 113 additions and 101 deletions
|
@ -141,31 +141,7 @@ export function isUrlPermitted(inputUrl) {
|
|||
}
|
||||
}
|
||||
|
||||
const sanitizeHtmlParams = {
|
||||
allowedTags: [
|
||||
'font', // custom to matrix for IRC-style font coloring
|
||||
'del', // for markdown
|
||||
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol', 'sup', 'sub',
|
||||
'nl', 'li', 'b', 'i', 'u', 'strong', 'em', 'strike', 'code', 'hr', 'br', 'div',
|
||||
'table', 'thead', 'caption', 'tbody', 'tr', 'th', 'td', 'pre', 'span', 'img',
|
||||
],
|
||||
allowedAttributes: {
|
||||
// custom ones first:
|
||||
font: ['color', 'data-mx-bg-color', 'data-mx-color', 'style'], // custom to matrix
|
||||
span: ['data-mx-bg-color', 'data-mx-color', 'style'], // custom to matrix
|
||||
a: ['href', 'name', 'target', 'rel'], // remote target: custom to matrix
|
||||
img: ['src', 'width', 'height', 'alt', 'title'],
|
||||
ol: ['start'],
|
||||
code: ['class'], // We don't actually allow all classes, we filter them in transformTags
|
||||
},
|
||||
// Lots of these won't come up by default because we don't allow them
|
||||
selfClosing: ['img', 'br', 'hr', 'area', 'base', 'basefont', 'input', 'link', 'meta'],
|
||||
// URL schemes we permit
|
||||
allowedSchemes: PERMITTED_URL_SCHEMES,
|
||||
|
||||
allowProtocolRelative: false,
|
||||
|
||||
transformTags: { // custom to matrix
|
||||
const transformTags = { // custom to matrix
|
||||
// add blank targets to all hyperlinks except vector URLs
|
||||
'a': function(tagName, attribs) {
|
||||
if (attribs.href) {
|
||||
|
@ -198,7 +174,7 @@ const sanitizeHtmlParams = {
|
|||
}
|
||||
}
|
||||
attribs.rel = 'noopener'; // https://mathiasbynens.github.io/rel-noopener/
|
||||
return { tagName: tagName, attribs: attribs };
|
||||
return { tagName, attribs };
|
||||
},
|
||||
'img': function(tagName, attribs) {
|
||||
// Strip out imgs that aren't `mxc` here instead of using allowedSchemesByTag
|
||||
|
@ -212,7 +188,7 @@ const sanitizeHtmlParams = {
|
|||
attribs.width || 800,
|
||||
attribs.height || 600,
|
||||
);
|
||||
return { tagName: tagName, attribs: attribs };
|
||||
return { tagName, attribs };
|
||||
},
|
||||
'code': function(tagName, attribs) {
|
||||
if (typeof attribs.class !== 'undefined') {
|
||||
|
@ -222,10 +198,7 @@ const sanitizeHtmlParams = {
|
|||
});
|
||||
attribs.class = classes.join(' ');
|
||||
}
|
||||
return {
|
||||
tagName: tagName,
|
||||
attribs: attribs,
|
||||
};
|
||||
return { tagName, attribs };
|
||||
},
|
||||
'*': function(tagName, attribs) {
|
||||
// Delete any style previously assigned, style is an allowedTag for font and span
|
||||
|
@ -257,9 +230,41 @@ const sanitizeHtmlParams = {
|
|||
attribs.style = style;
|
||||
}
|
||||
|
||||
return { tagName: tagName, attribs: attribs };
|
||||
return { tagName, attribs };
|
||||
},
|
||||
};
|
||||
|
||||
const sanitizeHtmlParams = {
|
||||
allowedTags: [
|
||||
'font', // custom to matrix for IRC-style font coloring
|
||||
'del', // for markdown
|
||||
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol', 'sup', 'sub',
|
||||
'nl', 'li', 'b', 'i', 'u', 'strong', 'em', 'strike', 'code', 'hr', 'br', 'div',
|
||||
'table', 'thead', 'caption', 'tbody', 'tr', 'th', 'td', 'pre', 'span', 'img',
|
||||
],
|
||||
allowedAttributes: {
|
||||
// custom ones first:
|
||||
font: ['color', 'data-mx-bg-color', 'data-mx-color', 'style'], // custom to matrix
|
||||
span: ['data-mx-bg-color', 'data-mx-color', 'style'], // custom to matrix
|
||||
a: ['href', 'name', 'target', 'rel'], // remote target: custom to matrix
|
||||
img: ['src', 'width', 'height', 'alt', 'title'],
|
||||
ol: ['start'],
|
||||
code: ['class'], // We don't actually allow all classes, we filter them in transformTags
|
||||
},
|
||||
// Lots of these won't come up by default because we don't allow them
|
||||
selfClosing: ['img', 'br', 'hr', 'area', 'base', 'basefont', 'input', 'link', 'meta'],
|
||||
// URL schemes we permit
|
||||
allowedSchemes: PERMITTED_URL_SCHEMES,
|
||||
|
||||
allowProtocolRelative: false,
|
||||
transformTags,
|
||||
};
|
||||
|
||||
// this is the same as the above except with less rewriting
|
||||
const composerSanitizeHtmlParams = Object.assign({}, sanitizeHtmlParams);
|
||||
composerSanitizeHtmlParams.transformTags = {
|
||||
'code': transformTags['code'],
|
||||
'*': transformTags['*'],
|
||||
};
|
||||
|
||||
class BaseHighlighter {
|
||||
|
@ -385,6 +390,7 @@ class TextHighlighter extends BaseHighlighter {
|
|||
* opts.stripReplyFallback: optional argument specifying the event is a reply and so fallback needs removing
|
||||
* opts.returnString: return an HTML string rather than JSX elements
|
||||
* opts.emojiOne: optional param to do emojiOne (default true)
|
||||
* opts.forComposerQuote: optional param to lessen the url rewriting done by sanitization, for quoting into composer
|
||||
*/
|
||||
export function bodyToHtml(content, highlights, opts={}) {
|
||||
const isHtmlMessage = content.format === "org.matrix.custom.html" && content.formatted_body;
|
||||
|
@ -392,6 +398,11 @@ export function bodyToHtml(content, highlights, opts={}) {
|
|||
const doEmojiOne = opts.emojiOne === undefined ? true : opts.emojiOne;
|
||||
let bodyHasEmoji = false;
|
||||
|
||||
let sanitizeParams = sanitizeHtmlParams;
|
||||
if (opts.forComposerQuote) {
|
||||
sanitizeParams = composerSanitizeHtmlParams;
|
||||
}
|
||||
|
||||
let strippedBody;
|
||||
let safeBody;
|
||||
let isDisplayedWithHtml;
|
||||
|
@ -403,10 +414,10 @@ export function bodyToHtml(content, highlights, opts={}) {
|
|||
if (highlights && highlights.length > 0) {
|
||||
const highlighter = new HtmlHighlighter("mx_EventTile_searchHighlight", opts.highlightLink);
|
||||
const safeHighlights = highlights.map(function(highlight) {
|
||||
return sanitizeHtml(highlight, sanitizeHtmlParams);
|
||||
return sanitizeHtml(highlight, sanitizeParams);
|
||||
});
|
||||
// XXX: hacky bodge to temporarily apply a textFilter to the sanitizeHtmlParams structure.
|
||||
sanitizeHtmlParams.textFilter = function(safeText) {
|
||||
// XXX: hacky bodge to temporarily apply a textFilter to the sanitizeParams structure.
|
||||
sanitizeParams.textFilter = function(safeText) {
|
||||
return highlighter.applyHighlights(safeText, safeHighlights).join('');
|
||||
};
|
||||
}
|
||||
|
@ -422,13 +433,13 @@ export function bodyToHtml(content, highlights, opts={}) {
|
|||
// Only generate safeBody if the message was sent as org.matrix.custom.html
|
||||
if (isHtmlMessage) {
|
||||
isDisplayedWithHtml = true;
|
||||
safeBody = sanitizeHtml(formattedBody, sanitizeHtmlParams);
|
||||
safeBody = sanitizeHtml(formattedBody, sanitizeParams);
|
||||
} else {
|
||||
// ... or if there are emoji, which we insert as HTML alongside the
|
||||
// escaped plaintext body.
|
||||
if (bodyHasEmoji) {
|
||||
isDisplayedWithHtml = true;
|
||||
safeBody = sanitizeHtml(escape(strippedBody), sanitizeHtmlParams);
|
||||
safeBody = sanitizeHtml(escape(strippedBody), sanitizeParams);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -439,7 +450,7 @@ export function bodyToHtml(content, highlights, opts={}) {
|
|||
safeBody = unicodeToImage(safeBody);
|
||||
}
|
||||
} finally {
|
||||
delete sanitizeHtmlParams.textFilter;
|
||||
delete sanitizeParams.textFilter;
|
||||
}
|
||||
|
||||
if (opts.returnString) {
|
||||
|
|
|
@ -373,6 +373,7 @@ export default class MessageComposerInput extends React.Component {
|
|||
break;
|
||||
case 'quote': {
|
||||
const html = HtmlUtils.bodyToHtml(payload.event.getContent(), null, {
|
||||
forComposerQuote: true,
|
||||
returnString: true,
|
||||
emojiOne: false,
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue