Escape html with markdown off (#732)

This commit is contained in:
Ajay Bura 2022-08-11 14:28:39 +05:30
parent 1692098d5d
commit 3c1cc59d59
3 changed files with 42 additions and 39 deletions

View file

@ -206,7 +206,13 @@ const MessageBody = React.memo(({
let content = null; let content = null;
if (isCustomHTML) { if (isCustomHTML) {
try { try {
content = twemojify(sanitizeCustomHtml(body), undefined, true, false, true); content = twemojify(
sanitizeCustomHtml(initMatrix.matrixClient, body),
undefined,
true,
false,
true,
);
} catch { } catch {
console.error('Malformed custom html: ', body); console.error('Malformed custom html: ', body);
content = twemojify(body, undefined); content = twemojify(body, undefined);

View file

@ -6,6 +6,7 @@ import { math } from 'micromark-extension-math';
import { encode } from 'blurhash'; import { encode } from 'blurhash';
import { getShortcodeToEmoji } from '../../app/organisms/emoji-board/custom-emoji'; import { getShortcodeToEmoji } from '../../app/organisms/emoji-board/custom-emoji';
import { mathExtensionHtml, spoilerExtension, spoilerExtensionHtml } from '../../util/markdown'; import { mathExtensionHtml, spoilerExtension, spoilerExtensionHtml } from '../../util/markdown';
import { sanitizeText } from '../../util/sanitize';
import cons from './cons'; import cons from './cons';
import settings from './settings'; import settings from './settings';
@ -148,29 +149,25 @@ function findAndReplace(text, regex, filter, replace) {
return copyText; return copyText;
} }
function formatAndEmojifyText(mx, roomList, room, text) { function formatUserPill(room, text) {
const { userIdsToDisplayNames } = room.currentState; const { userIdsToDisplayNames } = room.currentState;
const parentIds = roomList.getAllParentSpaces(room.roomId); return findAndReplace(
const parentRooms = [...parentIds].map((id) => mx.getRoom(id)); text,
const allEmoji = getShortcodeToEmoji(mx, [room, ...parentRooms]);
let formattedText;
if (settings.isMarkdown) {
formattedText = getFormattedBody(text);
} else {
formattedText = text;
}
formattedText = findAndReplace(
formattedText,
MXID_REGEX, MXID_REGEX,
(match) => userIdsToDisplayNames[match[0]], (match) => userIdsToDisplayNames[match[0]],
(match) => ( (match) => (
`<a href="https://matrix.to/#/${match[0]}">@${userIdsToDisplayNames[match[0]]}</a>` `<a href="https://matrix.to/#/${match[0]}">@${userIdsToDisplayNames[match[0]]}</a>`
), ),
); );
formattedText = findAndReplace( }
formattedText,
function formatEmoji(mx, room, roomList, text) {
const parentIds = roomList.getAllParentSpaces(room.roomId);
const parentRooms = [...parentIds].map((id) => mx.getRoom(id));
const allEmoji = getShortcodeToEmoji(mx, [room, ...parentRooms]);
return findAndReplace(
text,
SHORTCODE_REGEX, SHORTCODE_REGEX,
(match) => allEmoji.has(match[1]), (match) => allEmoji.has(match[1]),
(match) => { (match) => {
@ -191,8 +188,6 @@ function formatAndEmojifyText(mx, roomList, room, text) {
return tag; return tag;
}, },
); );
return formattedText;
} }
class RoomsInput extends EventEmitter { class RoomsInput extends EventEmitter {
@ -295,25 +290,27 @@ class RoomsInput extends EventEmitter {
} }
if (this.getMessage(roomId).trim() !== '') { if (this.getMessage(roomId).trim() !== '') {
const rawMessage = input.message;
let content = { let content = {
body: input.message, body: rawMessage,
msgtype: 'm.text', msgtype: 'm.text',
}; };
// Apply formatting if relevant // Apply formatting if relevant
const formattedBody = formatAndEmojifyText( let formattedBody = settings.isMarkdown
this.matrixClient, ? getFormattedBody(rawMessage)
this.roomList, : sanitizeText(rawMessage);
room,
input.message, formattedBody = formatUserPill(room, formattedBody);
); formattedBody = formatEmoji(this.matrixClient, room, this.roomList, formattedBody);
content.body = findAndReplace( content.body = findAndReplace(
content.body, content.body,
MXID_REGEX, MXID_REGEX,
(match) => room.currentState.userIdsToDisplayNames[match[0]], (match) => room.currentState.userIdsToDisplayNames[match[0]],
(match) => `@${room.currentState.userIdsToDisplayNames[match[0]]}`, (match) => `@${room.currentState.userIdsToDisplayNames[match[0]]}`,
); );
if (formattedBody !== input.message) { if (formattedBody !== sanitizeText(rawMessage)) {
// Formatting was applied, and we need to switch to custom HTML // Formatting was applied, and we need to switch to custom HTML
content.format = 'org.matrix.custom.html'; content.format = 'org.matrix.custom.html';
content.formatted_body = formattedBody; content.formatted_body = formattedBody;
@ -481,19 +478,19 @@ class RoomsInput extends EventEmitter {
}; };
// Apply formatting if relevant // Apply formatting if relevant
const formattedBody = formatAndEmojifyText( let formattedBody = settings.isMarkdown
this.matrixClient, ? getFormattedBody(editedBody)
this.roomList, : sanitizeText(editedBody);
room, formattedBody = formatUserPill(room, formattedBody);
editedBody, formattedBody = formatEmoji(this.matrixClient, room, this.roomList, formattedBody);
);
content.body = findAndReplace( content.body = findAndReplace(
content.body, content.body,
MXID_REGEX, MXID_REGEX,
(match) => room.currentState.userIdsToDisplayNames[match[0]], (match) => room.currentState.userIdsToDisplayNames[match[0]],
(match) => `@${room.currentState.userIdsToDisplayNames[match[0]]}`, (match) => `@${room.currentState.userIdsToDisplayNames[match[0]]}`,
); );
if (formattedBody !== editedBody) { if (formattedBody !== sanitizeText(editedBody)) {
content.formatted_body = ` * ${formattedBody}`; content.formatted_body = ` * ${formattedBody}`;
content.format = 'org.matrix.custom.html'; content.format = 'org.matrix.custom.html';
content['m.new_content'].formatted_body = formattedBody; content['m.new_content'].formatted_body = formattedBody;

View file

@ -1,7 +1,7 @@
import sanitizeHtml from 'sanitize-html'; import sanitizeHtml from 'sanitize-html';
import initMatrix from '../client/initMatrix';
const MAX_TAG_NESTING = 100; const MAX_TAG_NESTING = 100;
let mx = null;
const permittedHtmlTags = [ const permittedHtmlTags = [
'font', 'del', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'font', 'del', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
@ -54,7 +54,7 @@ function transformATag(tagName, attribs) {
'data-mx-pill': userId, 'data-mx-pill': userId,
}, },
}; };
if (userId === initMatrix.matrixClient.getUserId()) { if (userId === mx?.getUserId()) {
pill.attribs['data-mx-ping'] = undefined; pill.attribs['data-mx-ping'] = undefined;
} }
return pill; return pill;
@ -76,17 +76,17 @@ function transformATag(tagName, attribs) {
function transformImgTag(tagName, attribs) { function transformImgTag(tagName, attribs) {
const { src } = attribs; const { src } = attribs;
const mx = initMatrix.matrixClient;
return { return {
tagName, tagName,
attribs: { attribs: {
...attribs, ...attribs,
src: src.startsWith('mxc://') ? mx.mxcUrlToHttp(src) : src, src: src.startsWith('mxc://') ? mx?.mxcUrlToHttp(src) : src,
}, },
}; };
} }
export function sanitizeCustomHtml(body) { export function sanitizeCustomHtml(matrixClient, body) {
mx = matrixClient;
return sanitizeHtml(body, { return sanitizeHtml(body, {
allowedTags: permittedHtmlTags, allowedTags: permittedHtmlTags,
allowedAttributes: permittedTagToAttributes, allowedAttributes: permittedTagToAttributes,