diff --git a/app/assets/javascripts/openproject.js b/app/assets/javascripts/openproject.js index 5a37bb348c5e..89bad5580552 100644 --- a/app/assets/javascripts/openproject.js +++ b/app/assets/javascripts/openproject.js @@ -115,6 +115,24 @@ window.OpenProject = (function ($) { return (str+'').replace(REGEXP_ESCAPE, "\\$1"); }; + /** + * Use select2's escapeMarkup function for correctly escaping + * text and preventing XSS. + */ + Helpers.markupEscape = (function(){ + try { + var escapeMarkup = jQuery.fn.select2.defaults.escapeMarkup; + if(typeof escapeMarkup === "undefined") { + throw 'jQuery.fn.select2.defaults.escapeMarkup is undefined'; + } + return escapeMarkup; + } catch (e){ + console.log('Error: jQuery.fn.select2.defaults.escapeMarkup not found.\n' + + 'Exception: ' + e.toString()); + throw e; + } + }()); + /** * replace wrong with right in text * @@ -231,12 +249,13 @@ window.OpenProject = (function ($) { // fallback to base behavior if (result.matches === undefined) { - return replaceSpecialChars(format(result.text, query.term)); + return replaceSpecialChars( + Helpers.markupEscape(format(result.text, query.term))); } // shortcut for empty searches if (query.sterm.length === 0) { - return result.text; + return Helpers.markupEscape(result.text); } var matches = result.matches.slice(), @@ -248,7 +267,7 @@ window.OpenProject = (function ($) { text = Helpers.replace(text, match[0], format(match[0], match[1])); } - return replaceSpecialChars(text); + return replaceSpecialChars(Helpers.markupEscape(text)); }; })(); diff --git a/app/assets/javascripts/timelines_autocompleter.js b/app/assets/javascripts/timelines_autocompleter.js index a146557a85c2..85df82353e2b 100644 --- a/app/assets/javascripts/timelines_autocompleter.js +++ b/app/assets/javascripts/timelines_autocompleter.js @@ -124,18 +124,22 @@ markup = []; if (match < 0) { - return "" + item.name + ""; + return "" + + OpenProject.Helpers.markupEscape(item.name) + ""; } - markup.push(item.name.substring(0, match)); + markup.push(OpenProject.Helpers.markupEscape( + item.name.substring(0, match))); markup.push(""); - markup.push(item.name.substring(match, match + tl)); + markup.push(OpenProject.Helpers.markupEscape( + item.name.substring(match, match + tl))); markup.push(""); - markup.push(item.name.substring(match + tl, item.name.length)); - return markup.join("") + markup.push(OpenProject.Helpers.markupEscape( + item.name.substring(match + tl, item.name.length))); + return markup.join(""); }, formatSelection: function (item) { - return item.name; + return OpenProject.Helpers.markupEscape(item.name); }, initSelection: function (element, callback) { var data = [];