UNPKG

xml-fiesta

Version:

Electronic signed document XML Protocol for Node & Browser

236 lines 9.35 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var Promise = require("promise"); var xmlCrypto = require("xml-crypto"); var select = require("xpath.js"); var Dom = require("xmldom").DOMParser; var xml2js_1 = require("xml2js"); var common_1 = require("./common"); var certificate_1 = require("./certificate"); var xmlPatch_1 = require("./patches/xmlPatch"); var ExclusiveCanonicalization = xmlCrypto.SignedXml.CanonicalizationAlgorithms["http://www.w3.org/2001/10/xml-exc-c14n#"]; var versionToNumber = function (version) { var _a = version .split(/\./) .map(function (v) { return parseInt(v); }), firstNumber = _a[0], secondNumber = _a[1], thirdNumber = _a[2]; return firstNumber * 100 + secondNumber * 10 + thirdNumber; }; var START_VERSION_WITHOUT_SINGERS_CER = versionToNumber("2.5.0"); var XML = (function () { function XML() { this.tracked = false; this.destroyed = false; this.nameSpaces = null; } XML.parse = function (string) { var xml = new xmlPatch_1.default(); return xml.parse(string); }; XML.parseByElectronicDocument = function (electronicDocument) { var xml = new xmlPatch_1.default(); return xml.parseByElectronicDocument(electronicDocument); }; XML.toXML = function (eDocument, file) { var edoc = JSON.parse(JSON.stringify(eDocument)); this.removeEncrypedData(edoc); edoc.file[0]._ = file; var builder = new xml2js_1.Builder({ rootName: "electronicDocument", renderOpts: { pretty: false, }, }); return builder.buildObject(edoc); }; XML.removeEncrypedData = function (xmljs) { var _a, _b, _c; if (xmljs.file && xmljs.file[0]) { delete xmljs.file[0].$.encrypted; xmljs.file[0].$.name = xmljs.file[0].$.name.replace(".enc", ""); } (_c = (_b = (_a = xmljs.signers) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.signer) === null || _c === void 0 ? void 0 : _c.forEach(function (signer) { delete signer.ePass; }); }; XML.removeGeolocation = function (xmljs) { var _a, _b, _c; (_c = (_b = (_a = xmljs.signers) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.signer) === null || _c === void 0 ? void 0 : _c.forEach(function (signer) { if (signer.auditTrail) { signer.auditTrail[0].event.forEach(function (event, index) { if (event.$.name === "geolocation") { delete signer.auditTrail[0].event[index]; } }); } }); }; XML.removeBlockchain = function (xmljs) { delete xmljs.blockchain; }; XML.removeTransfer = function (xmljs) { delete xmljs.transfers; }; XML.detectNamespacePrefix = function (xmlString) { var prefixMatch = xmlString.match(/<\s*([A-Za-z_][\w.-]*):electronicDocument\b/); return prefixMatch ? prefixMatch[1] : null; }; XML.createAttrNameStripper = function (xmlString) { var detectedPrefix = XML.detectNamespacePrefix(xmlString); return function (name) { if (detectedPrefix && name) { return name .replace(new RegExp(detectedPrefix + ":", "g"), "") .replace(new RegExp(":" + detectedPrefix, "g"), ""); } return name; }; }; XML.removeSignersCertificate = function (xmljs) { var _a, _b, _c; (_c = (_b = (_a = xmljs.signers) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.signer) === null || _c === void 0 ? void 0 : _c.forEach(function (signer) { delete signer.$.name; delete signer.certificate[0]._; }); }; XML.prototype.parseByElectronicDocument = function (electronicDocument) { var el = this; if (electronicDocument.blockchain) { el.tracked = true; } el.eDocument = electronicDocument; var eDocumentAttrs = el.eDocument.$; el.version = eDocumentAttrs.version; el.signed = eDocumentAttrs.signed; el.version_int = versionToNumber(el.version); el.destroyed = eDocumentAttrs.cancel || false; if (el.version_int < 100) { el.fileElementName = "pdf"; } else { el.fileElementName = "file"; } var pdfAttrs = el.eDocument[el.fileElementName][0].$; el.encrypted = pdfAttrs.encrypted; el.name = pdfAttrs.name; el.contentType = pdfAttrs.contentType; el.originalHash = pdfAttrs.originalHash; return el; }; XML.prototype.parse = function (xml) { var el = this; return new Promise(function (resolve, reject) { return xml2js_1.parseString(xml, { tagNameProcessors: [xml2js_1.processors.stripPrefix], attrNameProcessors: [XML.createAttrNameStripper(xml)], }, function (err, _a) { var electronicDocument = _a.electronicDocument; if (err) { return reject(err); } el.parseByElectronicDocument(electronicDocument); return resolve(el); }); }); }; XML.prototype.canonical = function (electronicDocumentAttributes) { if (electronicDocumentAttributes === void 0) { electronicDocumentAttributes = {}; } var edoc = JSON.parse(JSON.stringify(this.eDocument)); if (electronicDocumentAttributes && Object.keys(electronicDocumentAttributes).length) { Object.entries(electronicDocumentAttributes).map(function (_a) { var key = _a[0], value = _a[1]; if (key.includes("xmlns")) { edoc.$[key] = value; } }); } delete edoc.$.cancel; delete edoc.conservancyRecord; var xml = this.constructor; xml.removeEncrypedData(edoc); xml.removeGeolocation(edoc); xml.removeBlockchain(edoc); xml.removeTransfer(edoc); if (this.version_int >= START_VERSION_WITHOUT_SINGERS_CER) { xml.removeSignersCertificate(edoc); } if (this.version_int >= 100) { edoc[this.fileElementName][0]._ = ""; } var builder = new xml2js_1.Builder({ rootName: "electronicDocument", renderOpts: { pretty: false, }, }); var originalXml = builder.buildObject(edoc); var doc = new Dom().parseFromString(originalXml); var elem = select(doc, "//*")[0]; var can = new ExclusiveCanonicalization(); var canonicalString = can.process(elem).toString(); return canonicalString.replace(/&#xD;/g, ""); }; XML.prototype.getCanonicalBuffer = function (electronicDocumentAttributes) { return Buffer.from(this.canonical(electronicDocumentAttributes), "utf-8"); }; XML.prototype.file = function () { return this.eDocument[this.fileElementName][0]._; }; XML.prototype.pdf = function () { return this.file(); }; XML.prototype.xmlSigners = function () { var parsedSigners = []; var signers = this.eDocument.signers; if (!signers) return; signers[0].signer.forEach(function (signer) { var attrs = signer.$; var cerHex = common_1.b64toHex(signer.certificate[0]._); var certificate = new certificate_1.default(null, cerHex); var xmlSigner = { name: attrs.name, taxId: attrs.id, email: attrs.email, cer: cerHex, signature: common_1.b64toHex(signer.signature[0]._), signedAt: signer.signature[0].$.signedAt, legalEntity: certificate.getUniqueIdentifier().length > 1, }; if (signer.ePass) { xmlSigner.ePass = { content: common_1.b64toHex(signer.ePass[0]._), algorithm: signer.ePass[0].$.algorithm, iterations: signer.ePass[0].$.iterations, keySize: signer.ePass[0].$.keySize, }; } return parsedSigners.push(xmlSigner); }); return parsedSigners; }; XML.prototype.getConservancyRecord = function () { var crVersion, userCertificate; if (!this.eDocument.conservancyRecord) { return null; } var cr = this.eDocument.conservancyRecord[0]; if (!cr.$.version) { userCertificate = cr.userCertificate[0]._; } else { crVersion = cr.$.version; } return { caCert: cr.caCertificate[0]._, userCert: userCertificate, record: cr.record[0], timestamp: cr.$.timestamp, originalXmlHash: common_1.sha256(this.canonical()), version: crVersion, }; }; return XML; }()); exports.default = XML; //# sourceMappingURL=xml.js.map