From f0da2bf71b49334e4f654f1381558d198336b797 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 9 Dec 2020 15:15:19 -0300 Subject: [PATCH] [FIX] Issue with special message rendering --- app/message-attachments/client/renderField.js | 4 ++- lib/escapeHTML.spec.ts | 19 +++++++++++++ lib/escapeHTML.ts | 27 +++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 lib/escapeHTML.spec.ts create mode 100644 lib/escapeHTML.ts diff --git a/app/message-attachments/client/renderField.js b/app/message-attachments/client/renderField.js index 3ba28e8ffc228..7993297fb8086 100644 --- a/app/message-attachments/client/renderField.js +++ b/app/message-attachments/client/renderField.js @@ -1,6 +1,8 @@ import { Template } from 'meteor/templating'; import { Blaze } from 'meteor/blaze'; +import { escapeHTML } from '../../../lib/escapeHTML'; + const renderers = {}; /** @@ -49,7 +51,7 @@ Template.renderField.helpers({ html = Blaze.toHTMLWithData(Template[renderers[field.type]], { field, message }); } else { // consider the value already formatted as html - html = field.value; + html = escapeHTML(field.value); } return `
${ html }
`; }, diff --git a/lib/escapeHTML.spec.ts b/lib/escapeHTML.spec.ts new file mode 100644 index 0000000000000..a153309fc7583 --- /dev/null +++ b/lib/escapeHTML.spec.ts @@ -0,0 +1,19 @@ +import assert from 'assert'; + +import { describe, it } from 'mocha'; + +import { escapeHTML } from './escapeHTML'; + +describe('escapeHTML', () => { + it('works', () => { + assert.strictEqual(escapeHTML('
Blah & "blah" & \'blah\'
'), '<div>Blah & "blah" & 'blah'</div>'); + assert.strictEqual(escapeHTML('<'), '&lt;'); + assert.strictEqual(escapeHTML(' '), ' '); + assert.strictEqual(escapeHTML('¢'), '¢'); + assert.strictEqual(escapeHTML('¢ £ ¥ € © ®'), '¢ £ ¥ € © ®'); + assert.strictEqual(escapeHTML(5 as unknown as string), '5'); + assert.strictEqual(escapeHTML(''), ''); + assert.strictEqual(escapeHTML(null as unknown as string), ''); + assert.strictEqual(escapeHTML(undefined as unknown as string), ''); + }); +}); diff --git a/lib/escapeHTML.ts b/lib/escapeHTML.ts new file mode 100644 index 0000000000000..00ac1f5a2a290 --- /dev/null +++ b/lib/escapeHTML.ts @@ -0,0 +1,27 @@ +const characterToHtmlEntityCode = { + '¢': 'cent', + '£': 'pound', + '¥': 'yen', + '€': 'euro', + '©': 'copy', + '®': 'reg', + '<': 'lt', + '>': 'gt', + '"': 'quot', + '&': 'amp', + '\'': '#39', +} as const; + +const regex = new RegExp(`[${ Object.keys(characterToHtmlEntityCode).join('') }]`, 'g'); + +const toString = (object: unknown): string => + (object ? `${ object }` : ''); + +const isEscapable = (char: string): char is keyof typeof characterToHtmlEntityCode => + char in characterToHtmlEntityCode; + +const escapeChar = (char: string): string => + (isEscapable(char) ? `&${ characterToHtmlEntityCode[char] };` : ''); + +export const escapeHTML = (str: string): string => + toString(str).replace(regex, escapeChar);