diff --git a/js/privatebin.js b/js/privatebin.js
index 86b6046..7b141c5 100644
--- a/js/privatebin.js
+++ b/js/privatebin.js
@@ -43,26 +43,6 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) {
var Helper = (function () {
var me = {};
- /**
- * character to HTML entity lookup table
- *
- * @see {@link https://github.com/janl/mustache.js/blob/master/mustache.js#L60}
- * @name Helper.entityMap
- * @private
- * @enum {Object}
- * @readonly
- */
- var entityMap = {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- "'": ''',
- '/': '/',
- '`': '`',
- '=': '='
- };
-
/**
* cache for script location
*
@@ -134,28 +114,6 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) {
}
}
- /**
- * set text of a jQuery element (required for IE),
- *
- * @name Helper.setElementText
- * @function
- * @param {jQuery} $element - a jQuery element
- * @param {string} text - the text to enter
- */
- me.setElementText = function($element, text)
- {
- // For IE<10: Doesn't support white-space:pre-wrap; so we have to do this...
- if ($('#oldienotice').is(':visible')) {
- var html = me.htmlEntities(text).replace(/\n/ig, '\r\n
');
- $element.html('
' + html + ''); - } - // for other (sane) browsers: - else - { - $element.text(text); - } - } - /** * convert URLs to clickable links. * URLs to handle: @@ -167,22 +125,14 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { * * @name Helper.urls2links * @function - * @param {Object} $element - a jQuery DOM element + * @param {string} html + * @return {string} */ - me.urls2links = function($element) + me.urls2links = function(html) { - var markup = '$1'; - $element.html( - $element.html().replace( - /((http|https|ftp):\/\/[\w?=&.\/-;#@~%+*-]+(?![\w\s?&.\/;#~%"=-]*>))/ig, - markup - ) - ); - $element.html( - $element.html().replace( - /((magnet):[\w?=&.\/-;#@~%+*-]+)/ig, - markup - ) + return html.replace( + /(((http|https|ftp):\/\/[\w?=&.\/-;#@~%+*-]+(?![\w\s?&.\/;#~%"=-]*>))|((magnet):[\w?=&.\/-;#@~%+*-]+))/ig, + '$1' ); } @@ -269,22 +219,6 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { return baseUri; } - /** - * convert all applicable characters to HTML entities - * - * @see {@link https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet#RULE_.231_-_HTML_Escape_Before_Inserting_Untrusted_Data_into_HTML_Element_Content} - * @name Helper.htmlEntities - * @function - * @param {string} str - * @return {string} escaped HTML - */ - me.htmlEntities = function(str) { - return String(str).replace( - /[&<>"'`=\/]/g, function(s) { - return entityMap[s]; - }); - } - /** * resets state, used for unit testing * @@ -1765,10 +1699,10 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { return; } - // set text - var sanitizedText = DOMPurify.sanitize(text, {SAFE_FOR_JQUERY: true}) - Helper.setElementText($plainText, sanitizedText); - Helper.setElementText($prettyPrint, sanitizedText); + // set sanitized and linked text + var sanitizedLinkedText = DOMPurify.sanitize(Helper.urls2links(text), {SAFE_FOR_JQUERY: true}); + $plainText.html(sanitizedLinkedText); + $prettyPrint.html(sanitizedLinkedText); switch (format) { case 'markdown': @@ -1785,23 +1719,20 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { $plainText.find('table').addClass('table-condensed table-bordered'); break; case 'syntaxhighlighting': - // @TODO is this really needed or is "one" enough? + // yes, this is really needed to initialize the environment if (typeof prettyPrint === 'function') { prettyPrint(); } $prettyPrint.html( - prettyPrintOne( - Helper.htmlEntities(sanitizedText), null, true + DOMPurify.sanitize( + prettyPrintOne(Helper.urls2links(text), null, true), + {SAFE_FOR_JQUERY: true} ) ); // fall through, as the rest is the same default: // = 'plaintext' - // convert URLs to clickable links - Helper.urls2links($plainText); - Helper.urls2links($prettyPrint); - $prettyPrint.css('white-space', 'pre-wrap'); $prettyPrint.css('word-break', 'normal'); $prettyPrint.removeClass('prettyprint'); @@ -2290,8 +2221,12 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { var $commentEntryData = $commentEntry.find('div.commentdata'); // set & parse text - Helper.setElementText($commentEntryData, commentText); - Helper.urls2links($commentEntryData); + $commentEntryData.html( + DOMPurify.sanitize( + Helper.urls2links(commentText), + {SAFE_FOR_JQUERY: true} + ) + ); // set nickname if (nickname.length > 0) { @@ -2594,7 +2529,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { for (var i = 0; i < $head.length; i++) { newDoc.write($head[i].outerHTML); } - newDoc.write('
' + Helper.htmlEntities(paste) + '