410 lines
12 KiB
Plaintext
410 lines
12 KiB
Plaintext
IMPORT util
|
|
IMPORT com
|
|
IMPORT os
|
|
IMPORT security
|
|
IMPORT XML
|
|
|
|
|
|
CONSTANT dpy_verb=TRUE -- send messages to standard output
|
|
|
|
DEFINE doc xml.DomDocument
|
|
|
|
DEFINE req com.HTTPServiceRequest
|
|
DEFINE url,msg,method,headers,mensaje,filexml,tipoecf,rnc_e,rnc_c,e_ncf,fileacuse,resp,
|
|
ruta_firmados,fileafirmar_f STRING,
|
|
tout, n, x,rcode INTEGER,
|
|
start_time DATETIME YEAR TO SECOND
|
|
|
|
DEFINE d0 DATETIME YEAR TO SECOND
|
|
|
|
DEFINE a om.SaxAttributes
|
|
DEFINE out om.SaxDocumentHandler,
|
|
i INT,
|
|
|
|
fechaFirma DATETIME YEAR TO SECOND
|
|
|
|
MAIN
|
|
|
|
LET filexml = ".\\ArchRecibidos\\"
|
|
LET fileacuse = ".\\Acuses\\"
|
|
LET ruta_firmados = fgl_getenv("RUTA_XML_FIRMADOS")
|
|
CALL recepcion()
|
|
END MAIN
|
|
|
|
PUBLIC FUNCTION recepcion () ATTRIBUTES(WSGet,
|
|
WSPath="/{servicio}/api/ecf/",
|
|
WSDescription="Api para la recepcion de los e-NCF" )
|
|
|
|
#, WSThrows="400:Invalid,406:Should not happen"
|
|
DEFINE urlhost STRING
|
|
|
|
CALL check_utf8() RETURNING x, msg
|
|
IF x != 0 THEN
|
|
DISPLAY "ERROR: ", msg
|
|
EXIT PROGRAM 1
|
|
END IF
|
|
|
|
CALL show_verb("Inicio Api server: ...")
|
|
|
|
-- Normally, the port is set by the GAS for load balancing
|
|
-- For standalone tests you can set FGLAPPSERVER environment variable
|
|
CALL show_verb("Listening on port : "|| NVL(fgl_getenv("FGLAPPSERVER"),"GAS"))
|
|
|
|
CALL com.WebServiceEngine.Start()
|
|
|
|
LET start_time = CURRENT
|
|
|
|
LET tout=-1
|
|
IF tout=-1 THEN
|
|
LET msg="The Api server is listening (timeout = infinite wait)."
|
|
ELSE
|
|
LET msg="The Api server is listening (timeout =",tout USING "-<<<<<<&"," seconds)."
|
|
END IF
|
|
CALL show_verb(msg)
|
|
|
|
LET n=0
|
|
|
|
WHILE TRUE
|
|
|
|
|
|
LET req = com.WebServiceEngine.getHTTPServiceRequest(tout)
|
|
|
|
LET url = req.getUrl()
|
|
DISPLAY "url 1: ",url
|
|
IF req IS NULL THEN -- timeout
|
|
CALL show_verb( SFMT("HTTP request timeout...: %1", CURRENT YEAR TO FRACTION))
|
|
CONTINUE WHILE
|
|
ELSE
|
|
LET urlhost = req.getUrlHost()
|
|
DISPLAY "url host ",urlhost
|
|
CALL show_verb( SFMT("HTTP request SERVICIO...: %1", CURRENT YEAR TO FRACTION))
|
|
|
|
END IF
|
|
|
|
LET url = req.getURL()
|
|
LET method = req.getMethod()
|
|
DISPLAY "metodo: ",method
|
|
IF method IS NULL OR method != "POST" THEN
|
|
IF method = "GET" THEN
|
|
|
|
|
|
LET mensaje = "Bienvenido al API Server del servicio ",url clipped
|
|
CALL req.sendTextResponse(200,NULL,mensaje)
|
|
END IF
|
|
|
|
EXIT WHILE
|
|
END IF
|
|
|
|
|
|
CALL read_request(req) RETURNING rcode,resp
|
|
|
|
IF rcode <> "200" THEN
|
|
|
|
CALL req.sendTextResponse(501,NULL,"No pudimos procesar el file")
|
|
|
|
ELSE
|
|
LET doc = xml.DomDocument.Create()
|
|
CALL doc.setFeature("format-pretty-print",TRUE)
|
|
CALL doc.load(fileafirmar_f)
|
|
CALL req.sendXmlResponse(200,NULL,doc)
|
|
# CALL req.sendTextResponse(200,NULL,resp)
|
|
END IF
|
|
|
|
|
|
LET d0 = CURRENT
|
|
EXIT WHILE
|
|
|
|
|
|
END WHILE
|
|
#CALL limpiatmp()
|
|
END FUNCTION
|
|
|
|
|
|
FUNCTION check_utf8()
|
|
IF ORD("€") == 8364 AND LENGTH("€") == 1 THEN
|
|
RETURN 0, NULL
|
|
ELSE
|
|
RETURN -1, "Application locale must be UTF-8, with char length semantics"
|
|
END IF
|
|
END FUNCTION
|
|
|
|
FUNCTION show_verb(msg)
|
|
DEFINE msg STRING
|
|
IF dpy_verb THEN
|
|
DISPLAY msg
|
|
END IF
|
|
# IF log_verb THEN
|
|
# CALL errorlog(msg CLIPPED)
|
|
# END IF
|
|
END FUNCTION
|
|
|
|
FUNCTION getxmldata()
|
|
DEFINE i, l INTEGER
|
|
DEFINE r om.XmlReader
|
|
DEFINE e,tok STRING,
|
|
pfechafirmadigital VARCHAR(50),
|
|
facturainterna INT
|
|
DEFINE a om.SaxAttributes
|
|
DISPLAY "filexml: ",filexml
|
|
LET r = om.XmlReader.createFileReader(filexml)
|
|
LET l = 0
|
|
LET e = r.read()
|
|
|
|
WHILE e IS NOT NULL
|
|
CASE e
|
|
WHEN "StartDocument"
|
|
# DISPLAY "StartDocument:"
|
|
WHEN "StartElement"
|
|
LET l=l+1
|
|
#DISPLAY l SPACES, "StartElement:", r.getTagName()
|
|
LET a = r.getAttributes()
|
|
FOR i=1 to a.getLength()
|
|
IF a.getName(i) = "SignatureValue" THEN
|
|
# DISPLAY l SPACES," ",
|
|
# a.getName(i)," = ",
|
|
# a.getValueByIndex(i)
|
|
END IF
|
|
END FOR
|
|
WHEN "Characters"
|
|
|
|
|
|
IF r.getTagName() = "TipoeCF" THEN
|
|
LET tipoecf = r.getCharacters()
|
|
EXIT CASE
|
|
END IF
|
|
IF r.getTagName() = "FechaHoraFirma" THEN
|
|
LET pfechafirmadigital = r.getCharacters()
|
|
EXIT CASE
|
|
END IF
|
|
IF r.getTagName() = "RNCEmisor" THEN
|
|
LET rnc_e = r.getCharacters()
|
|
EXIT CASE
|
|
END IF
|
|
IF r.getTagName() = "eNCF" THEN
|
|
LET e_ncf = r.getCharacters()
|
|
EXIT CASE
|
|
END IF
|
|
IF r.getTagName() = "RNCComprador" THEN
|
|
LET rnc_c = r.getCharacters()
|
|
EXIT CASE
|
|
END IF
|
|
|
|
WHEN "SkippedEntity"
|
|
# DISPLAY "Entity:'",r.skippedEntity(),"'"
|
|
WHEN "EndElement"
|
|
# DISPLAY l SPACES, "EndElement:", r.getTagName()
|
|
LET l=l-1
|
|
WHEN "EndDocument"
|
|
# DISPLAY "EndDocument:"
|
|
OTHERWISE
|
|
# DISPLAY "Invalid event: ",e
|
|
END CASE
|
|
LET e=r.read()
|
|
END WHILE
|
|
# RETURN phash,pfechafirmadigital,facturainterna
|
|
END FUNCTION
|
|
FUNCTION read_request(req)
|
|
# DEFINE doc xml.DomDocument
|
|
DEFINE req com.HttpServiceRequest
|
|
DEFINE cmd,recibido,tmpfile STRING,
|
|
p RECORD
|
|
oper STRING,
|
|
data RECORD
|
|
usuario STRING,
|
|
clave STRING,
|
|
codigo STRING
|
|
END RECORD
|
|
END RECORD
|
|
|
|
INITIALIZE cmd TO NULL
|
|
LET cmd = req.readFileRequest()
|
|
DISPLAY "request: ",cmd
|
|
# LET cmd = "cp ",cmd CLIPPED," /home/fourjs/gas/appdata/services/mbs/bin/tmp/recibido.xml"
|
|
LET cmd = "copy ",cmd CLIPPED, " C:\\ProgramData\\FourJs\\gas\\3.20.06-201906131721\\services\\ecf\\tmp\\recibido.xml"
|
|
RUN cmd
|
|
# LET tmpfile = "/home/fourjs/gas/appdata/services/mbs/bin/tmp/recibido.xml"
|
|
LET tmpfile = ".\\tmp\\recibido.xml"
|
|
LET recibido = filexml CLIPPED,"recibido.xml"
|
|
LET filexml = recibido
|
|
# TRY
|
|
LET doc = xml.DomDocument.Create()
|
|
CALL doc.setFeature("whitespace-in-element-content",FALSE)
|
|
|
|
IF os.Path.exists(tmpfile) THEN
|
|
CALL doc.load(tmpfile)
|
|
|
|
CALL doc.save(recibido)
|
|
CALL getxmldata()
|
|
LET filexml = filexml CLIPPED,rnc_e CLIPPED,e_ncf CLIPPED,".xml"
|
|
CALL doc.save(filexml)
|
|
CALL formaracuse() RETURNING filexml
|
|
CALL firmadocumento(filexml)
|
|
CALL doc.load(fileafirmar_f)
|
|
LET cmd = doc.saveToString()
|
|
|
|
RETURN 200,cmd
|
|
|
|
ELSE
|
|
RETURN 401,"Falla en el proceso del file"
|
|
|
|
END IF
|
|
# CATCH
|
|
|
|
# CALL show_err(SFMT("Unexpected HTTP request read exception: %1", STATUS))
|
|
# RETURN FALSE
|
|
# END TRY
|
|
|
|
|
|
|
|
END FUNCTION
|
|
|
|
FUNCTION show_err(msg)
|
|
DEFINE msg STRING
|
|
DISPLAY "ERROR:",msg
|
|
# CALL errorlog(msg CLIPPED)
|
|
END FUNCTION
|
|
|
|
FUNCTION formaracuse()
|
|
DEFINE chFechaFirma STRING
|
|
LET fileacuse = fileacuse CLIPPED,"acuse",rnc_c CLIPPED,".xml"
|
|
LET out=om.XmlWriter.createFileWriter(fileacuse)
|
|
|
|
LET a=om.SaxAttributes.create()
|
|
CALL out.startDocument()
|
|
|
|
CALL a.addAttribute("xmlns:xs","http://www.w3.org/2001/XMLSchema")
|
|
|
|
CALL out.startElement("ARECF",a)
|
|
CALL a.clear()
|
|
|
|
CALL out.startElement("DetalleAcusedeRecibo",a)
|
|
|
|
CALL out.startElement("Version",a)
|
|
CALL out.characters("1.0")
|
|
CALL out.endElement("Version")
|
|
|
|
CALL out.startElement("RNCEmisor",a)
|
|
CALL out.characters(rnc_e)
|
|
CALL out.endElement("RNCEmisor")
|
|
|
|
CALL out.startElement("RNCComprador",a)
|
|
CALL out.characters(rnc_c)
|
|
CALL out.endElement("RNCComprador")
|
|
|
|
CALL out.startElement("eNCF",a)
|
|
CALL out.characters(e_ncf)
|
|
CALL out.endElement("eNCF")
|
|
|
|
CALL out.startElement("Estado",a)
|
|
CALL out.characters("0")
|
|
CALL out.endElement("Estado")
|
|
|
|
LET chFechaFirma = util.Datetime.format(CURRENT, "%d-%m-%Y %H:%M:%S" )
|
|
DISPLAY "FECHA ",chFechaFirma
|
|
CALL out.startElement("FechaHoraAcuseRecibo",a)
|
|
CALL out.characters(chFechaFirma)
|
|
CALL out.endElement("FechaHoraAcuseRecibo")
|
|
|
|
CALL out.endElement("DetalleAcusedeRecibo")
|
|
|
|
|
|
CALL out.endElement("ARECF")
|
|
CALL out.endDocument()
|
|
|
|
RETURN fileacuse
|
|
|
|
END FUNCTION
|
|
FUNCTION limpiatmp()
|
|
DISPLAY "BORRANDO XML FILES..."
|
|
RUN 'rm /tmp/*.xml'
|
|
END FUNCTION
|
|
|
|
FUNCTION firmadocumento(fileafirmar)
|
|
DEFINE doc xml.DomDocument
|
|
DEFINE doc2 xml.DomDocument
|
|
DEFINE root xml.DomNode
|
|
DEFINE node xml.DomNode
|
|
DEFINE signNode xml.DomNode
|
|
|
|
DEFINE sig xml.Signature
|
|
DEFINE key xml.CryptoKey
|
|
DEFINE cert xml.CryptoX509
|
|
DEFINE index INTEGER,
|
|
fileafirmar STRING,
|
|
codsecure VARCHAR(6)
|
|
|
|
# Create DomDocument object
|
|
LET doc = xml.DomDocument.Create()
|
|
# Notice that whitespaces are significant in cryptography,
|
|
# therefore it is recommended to remove unnecessary ones
|
|
CALL doc.setFeature("whitespace-in-element-content",FALSE)
|
|
|
|
|
|
#DISPLAY "file ",fileafirmar
|
|
LET filexml = fileafirmar
|
|
|
|
CALL doc.load(fileafirmar)
|
|
|
|
TRY
|
|
|
|
|
|
# Create rsa key
|
|
LET key = xml.CryptoKey.Create("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256")
|
|
CALL key.loadPEM("onlyRSA.pem")
|
|
|
|
|
|
# Create an X509 certificate with the constructor of the CryptoX509 class.
|
|
LET cert = xml.CryptoX509.Create()
|
|
CALL cert.setFeature("X509Certificate",TRUE)
|
|
|
|
# Load the X509 certificate associated to the RSA or DSA private key into the CryptoKey object.
|
|
# CALL cert.loadPEM("cert509.crt")
|
|
CALL cert.loadPEM("onlyCert.pem")
|
|
# Create signature object with the key to use
|
|
LET sig = xml.Signature.Create()
|
|
# Assign the CryptoKey object to the Signature object.
|
|
CALL sig.setKey(KEY)
|
|
|
|
# Assign the CryptoX509 object to the Signature object.
|
|
CALL sig.setCertificate(cert)
|
|
|
|
# Set XML node to be signed. In our case, the entire document
|
|
# LET index = sig.createReference("",
|
|
# "http://www.w3.org/2001/04/xmlenc#sha256")
|
|
LET index = sig.createReference('""',
|
|
"http://www.w3.org/2001/04/xmlenc#sha256")
|
|
|
|
# Add enveloped method to not take the XML signature node into account
|
|
# when computing the entire document.
|
|
CALL sig.appendReferenceTransformation(index,
|
|
"http://www.w3.org/2000/09/xmldsig#enveloped-signature",doc.getDocumentElement())
|
|
# Set canonicalization method on the XML fragment to be signed.
|
|
|
|
# Compute enveloped signature
|
|
CALL sig.compute(doc)
|
|
# Retrieve signature document
|
|
LET doc2=sig.getDocument()
|
|
# Append the signature node to the original document to get
|
|
# a valid enveloped signature
|
|
# Notice that the enveloped signature can be added anywhere in the
|
|
# original document
|
|
LET signNode = doc2.getDocumentElement() # Get Signature node
|
|
# Import it into the original document
|
|
LET node = doc.importNode(signNode,true)
|
|
# Retrieve the original document root node
|
|
LET root = doc.getDocumentElement()
|
|
|
|
# Append the signature node as last child of the original document
|
|
CALL root.appendChild(node)
|
|
# Save document with enveloped signature back to disk
|
|
CALL doc.setFeature("format-pretty-print",TRUE)
|
|
LET fileafirmar = ruta_firmados CLIPPED,"\\",os.Path.baseName(fileafirmar)
|
|
|
|
CALL doc.save(fileafirmar)
|
|
LET fileafirmar_f = fileafirmar
|
|
|
|
CATCH
|
|
DISPLAY "Unable to create an enveloped signature :",status," ",sqlca.sqlerrm
|
|
END TRY
|
|
|
|
END FUNCTION |