Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions cl_sii/dte/data_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

import cl_sii.contribuyente.constants
import cl_sii.rut.constants
from cl_sii.libs import encoding_utils
from cl_sii.libs import tz_utils
from cl_sii.rut import Rut

Expand Down Expand Up @@ -361,11 +360,13 @@ class DteDataL2(DteDataL1):
DTE's digital signature's value (raw bytes, without base64 encoding).
"""

signature_x509_cert_pem: Optional[bytes] = dc_field(default=None)
signature_x509_cert_der: Optional[bytes] = dc_field(default=None)
"""
DTE's digital signature's PEM-encoded X.509 cert.
DTE's digital signature's DER-encoded X.509 cert.

PEM-encoded implies base64-encoded.
.. seealso::
Functions :func:`cl_sii.libs.crypto_utils.load_der_x509_cert`
and :func:`cl_sii.libs.crypto_utils.x509_cert_der_to_pem`.
"""

emisor_giro: Optional[str] = dc_field(default=None)
Expand Down Expand Up @@ -415,12 +416,11 @@ def __post_init__(self) -> None:
validate_clean_bytes(self.signature_value)
validate_non_empty_bytes(self.signature_value)

if self.signature_x509_cert_pem is not None:
if not isinstance(self.signature_x509_cert_pem, bytes):
raise TypeError("Inappropriate type of 'signature_x509_cert_pem'.")
validate_clean_bytes(self.signature_x509_cert_pem)
validate_non_empty_bytes(self.signature_x509_cert_pem)
encoding_utils.validate_base64(self.signature_x509_cert_pem)
if self.signature_x509_cert_der is not None:
if not isinstance(self.signature_x509_cert_der, bytes):
raise TypeError("Inappropriate type of 'signature_x509_cert_der'.")
validate_clean_bytes(self.signature_x509_cert_der)
validate_non_empty_bytes(self.signature_x509_cert_der)

if self.emisor_giro is not None:
if not isinstance(self.emisor_giro, str):
Expand Down
4 changes: 2 additions & 2 deletions cl_sii/dte/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ def parse_dte_xml(xml_doc: XmlElement) -> data_models.DteDataL2:

signature_signature_value = encoding_utils.decode_base64_strict(
signature_signature_value_em.text.strip())
signature_key_info_x509_cert_pem = encoding_utils.clean_base64(
signature_key_info_x509_cert_der = encoding_utils.decode_base64_strict(
signature_key_info_x509_cert_em.text.strip())

return data_models.DteDataL2(
Expand All @@ -469,7 +469,7 @@ def parse_dte_xml(xml_doc: XmlElement) -> data_models.DteDataL2:
fecha_vencimiento_date=fecha_vencimiento_value,
firma_documento_dt=tmst_firma_value,
signature_value=signature_signature_value,
signature_x509_cert_pem=signature_key_info_x509_cert_pem,
signature_x509_cert_der=signature_key_info_x509_cert_der,
emisor_giro=emisor_giro_value,
emisor_email=emisor_email_value,
receptor_email=receptor_email_value,
Expand Down
20 changes: 16 additions & 4 deletions tests/test_dte_data_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import unittest
from datetime import date, datetime

from cl_sii.libs import encoding_utils
from cl_sii.libs import tz_utils
from cl_sii.rut import Rut # noqa: F401

Expand All @@ -11,6 +12,8 @@
validate_contribuyente_razon_social, validate_dte_folio, validate_dte_monto_total,
)

from .utils import read_test_file_bytes


class DteNaturalKeyTest(unittest.TestCase):

Expand Down Expand Up @@ -138,6 +141,15 @@ def test_vendedor_rut_deudor_rut(self) -> None:

class DteDataL2Test(unittest.TestCase):

@classmethod
def setUpClass(cls) -> None:
super().setUpClass()

cls.dte_1_xml_signature_value = encoding_utils.decode_base64_strict(read_test_file_bytes(
'test_data/sii-crypto/DTE--76354771-K--33--170-signature-value-base64.txt'))
cls.dte_1_xml_cert_der = read_test_file_bytes(
'test_data/sii-crypto/DTE--76354771-K--33--170-cert.der')

def setUp(self) -> None:
super().setUp()

Expand All @@ -154,8 +166,8 @@ def setUp(self) -> None:
firma_documento_dt=tz_utils.convert_naive_dt_to_tz_aware(
dt=datetime(2019, 4, 1, 1, 36, 40),
tz=DteDataL2.DATETIME_FIELDS_TZ),
signature_value=None,
signature_x509_cert_pem=None,
signature_value=self.dte_1_xml_signature_value,
signature_x509_cert_der=self.dte_1_xml_cert_der,
emisor_giro='Ingenieria y Construccion',
emisor_email='hello@example.com',
receptor_email=None,
Expand All @@ -181,8 +193,8 @@ def test_as_dict(self) -> None:
firma_documento_dt=tz_utils.convert_naive_dt_to_tz_aware(
dt=datetime(2019, 4, 1, 1, 36, 40),
tz=DteDataL2.DATETIME_FIELDS_TZ),
signature_value=None,
signature_x509_cert_pem=None,
signature_value=self.dte_1_xml_signature_value,
signature_x509_cert_der=self.dte_1_xml_cert_der,
emisor_giro='Ingenieria y Construccion',
emisor_email='hello@example.com',
receptor_email=None,
Expand Down
15 changes: 13 additions & 2 deletions tests/test_dte_parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,9 +295,13 @@ def setUpClass(cls) -> None:
cls.dte_clean_xml_1_cert_pem_bytes = encoding_utils.clean_base64(
crypto_utils.remove_pem_cert_header_footer(
read_test_file_bytes('test_data/sii-crypto/DTE--76354771-K--33--170-cert.pem')))
cls.dte_clean_xml_1_cert_der = read_test_file_bytes(
'test_data/sii-crypto/DTE--76354771-K--33--170-cert.der')
cls.dte_clean_xml_2_cert_pem_bytes = encoding_utils.clean_base64(
crypto_utils.remove_pem_cert_header_footer(
read_test_file_bytes('test_data/sii-crypto/DTE--76399752-9--33--25568-cert.pem')))
cls.dte_clean_xml_2_cert_der = read_test_file_bytes(
'test_data/sii-crypto/DTE--76399752-9--33--25568-cert.der')

cls._TEST_DTE_1_SIGNATURE_VALUE = encoding_utils.decode_base64_strict(
read_test_file_bytes(
Expand Down Expand Up @@ -327,6 +331,13 @@ def test_data(self):
b"\xe5]E\xed\x9c\xcb\xc2\x84\x15i\xd0tT]\x8b\x8a\x1f'\xe9\x0b:\x88\x05|\xa0b\xb2"
b"\x19{\x1cW\x80\xe4\xa7*\xef\xf2\x1a")

self.assertEqual(
crypto_utils.x509_cert_pem_to_der(self.dte_clean_xml_1_cert_pem_bytes),
self.dte_clean_xml_1_cert_der)
self.assertEqual(
crypto_utils.x509_cert_pem_to_der(self.dte_clean_xml_2_cert_pem_bytes),
self.dte_clean_xml_2_cert_der)

def test_parse_dte_xml_ok_1(self) -> None:
xml_doc = xml_utils.parse_untrusted_xml(self.dte_clean_xml_1_xml_bytes)

Expand All @@ -347,7 +358,7 @@ def test_parse_dte_xml_ok_1(self) -> None:
dt=datetime(2019, 4, 1, 1, 36, 40),
tz=DteDataL2.DATETIME_FIELDS_TZ),
signature_value=self._TEST_DTE_1_SIGNATURE_VALUE,
signature_x509_cert_pem=self.dte_clean_xml_1_cert_pem_bytes,
signature_x509_cert_der=self.dte_clean_xml_1_cert_der,
emisor_giro='Ingenieria y Construccion',
emisor_email='ENACONLTDA@GMAIL.COM',
receptor_email=None,
Expand All @@ -373,7 +384,7 @@ def test_parse_dte_xml_ok_2(self) -> None:
dt=datetime(2019, 3, 28, 13, 59, 52),
tz=DteDataL2.DATETIME_FIELDS_TZ),
signature_value=self._TEST_DTE_2_SIGNATURE_VALUE,
signature_x509_cert_pem=self.dte_clean_xml_2_cert_pem_bytes,
signature_x509_cert_der=self.dte_clean_xml_2_cert_der,
emisor_giro='COMERCIALIZACION DE PRODUCTOS PARA EL HOGAR',
emisor_email='ANGEL.PEZO@APCASESORIAS.CL',
receptor_email=None,
Expand Down