From e3c402d03db2de7a488889bb5cb210be84bea993 Mon Sep 17 00:00:00 2001 From: Maciej Barelkowski Date: Thu, 13 Jun 2019 16:25:20 +0200 Subject: [PATCH] feat(i18n): escape translations per default --- lib/i18n/translate/translate.js | 17 ++++++++++++++--- lib/util/EscapeUtil.js | 13 ++++++++++--- test/spec/i18n/translate/translateSpec.js | 11 +++++++++++ test/spec/util/EscapeUtilSpec.js | 8 +++++--- 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/lib/i18n/translate/translate.js b/lib/i18n/translate/translate.js index a5240d19a..a413f8763 100644 --- a/lib/i18n/translate/translate.js +++ b/lib/i18n/translate/translate.js @@ -1,7 +1,10 @@ +import { escapeHTML } from '../../util/EscapeUtil'; + + /** * A simple translation stub to be used for multi-language support * in diagrams. Can be easily replaced with a more sophisticated - * solution. + * solution. Escapes HTML per default. * * @example * @@ -13,14 +16,22 @@ * * @param {String} template to interpolate * @param {Object} [replacements] a map with substitutes + * @param {boolean} [safe] true if should not be escaped * * @return {String} the translated string */ -export default function translate(template, replacements) { +export default function translate(template, replacements, safe) { + + if (typeof replacements === 'boolean') { + safe = replacements; + replacements = {}; + } replacements = replacements || {}; - return template.replace(/{([^}]+)}/g, function(_, key) { + template = template.replace(/{([^}]+)}/g, function(_, key) { return replacements[key] || '{' + key + '}'; }); + + return safe ? template : escapeHTML(template); } \ No newline at end of file diff --git a/lib/util/EscapeUtil.js b/lib/util/EscapeUtil.js index e9dbe81b3..668977554 100644 --- a/lib/util/EscapeUtil.js +++ b/lib/util/EscapeUtil.js @@ -2,13 +2,20 @@ export { default as escapeCSS } from 'css.escape'; +var UNSAFE_HTML = /[&<>"']/g; + var HTML_ESCAPE_MAP = { - '<': '<', - '>': '>' + '&': '&', + '<': '<', + '>': '>', + '"': '"', + '\'': ''' }; export function escapeHTML(str) { - return str.replace(/[<>]/g, function(match) { + str = '' + str; + + return str && str.replace(UNSAFE_HTML, function(match) { return HTML_ESCAPE_MAP[match]; }); } \ No newline at end of file diff --git a/test/spec/i18n/translate/translateSpec.js b/test/spec/i18n/translate/translateSpec.js index 5c8a4e539..79de48d7d 100644 --- a/test/spec/i18n/translate/translateSpec.js +++ b/test/spec/i18n/translate/translateSpec.js @@ -38,6 +38,17 @@ describe('i18n - translate', function() { expect(translate('FOO {bar}!', {})).to.eql('FOO {bar}!'); })); + + it('should escape HTML per default', inject(function(translate) { + expect(translate('Bold statement', {})).to.eql('<b>Bold</b> statement'); + })); + + + it('should not escape HTML for safe=true', inject(function(translate) { + expect(translate('Bold statement', true)).to.eql('Bold statement'); + expect(translate('Bold statement', {}, true)).to.eql('Bold statement'); + })); + }); diff --git a/test/spec/util/EscapeUtilSpec.js b/test/spec/util/EscapeUtilSpec.js index 4f53c23a3..44e362c6d 100644 --- a/test/spec/util/EscapeUtilSpec.js +++ b/test/spec/util/EscapeUtilSpec.js @@ -11,10 +11,12 @@ describe('util/EscapeUtil', function() { }); - it('escapeHTML', function() { - var htmlStr = '