Escape html with markdown off (#732)
This commit is contained in:
parent
1692098d5d
commit
3c1cc59d59
3 changed files with 42 additions and 39 deletions
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue