From c2dd6f82912c43b54d4cf46ed7daf1d3bcc1a9d7 Mon Sep 17 00:00:00 2001 From: Tom Blauwendraat Date: Fri, 9 Sep 2022 13:38:34 +0200 Subject: [PATCH] [IMP] sanitize forbidden chrs from xml --- .../models/xaf_auditfile_export.py | 40 +++++++++++++++++++ .../test_l10n_nl_xaf_auditfile_export.py | 18 +++++++++ 2 files changed, 58 insertions(+) diff --git a/l10n_nl_xaf_auditfile_export/models/xaf_auditfile_export.py b/l10n_nl_xaf_auditfile_export/models/xaf_auditfile_export.py index 3e9961c26..b0a5889fd 100644 --- a/l10n_nl_xaf_auditfile_export/models/xaf_auditfile_export.py +++ b/l10n_nl_xaf_auditfile_export/models/xaf_auditfile_export.py @@ -6,6 +6,7 @@ import logging import os import shutil +import sys import time import traceback import zipfile @@ -35,6 +36,41 @@ def memory_info(): return pmem.vms +# http://stackoverflow.com/questions/1707890 +# /fast-way-to-filter-illegal-xml-unicode-chars-in-python +ILLEGAL_RANGES = [ + (0x00, 0x08), + (0x0B, 0x1F), + (0x7F, 0x84), + (0x86, 0x9F), + (0xD800, 0xDFFF), + (0xFDD0, 0xFDDF), + (0xFFFE, 0xFFFF), + (0x1FFFE, 0x1FFFF), + (0x2FFFE, 0x2FFFF), + (0x3FFFE, 0x3FFFF), + (0x4FFFE, 0x4FFFF), + (0x5FFFE, 0x5FFFF), + (0x6FFFE, 0x6FFFF), + (0x7FFFE, 0x7FFFF), + (0x8FFFE, 0x8FFFF), + (0x9FFFE, 0x9FFFF), + (0xAFFFE, 0xAFFFF), + (0xBFFFE, 0xBFFFF), + (0xCFFFE, 0xCFFFF), + (0xDFFFE, 0xDFFFF), + (0xEFFFE, 0xEFFFF), + (0xFFFFE, 0xFFFFF), + (0x10FFFE, 0x10FFFF), +] +UNICODE_SANITIZE_TRANSLATION = {} +for low, high in ILLEGAL_RANGES: + if low > sys.maxunicode: # pragma: no cover + continue + for c in range(low, high + 1): + UNICODE_SANITIZE_TRANSLATION[c] = ord(" ") + + class XafAuditfileExport(models.Model): _name = "xaf.auditfile.export" _description = "XAF auditfile export" @@ -133,6 +169,9 @@ def button_generate(self): 1, ) ) + # removes invalid characters from xml + if not self.env.context.get("dont_sanitize_xml"): + xml = xml.translate(UNICODE_SANITIZE_TRANSLATION) filename = self.name + ".xaf" filename = filename.replace(os.sep, " ") @@ -183,6 +222,7 @@ def button_generate(self): logging.getLogger(__name__).error(e) logging.getLogger(__name__).info(traceback.format_exc()) self.message_post(body=e) + self.auditfile_success = False finally: shutil.rmtree(tmpdir) diff --git a/l10n_nl_xaf_auditfile_export/tests/test_l10n_nl_xaf_auditfile_export.py b/l10n_nl_xaf_auditfile_export/tests/test_l10n_nl_xaf_auditfile_export.py index 49fb51720..55bd87b8f 100644 --- a/l10n_nl_xaf_auditfile_export/tests/test_l10n_nl_xaf_auditfile_export.py +++ b/l10n_nl_xaf_auditfile_export/tests/test_l10n_nl_xaf_auditfile_export.py @@ -95,6 +95,7 @@ def test_02_export_success(self): self.assertTrue(record.date_generated) self.assertTrue(record.fiscalyear_name) self.assertFalse(record.unit4) + self.assertTrue(record.auditfile_success) zf = BytesIO(base64.b64decode(record.auditfile)) with ZipFile(zf, "r") as archive: @@ -111,6 +112,7 @@ def test_03_export_error(self): self.assertTrue(record) self.assertTrue(record.name) + self.assertFalse(record.auditfile_success) # still contains the faulty auditfile for debugging purposes self.assertTrue(record.auditfile) self.assertTrue(record.auditfile_name) @@ -197,3 +199,19 @@ def test_07_do_not_include_section_and_note_move_lines(self): line_count = record.get_move_line_count() parsed_line_count = get_transaction_line_count_from_xml(record.auditfile) self.assertEqual(parsed_line_count, line_count) + + @mute_logger("odoo.addons.l10n_nl_xaf_auditfile_export.models.xaf_auditfile_export") + def test_08_invalid_characters(self): + """Error because of invalid characters in an auditfile""" + record = ( + self.env["xaf.auditfile.export"] + .with_context(dont_sanitize_xml=True) + .create({}) + ) + # add an invalid character + record.company_id.name += chr(0x0B) + record.button_generate() + + self.assertTrue(record) + self.assertTrue(record.name) + self.assertFalse(record.auditfile_success)