From b8922969f5b2738e1f536bccb5601b9e2eca2839 Mon Sep 17 00:00:00 2001 From: Gorash Date: Thu, 10 Mar 2022 09:02:55 +0000 Subject: [PATCH] [FIX] qweb: do not allow rendering inline template During the merge of qweb/ir.qweb at commit 9ce5bc8881ae06b613ef61eb07453b224f62bae6, the behavior of qweb was preserved instead of the one from ir.qweb. Rendering inline templates should not be allowed as it is not needed and include security risks. Also, minimizing the number of possible types for template arguments simplifies the API. An error message allows the developer to know how to adapt his code. closes odoo/odoo#86404 X-original-commit: 31f3152a1328ec8e2dd28f15433a2cc3ccc80f81 Signed-off-by: Olivier Dony --- odoo/addons/base/models/ir_qweb.py | 11 ++++--- odoo/addons/base/tests/test_qweb.py | 46 +++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/odoo/addons/base/models/ir_qweb.py b/odoo/addons/base/models/ir_qweb.py index 0fe81af01ad..8e2ef1f41a8 100644 --- a/odoo/addons/base/models/ir_qweb.py +++ b/odoo/addons/base/models/ir_qweb.py @@ -636,22 +636,21 @@ class IrQWeb(models.AbstractModel): string document that contains ``element``, and ``ref`` if the uniq reference of the template (id, t-name or template). - :param template: template identifier, name or etree + :param template: template identifier or etree :param options: used to compile the template (the dict available for the rendering is frozen) ``load`` (function) overrides the load method """ + assert template not in (False, None, ""), "template is required" + # template is an xml etree already if isinstance(template, etree._Element): element = template document = etree.tostring(template, encoding='unicode') ref = None - # template is xml as string - elif isinstance(template, str) and template.startswith('<'): - element = etree.fromstring(template) - document = template - ref = None + elif isinstance(template, str) and '<' in template: + raise ValueError('Inline templates must be passed as `etree` documents') # template is (id or ref) to a database stored template else: diff --git a/odoo/addons/base/tests/test_qweb.py b/odoo/addons/base/tests/test_qweb.py index 11957e67ca9..b3897c2699c 100644 --- a/odoo/addons/base/tests/test_qweb.py +++ b/odoo/addons/base/tests/test_qweb.py @@ -17,6 +17,7 @@ from odoo.tests.common import TransactionCase from odoo.addons.base.models.ir_qweb import QWebException, render from odoo.tools import misc, mute_logger from odoo.tools.json import scriptsafe as json_scriptsafe +from odoo.exceptions import MissingError unsafe_eval = eval @@ -1240,6 +1241,51 @@ class TestQWebBasic(TransactionCase): self.assertIn('Can not compile expression', error) self.assertIn('
', error) + def test_error_message_3(self): + # The format error tells the developer what to do. + template = '''
+
+ content +
+
''' + with self.assertRaises(ValueError): + self.env['ir.qweb']._render(template) + try: + self.env['ir.qweb']._render(template) + except ValueError as e: + self.assertIn('Inline templates must be passed as `etree` documents', str(e)) + + template = '''toto ''' + with self.assertRaises(ValueError): + self.env['ir.qweb']._render(template) + try: + self.env['ir.qweb']._render(template) + except ValueError as e: + self.assertIn('Inline templates must be passed as `etree` documents', str(e)) + + def test_error_message_4(self): + # Template record view not found. + with self.assertRaises(MissingError): + self.env['ir.qweb']._render(-999) + try: + self.env['ir.qweb']._render(-999) + except MissingError as e: + self.assertIn('Record does not exist or has been deleted.', str(e)) + + with self.assertRaises(ValueError): + self.env['ir.qweb']._render('not.wrong_template_xmlid') + try: + self.env['ir.qweb']._render('not.wrong_template_xmlid') + except ValueError as e: + self.assertIn('External ID not found in the system', str(e)) + + with self.assertRaises(AssertionError): + self.env['ir.qweb']._render(False) + try: + self.env['ir.qweb']._render(False) + except AssertionError as e: + self.assertIn('template is required', str(e)) + def test_call_set(self): view0 = self.env['ir.ui.view'].create({ 'name': "dummy",