From 29efc14aa7aba095163ef5ea6cd9dc6c27816a80 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sat, 25 Jan 2020 09:07:29 +0100 Subject: [PATCH] Revert "implement simplified translation logic, forcing the use of safe application via jQuery element" This reverts commit 62365880b40a1bc3c2b65fe1fb369733a112d825. The unit tests showed that the text2string function completely undid the XSS fix, so it was always unsafe to use it. Also the logic simplifications were smaller then expected. --- js/privatebin.js | 80 ++++++++++--------------- js/test/I18n.js | 149 ++++++++++++++++++++++++---------------------- tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 4 files changed, 111 insertions(+), 122 deletions(-) diff --git a/js/privatebin.js b/js/privatebin.js index 82cc4e16..39537cd9 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -322,12 +322,19 @@ jQuery.PrivateBin = (function($, RawDeflate) { let format = args[0], i = 1; return format.replace(/%(s|d)/g, function (m) { + // m is the matched format, e.g. %s, %d let val = args[i]; - if (m === '%d') { - val = parseFloat(val); - if (isNaN(val)) { - val = 0; - } + // A switch statement so that the formatter can be extended. + switch (m) + { + case '%d': + val = parseFloat(val); + if (isNaN(val)) { + val = 0; + } + break; + default: + // Default is %s } ++i; return val; @@ -540,23 +547,19 @@ jQuery.PrivateBin = (function($, RawDeflate) { /** * translate a string * - * As the first parameter a jQuery element has to be provided, to let - * the text of this element be replaced. In case the (asynchronously + * Optionally pass a jQuery element as the first parameter, to automatically + * let the text of this element be replaced. In case the (asynchronously * loaded) language is not downloadet yet, this will make sure the string - * is replaced when it is actually loaded. This also handles HTML in - * secure fashion, to avoid XSS. - * The second parameter is the message ID, matching the ones found in - * the translation files under the i18n directory. - * Any additional parameters will get inserted into the message ID in - * place of %s (strings) or %d (digits), applying the appropriate plural - * in case of digits. See also Helper.sprintf(). + * is replaced when it is actually loaded. + * So for easy translations passing the jQuery object to apply it to is + * more save, especially when they are loaded in the beginning. * * @name I18n.translate * @function - * @param {jQuery} $element + * @param {jQuery} $element - optional * @param {string} messageId * @param {...*} args - one or multiple parameters injected into placeholders - * @throws {string} + * @return {string} */ me.translate = function() { @@ -570,8 +573,6 @@ jQuery.PrivateBin = (function($, RawDeflate) { // optional jQuery element as first parameter $element = args[0]; args.shift(); - } else { - throw 'translation requires a jQuery element to be passed, for secure insertion of messages and to avoid double encoding of HTML entities'; } // extract messageId from arguments @@ -632,10 +633,10 @@ jQuery.PrivateBin = (function($, RawDeflate) { let containsLinks = args[0].indexOf(' 0) may never contain HTML as they may come from untrusted parties - if (i > 0) { + if (i > 0 || !containsLinks) { args[i] = Helper.htmlEntities(args[i]); } } @@ -653,37 +654,18 @@ jQuery.PrivateBin = (function($, RawDeflate) { ); } - if (containsLinks) { - $element.html(output); - } else { - // text node takes care of entity encoding - $element.text(output); + // if $element is given, insert translation + if ($element !== null) { + if (containsLinks) { + $element.html(output); + } else { + // text node takes care of entity encoding + $element.text(output); + } + return ''; } - }; - /** - * translate a string, outputs the result - * - * This function is identical to I18n.translate, but doesn't require a - * jQuery element as the first parameter, instead it returns the - * translated message as string. - * Avoid using this function, if possible, as it may double encode your - * message's HTML entities. This is done to fail safe, preventing XSS. - * - * @name I18n.translate2string - * @function - * @param {string} messageId - * @param {...*} args - one or multiple parameters injected into placeholders - * @throws {string} - * @return {string} - */ - me.translate2string = function() - { - let args = Array.prototype.slice.call(arguments), - $element = $('