From f0842cbb1e4002823b67adf4c562d00899704797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Thu, 16 Jul 2015 11:49:00 +0200 Subject: [PATCH] template: escape substitution variables (#7860) --- tests/test_fields.py | 6 ++++++ tests/test_prefill.py | 2 +- wcs/data_sources.py | 4 ++-- wcs/fields.py | 7 ++++--- wcs/forms/root.py | 2 +- wcs/qommon/admin/texts.py | 2 +- wcs/qommon/emails.py | 2 +- wcs/qommon/form.py | 4 ++-- wcs/qommon/ident/idp.py | 2 +- wcs/qommon/substitution.py | 10 +++++++++- wcs/qommon/template.py | 2 +- wcs/wf/jump.py | 2 +- wcs/wf/wscall.py | 2 +- wcs/workflows.py | 12 +++++++++--- 14 files changed, 40 insertions(+), 19 deletions(-) diff --git a/tests/test_fields.py b/tests/test_fields.py index a9e1367..c7c6789 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -128,6 +128,12 @@ def test_comment(): field.add_to_form(form) assert '

Foobar

' in str(form.render()) + # test for proper escaping of substitution variables + field = fields.CommentField(label='[foo]') + form = Form() + field.add_to_form(form) + assert '

1 < 3

' in str(form.render()) + # test for html content field = fields.CommentField(label='

Foobar

') form = Form() diff --git a/tests/test_prefill.py b/tests/test_prefill.py index 9e35ec8..2ef56e6 100644 --- a/tests/test_prefill.py +++ b/tests/test_prefill.py @@ -57,7 +57,7 @@ def test_prefill_formula_with_error(): def test_prefill_formula_substition_variable(): - pub.substitutions.get_context_variables = lambda: {'test': 'value'} + pub.substitutions.get_context_variables = lambda escape: {'test': 'value'} field = fields.Field() field.prefill = {'type': 'formula', 'value': 'test'} diff --git a/wcs/data_sources.py b/wcs/data_sources.py index a41878f..4bbaf90 100644 --- a/wcs/data_sources.py +++ b/wcs/data_sources.py @@ -104,7 +104,7 @@ def get_structured_items(data_source): # - three elements, (id, text, key) # - two elements, (id, text) # - a single element, (id,) - vars = get_publisher().substitutions.get_context_variables() + vars = get_publisher().substitutions.get_context_variables(escape=False) try: value = eval(data_source.get('value'), vars, data_source_functions) if not isinstance(value, collections.Iterable): @@ -136,7 +136,7 @@ def get_structured_items(data_source): get_logger().warn('Empty URL in JSON data source') return [] if '[' in url: - vars = get_publisher().substitutions.get_context_variables() + vars = get_publisher().substitutions.get_context_variables(escape=False) url = get_variadic_url(url, vars) charset = get_publisher().site_charset try: diff --git a/wcs/fields.py b/wcs/fields.py index 9bd3422..19694c8 100644 --- a/wcs/fields.py +++ b/wcs/fields.py @@ -257,7 +257,7 @@ class Field(object): try: ret = eval(formula, get_publisher().get_global_eval_dict(), - get_publisher().substitutions.get_context_variables()) + get_publisher().substitutions.get_context_variables(escape=False)) if ret: return str(ret) except: @@ -453,7 +453,8 @@ class CommentField(Field): label = self.label import wcs.workflows - label = wcs.workflows.template_on_string(label) + label = wcs.workflows.template_on_string(label, + process=wcs.workflows.html_process) if '. +import cgi + from quixote.html import htmltext, TemplateIO class Substitutions(object): @@ -52,10 +54,16 @@ class Substitutions(object): return self.sources.append(source) - def get_context_variables(self): + def get_context_variables(self, escape=True): d = {} for source in self.sources: d.update(source.get_substitution_variables()) + if escape: + for var_key, var_value in d.items(): + if isinstance(var_value, basestring): + d[var_key] = cgi.escape(var_value) + else: + d[var_key] = var_value return d def get_substitution_html_table(cls): diff --git a/wcs/qommon/template.py b/wcs/qommon/template.py index f4087f9..cbf5789 100644 --- a/wcs/qommon/template.py +++ b/wcs/qommon/template.py @@ -438,7 +438,7 @@ def decorate(body, response): breadcrumb = ' > '.join(s) vars = response.filter.copy() - vars.update(get_publisher().substitutions.get_context_variables()) + vars.update(get_publisher().substitutions.get_context_variables(escape=True)) vars.update(locals()) fd = StringIO() template.generate(fd, vars) diff --git a/wcs/wf/jump.py b/wcs/wf/jump.py index 516853a..6f3058b 100644 --- a/wcs/wf/jump.py +++ b/wcs/wf/jump.py @@ -194,7 +194,7 @@ class JumpWorkflowStatusItem(WorkflowStatusJumpItem): must_jump = True if self.condition: - variables = get_publisher().substitutions.get_context_variables() + variables = get_publisher().substitutions.get_context_variables(escape=False) try: must_jump = eval(self.condition, get_publisher().get_global_eval_dict(), variables) except: diff --git a/wcs/wf/wscall.py b/wcs/wf/wscall.py index 9a4fd28..f707b8b 100644 --- a/wcs/wf/wscall.py +++ b/wcs/wf/wscall.py @@ -59,7 +59,7 @@ class WebserviceCallStatusItem(WorkflowStatusItem): return url = self.url if '[' in url: - variables = get_publisher().substitutions.get_context_variables() + variables = get_publisher().substitutions.get_context_variables(escape=False) url = get_variadic_url(url, variables) if self.request_signature_key: diff --git a/wcs/workflows.py b/wcs/workflows.py index e6abf88..b7245a3 100644 --- a/wcs/workflows.py +++ b/wcs/workflows.py @@ -15,6 +15,7 @@ # along with this program; if not, see . from qommon import ezt +import cgi from cStringIO import StringIO import copy import xml.etree.ElementTree as ET @@ -826,7 +827,7 @@ class WorkflowStatusItem(object): return var if not var.startswith('='): return var - vars = get_publisher().substitutions.get_context_variables() + vars = get_publisher().substitutions.get_context_variables(escape=False) try: return eval(var[1:], get_publisher().get_global_eval_dict(), vars) except: @@ -1356,7 +1357,7 @@ def template_on_formdata(formdata=None, template=None, process=None): if not '[' in template: return template dict = {} - dict.update(get_publisher().substitutions.get_context_variables()) + dict.update(get_publisher().substitutions.get_context_variables(escape=False)) if formdata: dict['url'] = formdata.get_url() dict['url_status'] = '%sstatus' % formdata.get_url() @@ -1462,7 +1463,7 @@ class DisplayMessageWorkflowStatusItem(WorkflowStatusItem): tmpl.parse(self.message) dict = {} - dict.update(get_publisher().substitutions.get_context_variables()) + dict.update(get_publisher().substitutions.get_context_variables(escape=True)) dict['date'] = misc.localstrftime(filled.receipt_time) dict['number'] = filled.id handling_role = filled.get_handling_role() @@ -1590,6 +1591,11 @@ def rtf_process(value): return None return str2rtf(unicode(str(value), get_publisher().site_charset)) +def html_process(value): + if not isinstance(value, basestring): + return value + return cgi.escape(value) + class ExportToModel(WorkflowStatusItem): description = N_('Create Document') key = 'export_to_model' -- 2.1.4