possibilité de n'autoriser que certaines expressions python (#76103) #218

Merged
fpeters merged 2 commits from wip/76103-python-restrict-expressions into main 2023-04-03 09:55:05 +02:00
3 changed files with 40 additions and 9 deletions

View File

@ -185,7 +185,7 @@ def test_python_datasource_errors(pub, error_email, http_requests, emails, caplo
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
pub.site_options.write(fd)
# running with disabled python expressions
# running with forbidden python expressions
pub.loggederror_class.wipe()
datasource = {
'type': 'formula',
@ -202,6 +202,25 @@ def test_python_datasource_errors(pub, error_email, http_requests, emails, caplo
assert logged_error.workflow_id is None
assert logged_error.summary == 'Unauthorized Python Usage'
# exception list
with open(os.path.join(pub.app_dir, 'allowed-python.txt'), 'w') as fd:
fd.write('blah\n')
pub.loggederror_class.wipe()
assert data_sources.get_items(datasource) == []
assert pub.loggederror_class.count() == 1
assert pub.loggederror_class.select()[0].summary == 'Unauthorized Python Usage'
with open(os.path.join(pub.app_dir, 'allowed-python.txt'), 'a') as fd:
fd.write('%r\n' % ['foo', 'bar'])
pub.loggederror_class.wipe()
assert data_sources.get_items(datasource) == [
('foo', 'foo', 'foo', {'id': 'foo', 'text': 'foo'}),
('bar', 'bar', 'bar', {'id': 'bar', 'text': 'bar'}),
]
assert pub.loggederror_class.count() == 0
def test_python_datasource_with_evalutils(pub):
plain_list = [

View File

@ -3462,7 +3462,9 @@ class FormBackOfficeStatusPage(FormStatusPage):
('template', '%s / %s' % (_('Template'), _('Django Expression')), 'template'),
('html_template', _('HTML Template (WYSIWYG)'), 'html_template'),
]
if get_publisher().has_site_option('disable-python-expressions'):
if get_publisher().has_site_option('disable-python-expressions') or get_publisher().has_site_option(
'forbid-python-expressions'
):
options = [x for x in options if x[0] != 'python-condition']
form.add(
RadiobuttonsWidget,
@ -3481,7 +3483,10 @@ class FormBackOfficeStatusPage(FormStatusPage):
'data-dynamic-display-value': 'django-condition',
},
)
if not get_publisher().has_site_option('disable-python-expressions'):
if not (
get_publisher().has_site_option('disable-python-expressions')
or get_publisher().has_site_option('forbid-python-expressions')
):
form.add(
StringWidget,
'python-condition',

View File

@ -1187,12 +1187,19 @@ class UnauthorizedPythonUsage(Exception):
def eval_python(expression, *args, **kwargs):
# Inherently unsafe, abort if support is forbidden.
if get_publisher().has_site_option('forbid-python-expressions'):
get_publisher().record_error(
_('Unauthorized Python Usage'),
notify=True,
record=True,
)
raise UnauthorizedPythonUsage()
allowed_python_filename = os.path.join(get_publisher().app_dir, 'allowed-python.txt')
allowed = False
if os.path.exists(allowed_python_filename):
with open(allowed_python_filename) as fd:
if expression in fd.read().splitlines():
allowed = True
if not allowed:
get_publisher().record_error(
_('Unauthorized Python Usage'),
notify=True,
record=True,
)
raise UnauthorizedPythonUsage()
# noqa pylint: disable=eval-used
return eval(expression, *args, **kwargs)