Skip to content

Commit

Permalink
add sign_xml class method
Browse files Browse the repository at this point in the history
  • Loading branch information
rvalyi committed Apr 1, 2024
1 parent 04dfbdf commit 295e16d
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 0 deletions.
37 changes: 37 additions & 0 deletions nfelib/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Copyright (C) 2023 Raphaël Valyi - Akretion <[email protected]>

import os
from os import environ
from pathlib import Path
from typing import Any, Dict, List, Optional

Expand Down Expand Up @@ -96,6 +97,33 @@ def _get_schema_path(cls) -> str:
)
return "undef"

@classmethod
def sign_xml(
cls,
xml: str,
pkcs12_data: Optional[bytes] = None,
pkcs12_password: Optional[str] = None,
doc_id: Optional[str] = None,
) -> str:
"""Sign xml file with pkcs12_data/pkcs12_password certificate.
Sometimes you need to test with a real certificate.
You can use the CERT_FILE and CERT_PASSWORD environment
variables to do tests with a real certificate data.
"""
try:
from erpbrasil.assinatura import certificado as cert
from erpbrasil.assinatura.assinatura import Assinatura
except ImportError:
raise (RuntimeError("erpbrasil.assinatura package is not installed!"))

certificate = cert.Certificado(
arquivo=environ.get("CERT_FILE", pkcs12_data),
senha=environ.get("CERT_PASSWORD", pkcs12_password),
)
xml_etree = etree.fromstring(xml.encode("utf-8"))
return Assinatura(certificate).assina_xml2(xml_etree, doc_id)

def to_xml(self, pretty_print: bool = True, ns_map: Optional[Dict] = None) -> str:
"""Serialize binding as an xml string."""
serializer = XmlSerializer(SerializerConfig(pretty_print=pretty_print))
Expand All @@ -113,3 +141,12 @@ def validate_xml(self, schema_path: Optional[str] = None) -> List:
"""Serialize binding as xml, validate it and return possible errors."""
xml = self.to_xml()
return self.schema_validation(xml, schema_path)

# this was an attempt to keep the signature inside the
# binding before serializing it again. But at the moment it fails
# because xsdata will serialize the Signature elements with their namespaces.
# def sign(self, pkcs12_data: bytes = None, pkcs12_password: str = None, doc_id: str=None):
# xml = self.to_xml(pretty_print=False)
# signed_xml = self.sign_xml(xml, pkcs12_data, pkcs12_password, element)
# nfe = self.from_xml(signed_xml)
# return nfe
31 changes: 31 additions & 0 deletions tests/nfe/test_nfe.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,37 @@ def test_patched_xsdata_for_ipi(self):
== "typing.Union[nfelib.nfe.bindings.v4_0.leiaute_nfe_v4_00.Tipi, NoneType]"
)

def test_sign(self):
path = os.path.join("nfelib", "nfe", "samples", "v4_0", "leiauteNFe")
filename = "42210775277525000178550030000266631762885493-procNFe.xml"
input_file = os.path.join(path, filename)
parser = XmlParser()
nfe = parser.from_path(Path(input_file))
serializer = XmlSerializer(config=SerializerConfig(pretty_print=False))
xml = serializer.render(
obj=nfe, ns_map={None: "http://www.portalfiscal.inf.br/nfe"}
)
self.assertNotIn("<X509Certificate>", xml)
valid = (True,)
cert_password = "123456"
issuer = "EMISSOR A TESTE"
country = "BR"
subject = "CERTIFICADO VALIDO TESTE"
from erpbrasil.assinatura import misc

cert_data = misc.create_fake_certificate_file(
valid, cert_password, issuer, country, subject
)
signed_xml = nfe.sign_xml(xml, cert_data, cert_password, nfe.NFe.infNFe.Id)
self.assertIn("<X509Certificate>", signed_xml)

# this was an attempt to keep the signature inside the
# binding before serializing it again. But at the moment it fails
# because xsdata will serialize the Signature elements with their namespaces.
# signed_nfe = nfe.sign(cert_data, cert_password, nfe.NFe.infNFe.Id)
# signed_xml2 = signed_nfe.to_xml(pretty_print=False)
# self.assertEqual(signed_xml, signed_xml2)

def test_in_out_leiauteNFe(self):
path = os.path.join("nfelib", "nfe", "samples", "v4_0", "leiauteNFe")
for filename in os.listdir(path):
Expand Down

0 comments on commit 295e16d

Please sign in to comment.