# HG changeset patch # User Mads Kiilerich # Date 2015-07-07 02:09:35 # Node ID c9cfaeb1cdfe5b1e3e8c326881e47aa08b0e23f3 # Parent c0da0ef508da341b376b522cb1e14a7e49858055 tooltips: fix unsafe insertion of userdata into the DOM as html This fixes js injection in the admin journal ... and probably also in other places. Tooltips are used both with hardcoded strings (which is safe and simple) and with user provided strings wrapped in html formatting (which requires careful escaping before being put into the DOM as html). The templating will automatically take care of one level of escaping, but here it requires two levels to do it correctly ... and that was not always done correctly. Instead, by default, just insert it into the DOM as text, not as html. The few places where we know the tooltip contains safe html are handled specially - the element is given the safe-html-title class. That is the case in file annotation and in display of tip revision in repo lists. diff --git a/kallithea/lib/helpers.py b/kallithea/lib/helpers.py --- a/kallithea/lib/helpers.py +++ b/kallithea/lib/helpers.py @@ -352,9 +352,9 @@ def pygmentize_annotation(repo_name, fil def url_func(repo_name): def _url_func(changeset): - author = changeset.author + author = escape(changeset.author) date = changeset.date - message = tooltip(changeset.message) + message = escape(changeset.message) tooltip_html = ("
Author:" " %s
Date: %s
Message:" @@ -367,7 +367,7 @@ def pygmentize_annotation(repo_name, fil url('changeset_home', repo_name=repo_name, revision=changeset.raw_id), style=get_color_string(changeset.raw_id), - class_='tooltip', + class_='tooltip safe-html-title', title=tooltip_html ) diff --git a/kallithea/public/js/base.js b/kallithea/public/js/base.js --- a/kallithea/public/js/base.js +++ b/kallithea/public/js/base.js @@ -510,25 +510,31 @@ var _init_tooltip = function(){ _activate_tooltip($('.tooltip')); }; -var _show_tooltip = function(e, tipText){ +var _show_tooltip = function(e, tipText, safe){ e.stopImmediatePropagation(); var el = e.currentTarget; + var $el = $(el); if(tipText){ // just use it } else if(el.tagName.toLowerCase() === 'img'){ tipText = el.alt ? el.alt : ''; } else { tipText = el.title ? el.title : ''; + safe = safe || $el.hasClass("safe-html-title"); } if(tipText !== ''){ // save org title - $(el).attr('tt_title', tipText); + $el.attr('tt_title', tipText); // reset title to not show org tooltips - $(el).attr('title', ''); + $el.attr('title', ''); var $tipBox = $('#tip-box'); - $tipBox.html(tipText); + if (safe) { + $tipBox.html(tipText); + } else { + $tipBox.text(tipText); + } $tipBox.css('display', 'block'); } }; diff --git a/kallithea/templates/data_table/_dt_elements.html b/kallithea/templates/data_table/_dt_elements.html --- a/kallithea/templates/data_table/_dt_elements.html +++ b/kallithea/templates/data_table/_dt_elements.html @@ -93,7 +93,7 @@ <%def name="revision(name,rev,tip,author,last_msg)">
%if rev >= 0: - ${'r%s:%s' % (rev,h.short_id(tip))} + ${'r%s:%s' % (rev,h.short_id(tip))} %else: ${_('No changesets yet')} %endif