diff --git a/pytrustnfe/certificado.py b/pytrustnfe/certificado.py index a4f0241..1971f15 100644 --- a/pytrustnfe/certificado.py +++ b/pytrustnfe/certificado.py @@ -4,7 +4,6 @@ from uuid import uuid4 -import os.path from OpenSSL import crypto @@ -13,6 +12,13 @@ class Certificado(object): self.pfx = pfx self.password = password + def save_pfx(self): + pfx_temp = '/tmp/' + uuid4().hex + arq_temp = open(pfx_temp, 'w') + arq_temp.write(self.pfx) + arq_temp.close() + return pfx_temp + def extract_cert_and_key_from_pfx(pfx, password): pfx = crypto.load_pkcs12(pfx, password) @@ -25,6 +31,7 @@ def extract_cert_and_key_from_pfx(pfx, password): return cert, key + def save_cert_key(cert, key): cert_temp = '/tmp/' + uuid4().hex key_temp = '/tmp/' + uuid4().hex diff --git a/pytrustnfe/nfe/__init__.py b/pytrustnfe/nfe/__init__.py index 2a9ccf5..8d24ceb 100644 --- a/pytrustnfe/nfe/__init__.py +++ b/pytrustnfe/nfe/__init__.py @@ -6,7 +6,7 @@ import os from lxml import etree from .comunicacao import Comunicacao -from .assinatura import assinar, Assinatura +from .assinatura import sign_xml, Assinatura from pytrustnfe import utils from pytrustnfe.xml import render_xml @@ -40,7 +40,7 @@ class NFe(Comunicacao): xml = render_xml(path, 'nfeEnv.xml', **nfe) xmlElem = etree.fromstring(xml) - xml_signed = assinar(xmlElem, self.cert, self.key, '#%s' % nfe_id) + xml_signed = sign_xml(xmlElem, self.cert, self.key, '#%s' % nfe_id) xml_response, obj = self._executar_consulta(xml_signed) diff --git a/pytrustnfe/nfe/assinatura.py b/pytrustnfe/nfe/assinatura.py index 2b4a53f..eaf6b35 100644 --- a/pytrustnfe/nfe/assinatura.py +++ b/pytrustnfe/nfe/assinatura.py @@ -31,27 +31,21 @@ def recursively_empty(e): return all((recursively_empty(c) for c in e.iterchildren())) -def assinar(xml, cert, key, reference): - context = etree.iterwalk(xml) - for dummy, elem in context: - parent = elem.getparent() - if recursively_empty(elem): - parent.remove(elem) - - element = xml.find('{' + xml.nsmap[None] + '}NFe') +def sign_xml(xml, cert, key): + parser = etree.XMLParser(remove_blank_text=True, remove_comments=True) + elem = etree.fromstring(xml, parser=parser) + signer = XMLSigner( digest_algorithm=u'sha1', signature_algorithm="rsa-sha1", - method=methods.enveloped, + method=methods.enveloping, c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') ns = {} ns[None] = signer.namespaces['ds'] signer.namespaces = ns - signed_root = signer.sign(element, key=str(key), cert=cert, - reference_uri=reference) + signed_root = signer.sign(elem, key=str(key), cert=cert) + + return etree.tostring(signed_root) - xml.remove(element) - xml.append(signed_root) - return etree.tostring(xml) class Assinatura(object): @@ -84,12 +78,12 @@ class Assinatura(object): self._inicializar_cripto() try: doc_xml = libxml2.parseMemory( - xml.encode('utf-8'), len(xml.encode('utf-8'))) + xml, len(xml)) signNode = xmlsec.TmplSignature(doc_xml, xmlsec.transformInclC14NId(), xmlsec.transformRsaSha1Id(), None) - doc_xml.getLastChild().addChild(signNode) + doc_xml.getRootElement().addChild(signNode) refNode = signNode.addReference(xmlsec.transformSha1Id(), None, reference, None) @@ -129,4 +123,4 @@ class Assinatura(object): return xml finally: doc_xml.freeDoc() - self._finalizar_cripto() + # self._finalizar_cripto() diff --git a/pytrustnfe/nfse/paulistana/__init__.py b/pytrustnfe/nfse/paulistana/__init__.py index 1883f34..7edc38f 100644 --- a/pytrustnfe/nfse/paulistana/__init__.py +++ b/pytrustnfe/nfse/paulistana/__init__.py @@ -5,44 +5,30 @@ import os import logging import suds +from OpenSSL import crypto +from base64 import b64encode, b64decode from uuid import uuid4 -from lxml import etree from pytrustnfe.xml import render_xml, valida_schema, sanitize_response from pytrustnfe.client import get_authenticated_client from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key +from pytrustnfe.nfe.assinatura import Assinatura -from signxml import XMLSigner -from signxml import methods - -def sign_xml(xml, cert, key): - parser = etree.XMLParser(remove_blank_text=True, remove_comments=True) - elem = etree.fromstring(xml, parser=parser) - - root = etree.Element('root') - rps = elem.find('RPS') - - signer = XMLSigner( - digest_algorithm=u'sha1', signature_algorithm="rsa-sha1", - method=methods.enveloped, - c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') - ns = {} - ns[None] = signer.namespaces['ds'] - signer.namespaces = ns - signed_root = signer.sign(rps, key=str(key), cert=cert) - - root.append( - signed_root.find('{http://www.w3.org/2000/09/xmldsig#}Signature')) - elem.remove(rps) - elem.append(signed_root) - elem.append(root.find('{http://www.w3.org/2000/09/xmldsig#}Signature')) - return etree.tostring(elem) +def sign_tag(certificado, **kwargs): + pkcs12 = crypto.load_pkcs12(certificado.pfx, certificado.password) + key = pkcs12.get_privatekey() + for item in kwargs['nfse']['lista_rps']: + signed = crypto.sign(key, item['assinatura'], 'SHA1') + item['assinatura'] = b64encode(signed) def _send(certificado, method, **kwargs): # A little hack to test path = os.path.join(os.path.dirname(__file__), 'templates') + if method == 'TesteEnvioLoteRPS' or method == 'EnvioLoteRPS': + sign_tag(certificado, **kwargs) + if method == 'TesteEnvioLoteRPS': xml = render_xml(path, 'EnvioLoteRPS.xml', **kwargs) else: @@ -54,7 +40,9 @@ def _send(certificado, method, **kwargs): cert_path, key_path = save_cert_key(cert, key) client = get_authenticated_client(base_url, cert_path, key_path) - xml_signed = sign_xml(xml, cert, key) + pfx_path = certificado.save_pfx() + signer = Assinatura(pfx_path, certificado.password) + xml_signed = signer.assina_xml(xml, '') try: response = getattr(client.service, method)(1, xml_signed) diff --git a/pytrustnfe/nfse/paulistana/templates/EnvioLoteRPS.xml b/pytrustnfe/nfse/paulistana/templates/EnvioLoteRPS.xml index 5cc5e67..33a3fcd 100644 --- a/pytrustnfe/nfse/paulistana/templates/EnvioLoteRPS.xml +++ b/pytrustnfe/nfse/paulistana/templates/EnvioLoteRPS.xml @@ -4,8 +4,8 @@ {{ nfse.cpf_cnpj }} false - 2016-02-08 - 2016-02-08 + {{ nfse.data_inicio }} + {{ nfse.data_fim }} 1 {{ nfse.total_servicos }} {{ nfse.total_deducoes }} @@ -22,8 +22,8 @@ {{ rps.data_emissao }} N T - 1000 - 0.00 + {{ rps.valor_servico }} + {{ rps.valor_deducao }} 0.00 0.00 0.00 @@ -40,7 +40,9 @@ {{ rps.tomador.cpf_cnpj }} {% endif %} - 23354900 + {% if rps.tomador.inscricao_municipal -%} + {{ rps.tomador.inscricao_municipal }} + {% endif %} {{ rps.tomador.razao_social }} {{ rps.tomador.tipo_logradouro }}