From c6d266c74d462557d4bbf9216102675b34f24cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Thu, 28 Dec 2023 17:01:16 +0100 Subject: [PATCH] misc: check XML model files are proper UTF-8 (#58791) --- tests/workflow/test_export_to_model.py | 19 +++++++++++-------- wcs/wf/export_to_model.py | 11 ++++++++--- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/tests/workflow/test_export_to_model.py b/tests/workflow/test_export_to_model.py index 5bdbfd019..57e7ab2cf 100644 --- a/tests/workflow/test_export_to_model.py +++ b/tests/workflow/test_export_to_model.py @@ -4,6 +4,7 @@ import time import zipfile import pytest +from django.utils.encoding import force_bytes from PIL import Image from pyzbar.pyzbar import ZBarSymbol from pyzbar.pyzbar import decode as zbar_decode_qrcode @@ -299,10 +300,6 @@ def test_export_to_model_django_template(pub): def test_export_to_model_xml(pub): - LoggedError = pub.loggederror_class - if LoggedError: - LoggedError.wipe() - formdef = FormDef() formdef.name = 'foo-export-to-template-with-django' formdef.fields = [ @@ -320,9 +317,10 @@ def test_export_to_model_xml(pub): item.attach_to_history = True def run(template, filename='/foo/template.xml', content_type='application/xml'): + pub.loggederror_class.wipe() upload = QuixoteUpload(filename, content_type=content_type) upload.fp = io.BytesIO() - upload.fp.write(template.encode()) + upload.fp.write(force_bytes(template)) upload.fp.seek(0) item.model_file = UploadedFile(pub.app_dir, None, upload) item.convert_to_pdf = False @@ -340,18 +338,23 @@ def test_export_to_model_xml(pub): assert run(template='{{ form_var_string }}', filename='/foo/template.svg') == 'écho' # unknown file format - with pytest.raises(UploadValidationError): + with pytest.raises(UploadValidationError) as e: run( template='{{ form_var_string }}', filename='/foo/template.txt', content_type='application/octet-stream', ) + assert str(e.value) == 'Only OpenDocument and XML files can be used.' + + # invalid UTF-8 + with pytest.raises(UploadValidationError) as e: + assert run(template=b'test \xE0 {{form_var_string}}') == '' + assert str(e.value) == 'XML model files must be UTF-8.' # malformed XML - assert not LoggedError or LoggedError.count() == 0 assert run(template='{{ form_var_string }}') == 'écho' # on error in the XML correctness no exception is raised but an error is logged - assert not LoggedError or LoggedError.count() == 1 + assert pub.loggederror_class.count() == 1 @pytest.mark.parametrize('filename', ['template-form-details.odt', 'template-form-details-no-styles.odt']) diff --git a/wcs/wf/export_to_model.py b/wcs/wf/export_to_model.py index 0d1248389..e27e561d0 100644 --- a/wcs/wf/export_to_model.py +++ b/wcs/wf/export_to_model.py @@ -361,13 +361,18 @@ class ExportToModel(WorkflowStatusItem): # XML fp.seek(0) - xml_prefix = fp.read(1) + xml_content = fp.read() fp.seek(0) if (upload.content_type and upload.content_type in ('text/xml', 'application/xml')) or ( - upload.base_filename and upload.base_filename.endswith('.xml') and xml_prefix == b'<' + upload.base_filename and upload.base_filename.endswith('.xml') and xml_content.startswith(b'<') ): + # check XML content is valid UTF-8 + try: + xml_content.decode('utf-8') + except UnicodeDecodeError: + raise UploadValidationError(_('XML model files must be UTF-8.')) return 'xml' - raise UploadValidationError(_('Only OpenDocument and XML files can be used')) + raise UploadValidationError(_('Only OpenDocument and XML files can be used.')) def get_parameters(self): parameters = ('model_file',) -- 2.39.2