Skip to content

Instantly share code, notes, and snippets.

@rodrigorodriguescosta
Created December 22, 2020 19:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rodrigorodriguescosta/b6801af6358c818689f48b90d4134101 to your computer and use it in GitHub Desktop.
Save rodrigorodriguescosta/b6801af6358c818689f48b90d4134101 to your computer and use it in GitHub Desktop.
import falcon
import signxml
from OpenSSL import crypto
from lxml import etree
from signxml import XMLSigner
from wsgiref.simple_server import make_server
def find_between( s, first, last ):
try:
start = s.index( first )
end = s.index( last, start ) + len( last )
return s[start:end]
except ValueError:
return ""
def assina_xml(cert, key, xml_string):
signer = XMLSigner(
method=signxml.methods.enveloped,
signature_algorithm="rsa-sha1",
digest_algorithm='sha1',
c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
# if reference:
# reference = '#%s' % reference
parser = etree.XMLParser(remove_blank_text=True, remove_comments=True, recover=True)
xml_element = etree.fromstring(xml_string.encode(), parser=parser)
reference = '#'+ xml_element.xpath('//@Id')[0]
ns = {}
ns[None] = signer.namespaces['ds']
signer.namespaces = ns
signed_root = signer.sign(
xml_element,
key=key,
cert=cert,
reference_uri=reference)
assinatura = etree.tostring(signed_root).decode()
assinatura = find_between(assinatura, '<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">', '</Signature>')
return assinatura
def extract_cert_and_key_from_pfx(arquivo_pfx, password):
pfx = open(arquivo_pfx, 'rb').read()
try:
pfx = crypto.load_pkcs12(pfx, password)
except Exception as e:
if 'mac verify failure' in str(e):
raise Exception('Senha do certificado inválida')
# PEM formatted private key
key = crypto.dump_privatekey(crypto.FILETYPE_PEM,
pfx.get_privatekey())
# PEM formatted certificate
cert = crypto.dump_certificate(crypto.FILETYPE_PEM,
pfx.get_certificate())
return cert, key
def test():
cert, key = extract_cert_and_key_from_pfx('meu_certificado.pfx', '123456')
# xml = '<enviNFe xmlns="http://www.portalfiscal.inf.br/nfe" versao="4.00"><idLote>1500</idLote><indSinc>0</indSinc><NFe xmlns="http://www.portalfiscal.inf.br/nfe"><infNFe Id="NFe24201019843657000149650010000086901016899378" versao="4.00"><ide><cUF>24</cUF><cNF>01689937</cNF><natOp>VENDA</natOp><mod>65</mod><serie>1</serie><nNF>8690</nNF><dhEmi>2020-10-23T19:28:49-03:00</dhEmi><tpNF>1</tpNF><idDest>1</idDest><cMunFG>2408003</cMunFG><tpImp>4</tpImp><tpEmis>1</tpEmis><cDV>8</cDV><tpAmb>1</tpAmb><finNFe>1</finNFe><indFinal>1</indFinal><indPres>1</indPres><procEmi>0</procEmi><verProc>Sigeflex ERP</verProc></ide><emit><CNPJ>19843657000149</CNPJ><xNome>CASA DO CONSTRUTOR MATERIAIS DE CONSTRUCAO LTDA</xNome><xFant>CASA DO CONSTRUTOR</xFant><enderEmit><xLgr>AVENIDA WILSON ROSADO</xLgr><nro>15</nro><xBairro>ALTO DO SUMARE</xBairro><cMun>2408003</cMun><xMun>MOSSORO</xMun><UF>RN</UF><CEP>59633730</CEP><cPais>1058</cPais><xPais>BRASIL</xPais><fone>8433127000</fone></enderEmit><IE>204051975</IE><CRT>1</CRT></emit><det nItem="1"><prod><cProd>0491.00089.0010PCR</cProd><cEAN>7894174211422</cEAN><xProd>FITA VEDA TUDO QUARTZOLIT 10CM - PC</xProd><NCM>68071000</NCM><CFOP>5102</CFOP><uCom>UN</uCom><qCom>1.0000</qCom><vUnCom>6.000000</vUnCom><vProd>6.00</vProd><cEANTrib>7894174211422</cEANTrib><uTrib>UN</uTrib><qTrib>1.0000</qTrib><vUnTrib>6.00000</vUnTrib><indTot>1</indTot></prod><imposto><vTotTrib>2.00</vTotTrib><ICMS><ICMSSN102><orig>0</orig><CSOSN>102</CSOSN></ICMSSN102></ICMS><PIS><PISAliq><CST>01</CST><vBC>6.00</vBC><pPIS>1.65</pPIS><vPIS>0.10</vPIS></PISAliq></PIS><COFINS><COFINSOutr><CST>99</CST><qBCProd>0</qBCProd><vAliqProd>7.60</vAliqProd><vCOFINS>0.46</vCOFINS></COFINSOutr></COFINS></imposto></det><total><ICMSTot><vBC>0.00</vBC><vICMS>0.00</vICMS><vICMSDeson>0.00</vICMSDeson><vFCP>0.00</vFCP><vBCST>0.00</vBCST><vST>0.00</vST><vFCPST>0.00</vFCPST><vFCPSTRet>0.00</vFCPSTRet><vProd>6.00</vProd><vFrete>0.00</vFrete><vSeg>0.00</vSeg><vDesc>0.00</vDesc><vII>0.00</vII><vIPI>0.00</vIPI><vIPIDevol>0.00</vIPIDevol><vPIS>0.10</vPIS><vCOFINS>0.46</vCOFINS><vOutro>0.00</vOutro><vNF>6.00</vNF><vTotTrib>2.00</vTotTrib></ICMSTot></total><transp><modFrete>9</modFrete></transp><pag><detPag><tPag>01</tPag><vPag>6.00</vPag></detPag></pag></infNFe></NFe></enviNFe>'
xml = '<test><subelement aaaa="123"></subelement></test>'
assinatura = assina_xml(cert, key, xml)
xml = xml % (infNfe + assinatura)
print(xml)
class NfeResource(object):
def on_post(self, req, resp):
cert = req.get_param("cert", required=True)
key = req.get_param("key", required=True)
xml = req.get_param("xml", required=True)
xml_assinado = assina_xml(cert, key, xml)
resp.media = xml_assinado
app = falcon.API()
app.req_options.auto_parse_form_urlencoded=True
nfe = NfeResource()
app.add_route('/assina_xml', nfe)
api = application = falcon.API()
if __name__ == '__main__':
with make_server('', 8181, app) as httpd:
print('Serving on port 8181...')
# Serve until process is killed
httpd.serve_forever()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment