From 9c3616a772933bce04d1e199378757c82ec5f935 Mon Sep 17 00:00:00 2001 From: Romain Courteaud <romain@nexedi.com> Date: Thu, 3 Sep 2020 14:08:19 +0000 Subject: [PATCH] erp5_hal_json_style: forbid querying unknown catalog column --- .../ERP5Document_getHateoas.py | 13 +++++ .../test.erp5.testHalJsonStyle.py | 32 +++++++++- .../testListboxQueryRejectUnknownColumn.xml | 58 +++++++++++++++++++ .../testListboxQueryRejectUnknownColumn.zpt | 53 +++++++++++++++++ .../testPageActionBackLinkOnModule.zpt | 6 +- 5 files changed, 157 insertions(+), 5 deletions(-) create mode 100644 bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_listbox_zuite/testListboxQueryRejectUnknownColumn.xml create mode 100644 bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_listbox_zuite/testListboxQueryRejectUnknownColumn.zpt diff --git a/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/ERP5Document_getHateoas.py b/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/ERP5Document_getHateoas.py index 4df932393b..b6097d9b33 100644 --- a/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/ERP5Document_getHateoas.py +++ b/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/ERP5Document_getHateoas.py @@ -1727,6 +1727,19 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None, byteify( json.loads(urlsafe_b64decode(default_param_json))))) if query: + # Forbid querying unknown catalog column + invalid_column_list = [] + def isValidColumnOrRaise(column_id): + is_valid_column = sql_catalog.isValidColumn(column_id) + if not is_valid_column: + invalid_column_list.append(column_id) + return is_valid_column + sql_catalog.parseSearchText(query, search_key='FullTextKey', is_valid=isValidColumnOrRaise) + + if invalid_column_list: + response.setStatus(400) + result_dict["_debug"] = 'Invalid column name: %s' % str(invalid_column_list) + return result_dict catalog_kw["full_text"] = query if selection_domain is not None: diff --git a/bt5/erp5_hal_json_style/TestTemplateItem/portal_components/test.erp5.testHalJsonStyle.py b/bt5/erp5_hal_json_style/TestTemplateItem/portal_components/test.erp5.testHalJsonStyle.py index 9ec6853043..c12fc6ef76 100644 --- a/bt5/erp5_hal_json_style/TestTemplateItem/portal_components/test.erp5.testHalJsonStyle.py +++ b/bt5/erp5_hal_json_style/TestTemplateItem/portal_components/test.erp5.testHalJsonStyle.py @@ -1432,6 +1432,34 @@ class TestERP5Document_getHateoas_mode_search(ERP5HALJSONStyleSkinsMixin): # No count if not in the listbox context currently self.assertEqual(result_dict['_embedded'].get('count', None), None) + @simulate('Base_getRequestUrl', '*args, **kwargs', 'return "http://example.org/bar"') + @simulate('Base_getRequestHeader', '*args, **kwargs', 'return "application/hal+json"') + @simulate('Test_listCatalog', '*args, **kwargs', "return []") + @changeSkin('Hal') + def test_getHateoas_query_param_reject_unknown_column(self, **kw): + """Check that listbox line calculation modify the selection + """ + self.portal.foo_module.FooModule_viewFooList.listbox.ListBox_setPropertyList( + field_count_method = '') + + selection_tool = self.portal.portal_selections + selection_name = self.portal.foo_module.FooModule_viewFooList.listbox.get_value('selection_name') + selection_tool.setSelectionFor(selection_name, Selection(selection_name)) + + # Create the listbox selection + fake_request = do_fake_request("GET") + result = self.portal.web_site_module.hateoas.ERP5Document_getHateoas( + REQUEST=fake_request, + mode="search", + query='bar:"foo"' + ) + self.assertEquals(fake_request.RESPONSE.status, 400) + self.assertEquals(fake_request.RESPONSE.getHeader('Content-Type'), + "application/hal+json" + ) + result_dict = json.loads(result) + self.assertEqual(result_dict['_debug'], "Invalid column name: ['bar', 'bar']") + @simulate('Base_getRequestUrl', '*args, **kwargs', 'return "http://example.org/bar"') @simulate('Base_getRequestHeader', '*args, **kwargs', @@ -2231,7 +2259,7 @@ return context.getPortalObject().portal_catalog(portal_type='Foo', sort_on=[('id REQUEST=fake_request, mode="search", local_roles=["Manager"], - query='bar:"foo"', + query='id:"foo"', list_method='Test_listCatalog', select_list=['title', 'uid'], selection_domain=json.dumps({'foo_domain': 'a/a1', 'foo_category': 'a/a2'}), @@ -2250,7 +2278,7 @@ return context.getPortalObject().portal_catalog(portal_type='Foo', sort_on=[('id self.assertEquals( selection.getParams(), { 'local_roles': ['Manager'], - 'full_text': 'bar:"foo"', + 'full_text': 'id:"foo"', 'ignore_unknown_columns': True, 'portal_type': ['Foo'], 'limit': 1000 diff --git a/bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_listbox_zuite/testListboxQueryRejectUnknownColumn.xml b/bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_listbox_zuite/testListboxQueryRejectUnknownColumn.xml new file mode 100644 index 0000000000..74984918d4 --- /dev/null +++ b/bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_listbox_zuite/testListboxQueryRejectUnknownColumn.xml @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_bind_names</string> </key> + <value> + <object> + <klass> + <global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/> + </klass> + <tuple/> + <state> + <dictionary> + <item> + <key> <string>_asgns</string> </key> + <value> + <dictionary> + <item> + <key> <string>name_subpath</string> </key> + <value> <string>traverse_subpath</string> </value> + </item> + </dictionary> + </value> + </item> + </dictionary> + </state> + </object> + </value> + </item> + <item> + <key> <string>content_type</string> </key> + <value> <string>text/html</string> </value> + </item> + <item> + <key> <string>expand</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>id</string> </key> + <value> <string>testListboxQueryRejectUnknownColumn</string> </value> + </item> + <item> + <key> <string>output_encoding</string> </key> + <value> <string>utf-8</string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <unicode></unicode> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_listbox_zuite/testListboxQueryRejectUnknownColumn.zpt b/bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_listbox_zuite/testListboxQueryRejectUnknownColumn.zpt new file mode 100644 index 0000000000..da8d011ceb --- /dev/null +++ b/bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_listbox_zuite/testListboxQueryRejectUnknownColumn.zpt @@ -0,0 +1,53 @@ +<html xmlns:tal="http://xml.zope.org/namespaces/tal" + xmlns:metal="http://xml.zope.org/namespaces/metal"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<title>Test RenderJS UI</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">Test RenderJS UI</td></tr> +</thead><tbody> +<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" /> + +<!-- Clean Up --> +<tr> + <td>open</td> + <td>${base_url}/bar_module/ListBoxZuite_reset</td> + <td></td> +</tr> + +<tr> + <td>assertTextPresent</td> + <td>Reset Successfully.</td> + <td></td> +</tr> + +<!-- Initialize --> +<tr> + <td>open</td> + <td>${base_url}/web_site_module/renderjs_runner/#/foo_module</td> + <td></td> +</tr> + +<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_listbox_loaded" /> + +<tal:block tal:define="search_query python: 'bar:"foo"'"> + <tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/search_in_form_list" /> +</tal:block> + +<tr> + <td>assertElementPresent</td> + <td>//span[text()="Invalid Search Criteria"]</td> + <td></td> +</tr> + +<tal:block tal:define="parsed_query python: 'bar: "foo"'; + search_query python: ''"> + <tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/check_search_in_form_list" /> +</tal:block> + +</tbody></table> +</body> +</html> \ No newline at end of file diff --git a/bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_page_zuite/testPageActionBackLinkOnModule.zpt b/bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_page_zuite/testPageActionBackLinkOnModule.zpt index 4731d5dcc8..f27778def0 100644 --- a/bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_page_zuite/testPageActionBackLinkOnModule.zpt +++ b/bt5/erp5_web_renderjs_ui_test/PathTemplateItem/portal_tests/renderjs_ui_page_zuite/testPageActionBackLinkOnModule.zpt @@ -19,12 +19,12 @@ <tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_app_loaded" /> <tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_listbox_loaded" /> -<tal:block tal:define="search_query python: 'foo:"bar" AND barfoo'"> +<tal:block tal:define="search_query python: 'title:"bar" AND barfoo'"> <tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/search_in_form_list" /> </tal:block> <tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_listbox_loaded" /> -<tal:block tal:define="parsed_query python: 'foo: "bar"'; +<tal:block tal:define="parsed_query python: 'title: "bar"'; search_query python: 'barfoo'"> <tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/check_search_in_form_list" /> </tal:block> @@ -69,7 +69,7 @@ <td>Foos</td> <td></td> </tr> -<tal:block tal:define="parsed_query python: 'foo: "bar"'; +<tal:block tal:define="parsed_query python: 'title: "bar"'; search_query python: 'barfoo'"> <tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/check_search_in_form_list" /> </tal:block> -- 2.30.9