general: escape substitution variables (#7860)
In templates used for comments and editable texts the substitution is done on-the-fly by ezt. This is not enabled to the general template as most variables in there are supposed to be HTML and many sites created on that assumption. Therefore the substitution is done ahead and limited to context variables.
This commit is contained in:
parent
24a783380b
commit
692af244d4
|
@ -128,6 +128,12 @@ def test_comment():
|
|||
field.add_to_form(form)
|
||||
assert '<p>Foobar</p>' in str(form.render())
|
||||
|
||||
# test for proper escaping of substitution variables
|
||||
field = fields.CommentField(label='[foo]')
|
||||
form = Form()
|
||||
field.add_to_form(form)
|
||||
assert '<p>1 < 3</p>' in str(form.render())
|
||||
|
||||
# test for html content
|
||||
field = fields.CommentField(label='<p>Foobar</p>')
|
||||
form = Form()
|
||||
|
|
|
@ -48,3 +48,7 @@ def test_get_html_subst():
|
|||
pub.cfg['texts'] = {'text-foo4': '[bar]'}
|
||||
pub.write_cfg()
|
||||
assert TextsDirectory.get_html_text('foo4') == '<p>Foobar</p>'
|
||||
|
||||
pub.cfg['texts'] = {'text-foo4': '[foo]'}
|
||||
pub.write_cfg()
|
||||
assert TextsDirectory.get_html_text('foo4') == '<p>1 < 3</p>'
|
||||
|
|
|
@ -12,7 +12,8 @@ from wcs import sessions
|
|||
from wcs.fields import StringField, DateField
|
||||
from wcs.roles import Role
|
||||
from wcs.workflows import (Workflow, WorkflowStatusItem,
|
||||
SendmailWorkflowStatusItem, SendSMSWorkflowStatusItem)
|
||||
SendmailWorkflowStatusItem, SendSMSWorkflowStatusItem,
|
||||
DisplayMessageWorkflowStatusItem)
|
||||
from wcs.wf.anonymise import AnonymiseWorkflowStatusItem
|
||||
from wcs.wf.dispatch import DispatchWorkflowStatusItem
|
||||
from wcs.wf.form import FormWorkflowStatusItem, WorkflowFormFieldsFormDef
|
||||
|
@ -27,7 +28,16 @@ from utilities import (create_temporary_pub, MockSubstitutionVariables, emails,
|
|||
|
||||
def setup_module(module):
|
||||
cleanup()
|
||||
global pub, req
|
||||
|
||||
def teardown_module(module):
|
||||
clean_temporary_pub()
|
||||
|
||||
def pytest_generate_tests(metafunc):
|
||||
if 'two_pubs' in metafunc.fixturenames:
|
||||
metafunc.parametrize('two_pubs', ['pickle', 'sql'], indirect=True)
|
||||
|
||||
@pytest.fixture
|
||||
def pub(request):
|
||||
pub = create_temporary_pub()
|
||||
pub.cfg['language'] = {'language': 'en'}
|
||||
pub.write_cfg()
|
||||
|
@ -36,13 +46,7 @@ def setup_module(module):
|
|||
req.user = None
|
||||
pub._set_request(req)
|
||||
req.session = sessions.BasicSession(id=1)
|
||||
|
||||
def teardown_module(module):
|
||||
clean_temporary_pub()
|
||||
|
||||
def pytest_generate_tests(metafunc):
|
||||
if 'two_pubs' in metafunc.fixturenames:
|
||||
metafunc.parametrize('two_pubs', ['pickle', 'sql'], indirect=True)
|
||||
return pub
|
||||
|
||||
@pytest.fixture
|
||||
def two_pubs(request):
|
||||
|
@ -57,7 +61,7 @@ def two_pubs(request):
|
|||
|
||||
return pub
|
||||
|
||||
def test_jump_nothing():
|
||||
def test_jump_nothing(pub):
|
||||
FormDef.wipe()
|
||||
formdef = FormDef()
|
||||
formdef.name = 'foobar'
|
||||
|
@ -66,7 +70,7 @@ def test_jump_nothing():
|
|||
item = JumpWorkflowStatusItem()
|
||||
assert item.must_jump(formdata) is True
|
||||
|
||||
def test_jump_datetime_condition():
|
||||
def test_jump_datetime_condition(pub):
|
||||
FormDef.wipe()
|
||||
formdef = FormDef()
|
||||
formdef.name = 'foobar'
|
||||
|
@ -83,7 +87,7 @@ def test_jump_datetime_condition():
|
|||
tomorrow.timetuple()[:3]
|
||||
assert item.must_jump(formdata) is False
|
||||
|
||||
def test_jump_count_condition():
|
||||
def test_jump_count_condition(pub):
|
||||
FormDef.wipe()
|
||||
formdef = FormDef()
|
||||
formdef.name = 'foobar'
|
||||
|
@ -101,7 +105,7 @@ def test_jump_count_condition():
|
|||
item.condition = 'form_objects.count < 2'
|
||||
assert item.must_jump(formdata) is False
|
||||
|
||||
def test_check_auth():
|
||||
def test_check_auth(pub):
|
||||
user = pub.user_class(name='foo')
|
||||
user.store()
|
||||
|
||||
|
@ -148,7 +152,7 @@ def test_check_auth():
|
|||
formdata.workflow_roles = None
|
||||
assert status_item.check_auth(formdata, user) is True
|
||||
|
||||
def test_dispatch():
|
||||
def test_dispatch(pub):
|
||||
formdef = FormDef()
|
||||
formdef.name = 'baz'
|
||||
formdef.store()
|
||||
|
@ -165,7 +169,7 @@ def test_dispatch():
|
|||
item.perform(formdata)
|
||||
assert formdata.workflow_roles == {'_receiver': '1'}
|
||||
|
||||
def test_roles():
|
||||
def test_roles(pub):
|
||||
user = pub.user_class()
|
||||
user.store()
|
||||
|
||||
|
@ -206,7 +210,7 @@ def test_roles():
|
|||
item.perform(formdata)
|
||||
assert pub.user_class.get(user.id).roles == ['2']
|
||||
|
||||
def test_anonymise():
|
||||
def test_anonymise(pub):
|
||||
formdef = FormDef()
|
||||
formdef.name = 'baz'
|
||||
formdef.fields = []
|
||||
|
@ -222,7 +226,7 @@ def test_anonymise():
|
|||
assert formdef.data_class().get(formdata.id).user_id is None
|
||||
assert formdef.data_class().get(formdata.id).anonymised
|
||||
|
||||
def test_remove():
|
||||
def test_remove(pub):
|
||||
formdef = FormDef()
|
||||
formdef.name = 'baz'
|
||||
formdef.store()
|
||||
|
@ -239,6 +243,7 @@ def test_remove():
|
|||
formdata.store()
|
||||
|
||||
item = RemoveWorkflowStatusItem()
|
||||
req = pub.get_request()
|
||||
req.response.filter['in_backoffice'] = True
|
||||
assert formdef.data_class().has_key(formdata.id)
|
||||
assert item.perform(formdata) == '..'
|
||||
|
@ -246,7 +251,7 @@ def test_remove():
|
|||
req.response.filter = {}
|
||||
assert req.session.message
|
||||
|
||||
def test_register_comment():
|
||||
def test_register_comment(pub):
|
||||
pub.substitutions.feed(MockSubstitutionVariables())
|
||||
|
||||
formdef = FormDef()
|
||||
|
@ -286,7 +291,7 @@ def test_register_comment():
|
|||
item.perform(formdata)
|
||||
assert formdata.evolution[-1].display_parts()[-1] == '<div>1 < 3</div>'
|
||||
|
||||
def test_email():
|
||||
def test_email(pub):
|
||||
pub.substitutions.feed(MockSubstitutionVariables())
|
||||
|
||||
formdef = FormDef()
|
||||
|
@ -378,7 +383,7 @@ def test_email():
|
|||
assert emails.count() == 1
|
||||
assert emails.get('foobar')['email_rcpt'] == ['xyz@localhost']
|
||||
|
||||
def test_webservice_call():
|
||||
def test_webservice_call(pub):
|
||||
pub.substitutions.feed(MockSubstitutionVariables())
|
||||
|
||||
formdef = FormDef()
|
||||
|
@ -425,7 +430,7 @@ def test_webservice_call():
|
|||
item.perform(formdata)
|
||||
assert 'signature=' in http_requests.get_last('url')
|
||||
|
||||
def test_timeout():
|
||||
def test_timeout(pub):
|
||||
workflow = Workflow(name='timeout')
|
||||
st1 = workflow.add_status('Status1', 'st1')
|
||||
st2 = workflow.add_status('Status2', 'st2')
|
||||
|
@ -491,11 +496,11 @@ def test_timeout_then_remove(two_pubs):
|
|||
assert str(formdata_id) in [str(x) for x in formdef.data_class().keys()]
|
||||
|
||||
time.sleep(0.2)
|
||||
_apply_timeouts(pub)
|
||||
_apply_timeouts(two_pubs)
|
||||
|
||||
assert not str(formdata_id) in [str(x) for x in formdef.data_class().keys()]
|
||||
|
||||
def test_sms():
|
||||
def test_sms(pub):
|
||||
formdef = FormDef()
|
||||
formdef.name = 'baz'
|
||||
formdef.fields = []
|
||||
|
@ -572,9 +577,9 @@ def test_display_form(two_pubs):
|
|||
assert formdata.get_substitution_variables()['xxx_var_date_raw'] == \
|
||||
time.strptime('2015-05-12', '%Y-%m-%d')
|
||||
|
||||
pub.cfg['language'] = {'language': 'en'}
|
||||
two_pubs.cfg['language'] = {'language': 'en'}
|
||||
|
||||
def test_workflow_role_type_migration():
|
||||
def test_workflow_role_type_migration(pub):
|
||||
workflow = Workflow(name='role migration')
|
||||
st1 = workflow.add_status('Status1', 'st1')
|
||||
|
||||
|
@ -588,3 +593,33 @@ def test_workflow_role_type_migration():
|
|||
|
||||
reloaded_workflow = Workflow.get(workflow.id)
|
||||
assert reloaded_workflow.possible_status[0].items[0].by == ['1', '2']
|
||||
|
||||
def test_workflow_display_message(pub):
|
||||
pub.substitutions.feed(MockSubstitutionVariables())
|
||||
|
||||
workflow = Workflow(name='display message')
|
||||
st1 = workflow.add_status('Status1', 'st1')
|
||||
|
||||
FormDef.wipe()
|
||||
formdef = FormDef()
|
||||
formdef.name = 'foobar'
|
||||
formdef.fields = []
|
||||
formdef.store()
|
||||
formdata = formdef.data_class()()
|
||||
formdata.id = '1'
|
||||
|
||||
display_message = DisplayMessageWorkflowStatusItem()
|
||||
display_message.parent = st1
|
||||
|
||||
display_message.message = 'test'
|
||||
assert display_message.get_message(formdata) == 'test'
|
||||
|
||||
display_message.message = '[number]'
|
||||
assert display_message.get_message(formdata) == str(formdata.id)
|
||||
|
||||
display_message.message = '[bar]'
|
||||
assert display_message.get_message(formdata) == 'Foobar'
|
||||
|
||||
# makes sure the string is correctly escaped for HTML
|
||||
display_message.message = '[foo]'
|
||||
assert display_message.get_message(formdata) == '1 < 3'
|
||||
|
|
|
@ -453,7 +453,7 @@ class CommentField(Field):
|
|||
label = self.label
|
||||
|
||||
import wcs.workflows
|
||||
label = wcs.workflows.template_on_string(label)
|
||||
label = wcs.workflows.template_on_html_string(label)
|
||||
|
||||
if '<p' in label:
|
||||
enclosing_tag = 'div'
|
||||
|
|
|
@ -50,7 +50,7 @@ class TextsDirectory(Directory):
|
|||
subst_vars.update(vars)
|
||||
|
||||
text_template = ezt.Template(compress_whitespace=False)
|
||||
text_template.parse(text)
|
||||
text_template.parse(text, base_format=ezt.FORMAT_HTML)
|
||||
fd = StringIO()
|
||||
text_template.generate(fd, subst_vars)
|
||||
text = fd.getvalue()
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import cgi
|
||||
from cStringIO import StringIO
|
||||
import os
|
||||
import glob
|
||||
|
@ -438,7 +439,10 @@ def decorate(body, response):
|
|||
breadcrumb = ' <span class="separator">></span> '.join(s)
|
||||
|
||||
vars = response.filter.copy()
|
||||
vars.update(get_publisher().substitutions.get_context_variables())
|
||||
for var_key, var_value in get_publisher().substitutions.get_context_variables().items():
|
||||
if isinstance(var_value, basestring):
|
||||
var_value = cgi.escape(var_value)
|
||||
vars[var_key] = var_value
|
||||
vars.update(locals())
|
||||
fd = StringIO()
|
||||
template.generate(fd, vars)
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from qommon import ezt
|
||||
import cgi
|
||||
from cStringIO import StringIO
|
||||
import copy
|
||||
import xml.etree.ElementTree as ET
|
||||
|
@ -1347,11 +1348,13 @@ class SendmailWorkflowStatusItem(WorkflowStatusItem):
|
|||
register_item_class(SendmailWorkflowStatusItem)
|
||||
|
||||
|
||||
def template_on_string(template, process=None):
|
||||
return template_on_formdata(None, template, process=process)
|
||||
def template_on_html_string(template, process=None):
|
||||
return template_on_formdata(None, template, process=process,
|
||||
base_format=ezt.FORMAT_HTML)
|
||||
|
||||
|
||||
def template_on_formdata(formdata=None, template=None, process=None):
|
||||
def template_on_formdata(formdata=None, template=None, process=None,
|
||||
base_format=ezt.FORMAT_RAW):
|
||||
assert template is not None
|
||||
if not '[' in template:
|
||||
return template
|
||||
|
@ -1384,7 +1387,7 @@ def template_on_formdata(formdata=None, template=None, process=None):
|
|||
dict[k] = v.encode(charset, 'ignore')
|
||||
|
||||
processor = ezt.Template(compress_whitespace=False)
|
||||
processor.parse(template or '')
|
||||
processor.parse(template or '', base_format=base_format)
|
||||
|
||||
fd = StringIO()
|
||||
processor.generate(fd, dict)
|
||||
|
@ -1459,7 +1462,7 @@ class DisplayMessageWorkflowStatusItem(WorkflowStatusItem):
|
|||
if not self.message:
|
||||
return ''
|
||||
tmpl = ezt.Template()
|
||||
tmpl.parse(self.message)
|
||||
tmpl.parse(self.message, base_format=ezt.FORMAT_HTML)
|
||||
|
||||
dict = {}
|
||||
dict.update(get_publisher().substitutions.get_context_variables())
|
||||
|
|
Loading…
Reference in New Issue