mirror of
				https://github.com/node-ebics/node-ebics-client.git
				synced 2025-10-31 03:27:05 +00:00 
			
		
		
		
	Merge pull request #87 from node-ebics/update-deps
Update dependencies, replace deprecated libs
This commit is contained in:
		
							
								
								
									
										10
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								.travis.yml
									
									
									
									
									
								
							| @@ -1,8 +1,8 @@ | ||||
| language: node_js | ||||
| node_js: | ||||
|   - "8" | ||||
|   - "9" | ||||
|   - "10" | ||||
|   - "11" | ||||
|   - "12" | ||||
|   - "16" # maintance lts | ||||
|   - "17" | ||||
|   - "18" # active lts | ||||
|   - "19" | ||||
|   - "20" # current | ||||
| after_success: npm run coverage | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| 'use strict'; | ||||
| "use strict"; | ||||
|  | ||||
| const H004Signer = require('../orders/H004/signer'); | ||||
| const H004Signer = require("../orders/H004/signer"); | ||||
|  | ||||
| module.exports = { | ||||
| 	version(v) { | ||||
| 		if (v.toUpperCase() === 'H004') return H004Signer; | ||||
| 		if (v.toUpperCase() === "H004") return H004Signer; | ||||
|  | ||||
| 		throw Error('Error from middleware/signer.js: Invalid version number'); | ||||
| 		throw Error("Error from middleware/signer.js: Invalid version number"); | ||||
| 	}, | ||||
| }; | ||||
|   | ||||
| @@ -1,13 +1,13 @@ | ||||
| 'use strict'; | ||||
| "use strict"; | ||||
|  | ||||
| const zlib = require('zlib'); | ||||
| const crypto = require('crypto'); | ||||
| const zlib = require("zlib"); | ||||
| const crypto = require("crypto"); | ||||
|  | ||||
| const Crypto = require('../../crypto/Crypto'); | ||||
| const Crypto = require("../../crypto/Crypto"); | ||||
|  | ||||
| const { DOMParser, XMLSerializer } = require('xmldom'); | ||||
| const xpath = require('xpath'); | ||||
| const errors = require('./errors'); | ||||
| const { DOMParser, XMLSerializer } = require("@xmldom/xmldom"); | ||||
| const xpath = require("xpath"); | ||||
| const errors = require("./errors"); | ||||
|  | ||||
| const DEFAULT_IV = Buffer.from(Array(16).fill(0, 0, 15)); | ||||
|  | ||||
| @@ -21,58 +21,85 @@ const lastChild = (node) => { | ||||
|  | ||||
| module.exports = (xml, keys) => ({ | ||||
| 	keys, | ||||
| 	doc: new DOMParser().parseFromString(xml, 'text/xml'), | ||||
| 	doc: new DOMParser().parseFromString(xml, "text/xml"), | ||||
|  | ||||
| 	isSegmented() { | ||||
| 		const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' }); | ||||
| 		const node = select('//xmlns:header/xmlns:mutable/xmlns:SegmentNumber', this.doc); | ||||
| 		const select = xpath.useNamespaces({ xmlns: "urn:org:ebics:H004" }); | ||||
| 		const node = select( | ||||
| 			"//xmlns:header/xmlns:mutable/xmlns:SegmentNumber", | ||||
| 			this.doc | ||||
| 		); | ||||
|  | ||||
| 		return !!node.length; | ||||
| 	}, | ||||
|  | ||||
| 	isLastSegment() { | ||||
| 		const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' }); | ||||
| 		const node = select("//xmlns:header/xmlns:mutable/*[@lastSegment='true']", this.doc); | ||||
| 		const select = xpath.useNamespaces({ xmlns: "urn:org:ebics:H004" }); | ||||
| 		const node = select( | ||||
| 			"//xmlns:header/xmlns:mutable/*[@lastSegment='true']", | ||||
| 			this.doc | ||||
| 		); | ||||
|  | ||||
| 		return !!node.length; | ||||
| 	}, | ||||
|  | ||||
| 	orderData() { | ||||
| 		const orderDataNode = this.doc.getElementsByTagNameNS('urn:org:ebics:H004', 'OrderData'); | ||||
| 		const orderDataNode = this.doc.getElementsByTagNameNS( | ||||
| 			"urn:org:ebics:H004", | ||||
| 			"OrderData" | ||||
| 		); | ||||
|  | ||||
| 		if (!orderDataNode.length) return {}; | ||||
|  | ||||
| 		const orderData = orderDataNode[0].textContent; | ||||
| 		const decipher = crypto.createDecipheriv('aes-128-cbc', this.transactionKey(), DEFAULT_IV).setAutoPadding(false); | ||||
| 		const data = Buffer.from(decipher.update(orderData, 'base64', 'binary') + decipher.final('binary'), 'binary'); | ||||
| 		const decipher = crypto | ||||
| 			.createDecipheriv("aes-128-cbc", this.transactionKey(), DEFAULT_IV) | ||||
| 			.setAutoPadding(false); | ||||
| 		const data = Buffer.from( | ||||
| 			decipher.update(orderData, "base64", "binary") + | ||||
| 				decipher.final("binary"), | ||||
| 			"binary" | ||||
| 		); | ||||
|  | ||||
| 		return zlib.inflateSync(data); | ||||
| 	}, | ||||
|  | ||||
| 	transactionKey() { | ||||
| 		const keyNodeText = this.doc.getElementsByTagNameNS('urn:org:ebics:H004', 'TransactionKey')[0].textContent; | ||||
| 		return Crypto.privateDecrypt(this.keys.e(), Buffer.from(keyNodeText, 'base64')); | ||||
| 		const keyNodeText = this.doc.getElementsByTagNameNS( | ||||
| 			"urn:org:ebics:H004", | ||||
| 			"TransactionKey" | ||||
| 		)[0].textContent; | ||||
| 		return Crypto.privateDecrypt( | ||||
| 			this.keys.e(), | ||||
| 			Buffer.from(keyNodeText, "base64") | ||||
| 		); | ||||
| 	}, | ||||
|  | ||||
| 	transactionId() { | ||||
| 		const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' }); | ||||
| 		const node = select('//xmlns:header/xmlns:static/xmlns:TransactionID', this.doc); | ||||
| 		const select = xpath.useNamespaces({ xmlns: "urn:org:ebics:H004" }); | ||||
| 		const node = select( | ||||
| 			"//xmlns:header/xmlns:static/xmlns:TransactionID", | ||||
| 			this.doc | ||||
| 		); | ||||
|  | ||||
| 		return node.length ? node[0].textContent : ''; | ||||
| 		return node.length ? node[0].textContent : ""; | ||||
| 	}, | ||||
|  | ||||
| 	orderId() { | ||||
| 		const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' }); | ||||
| 		const node = select('.//xmlns:header/xmlns:mutable/xmlns:OrderID', this.doc); | ||||
| 		const select = xpath.useNamespaces({ xmlns: "urn:org:ebics:H004" }); | ||||
| 		const node = select( | ||||
| 			".//xmlns:header/xmlns:mutable/xmlns:OrderID", | ||||
| 			this.doc | ||||
| 		); | ||||
|  | ||||
| 		return node.length ? node[0].textContent : ''; | ||||
| 		return node.length ? node[0].textContent : ""; | ||||
| 	}, | ||||
|  | ||||
| 	businessCode() { | ||||
| 		const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' }); | ||||
| 		const node = select('//xmlns:body/xmlns:ReturnCode', this.doc); | ||||
| 		const select = xpath.useNamespaces({ xmlns: "urn:org:ebics:H004" }); | ||||
| 		const node = select("//xmlns:body/xmlns:ReturnCode", this.doc); | ||||
|  | ||||
| 		return node.length ? node[0].textContent : ''; | ||||
| 		return node.length ? node[0].textContent : ""; | ||||
| 	}, | ||||
|  | ||||
| 	businessSymbol(code) { | ||||
| @@ -88,17 +115,23 @@ module.exports = (xml, keys) => ({ | ||||
| 	}, | ||||
|  | ||||
| 	technicalCode() { | ||||
| 		const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' }); | ||||
| 		const node = select('//xmlns:header/xmlns:mutable/xmlns:ReturnCode', this.doc); | ||||
| 		const select = xpath.useNamespaces({ xmlns: "urn:org:ebics:H004" }); | ||||
| 		const node = select( | ||||
| 			"//xmlns:header/xmlns:mutable/xmlns:ReturnCode", | ||||
| 			this.doc | ||||
| 		); | ||||
|  | ||||
| 		return node.length ? node[0].textContent : ''; | ||||
| 		return node.length ? node[0].textContent : ""; | ||||
| 	}, | ||||
|  | ||||
| 	technicalSymbol() { | ||||
| 		const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' }); | ||||
| 		const node = select('//xmlns:header/xmlns:mutable/xmlns:ReportText', this.doc); | ||||
| 		const select = xpath.useNamespaces({ xmlns: "urn:org:ebics:H004" }); | ||||
| 		const node = select( | ||||
| 			"//xmlns:header/xmlns:mutable/xmlns:ReportText", | ||||
| 			this.doc | ||||
| 		); | ||||
|  | ||||
| 		return node.length ? node[0].textContent : ''; | ||||
| 		return node.length ? node[0].textContent : ""; | ||||
| 	}, | ||||
|  | ||||
| 	technicalShortText(code) { | ||||
| @@ -113,20 +146,26 @@ module.exports = (xml, keys) => ({ | ||||
| 		const orderData = this.orderData().toString(); | ||||
| 		if (!Object.keys(orderData).length) return {}; | ||||
|  | ||||
| 		const doc = new DOMParser().parseFromString(orderData, 'text/xml'); | ||||
| 		const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' }); | ||||
| 		const keyNodes = select('//xmlns:PubKeyValue', doc); | ||||
| 		const doc = new DOMParser().parseFromString(orderData, "text/xml"); | ||||
| 		const select = xpath.useNamespaces({ xmlns: "urn:org:ebics:H004" }); | ||||
| 		const keyNodes = select("//xmlns:PubKeyValue", doc); | ||||
| 		const bankKeys = {}; | ||||
|  | ||||
| 		if (!keyNodes.length) return {}; | ||||
|  | ||||
| 		for (let i = 0; i < keyNodes.length; i++) { | ||||
| 			const type = lastChild(keyNodes[i].parentNode).textContent; | ||||
| 			const modulus = xpath.select(".//*[local-name(.)='Modulus']", keyNodes[i])[0].textContent; | ||||
| 			const exponent = xpath.select(".//*[local-name(.)='Exponent']", keyNodes[i])[0].textContent; | ||||
| 			const modulus = xpath.select( | ||||
| 				".//*[local-name(.)='Modulus']", | ||||
| 				keyNodes[i] | ||||
| 			)[0].textContent; | ||||
| 			const exponent = xpath.select( | ||||
| 				".//*[local-name(.)='Exponent']", | ||||
| 				keyNodes[i] | ||||
| 			)[0].textContent; | ||||
|  | ||||
| 			const mod = Buffer.from(modulus, 'base64'); | ||||
| 			const exp = Buffer.from(exponent, 'base64'); | ||||
| 			const mod = Buffer.from(modulus, "base64"); | ||||
| 			const exp = Buffer.from(exponent, "base64"); | ||||
| 			bankKeys[`bank${type}`] = { | ||||
| 				mod, | ||||
| 				exp, | ||||
|   | ||||
| @@ -1,36 +1,50 @@ | ||||
|  | ||||
| 'use strict'; | ||||
| "use strict"; | ||||
|  | ||||
| // const crypto = require('crypto'); | ||||
| const Crypto = require('../../crypto/Crypto'); | ||||
| const Crypto = require("../../crypto/Crypto"); | ||||
|  | ||||
| const { DOMParser, XMLSerializer } = require('xmldom'); | ||||
| const xpath = require('xpath'); | ||||
| const C14n = require('xml-crypto/lib/c14n-canonicalization').C14nCanonicalization; | ||||
| const { DOMParser, XMLSerializer } = require("@xmldom/xmldom"); | ||||
| const xpath = require("xpath"); | ||||
| const C14n = | ||||
| 	require("xml-crypto/lib/c14n-canonicalization").C14nCanonicalization; | ||||
|  | ||||
| const digest = (doc) => { | ||||
| 	// get the xml node, where the digested value is supposed to be | ||||
| 	const nodeDigestValue = doc.getElementsByTagName('ds:DigestValue')[0]; | ||||
| 	const nodeDigestValue = doc.getElementsByTagName("ds:DigestValue")[0]; | ||||
|  | ||||
| 	// canonicalize the node that has authenticate='true' attribute | ||||
| 	const contentToDigest = xpath.select("//*[@authenticate='true']", doc) | ||||
| 		.map(x => new C14n().process(x)).join(''); | ||||
| 	const contentToDigest = xpath | ||||
| 		.select("//*[@authenticate='true']", doc) | ||||
| 		.map((x) => new C14n().process(x)) | ||||
| 		.join(""); | ||||
|  | ||||
| 	// fix the canonicalization | ||||
| 	const fixedContent = contentToDigest.replace(/xmlns="urn:org:ebics:H004"/g, 'xmlns="urn:org:ebics:H004" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"'); | ||||
| 	const fixedContent = contentToDigest.replace( | ||||
| 		/xmlns="urn:org:ebics:H004"/g, | ||||
| 		'xmlns="urn:org:ebics:H004" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"' | ||||
| 	); | ||||
|  | ||||
| 	if (nodeDigestValue) | ||||
| 		nodeDigestValue.textContent = Crypto.digestWithHash(fixedContent).toString('base64').trim(); | ||||
| 		nodeDigestValue.textContent = Crypto.digestWithHash(fixedContent) | ||||
| 			.toString("base64") | ||||
| 			.trim(); | ||||
|  | ||||
| 	return doc; | ||||
| }; | ||||
|  | ||||
| const sign = (doc, key) => { | ||||
| 	const nodeSignatureValue = doc.getElementsByTagName('ds:SignatureValue')[0]; | ||||
| 	const nodeSignatureValue = doc.getElementsByTagName("ds:SignatureValue")[0]; | ||||
|  | ||||
| 	if (nodeSignatureValue) { | ||||
| 		const select = xpath.useNamespaces({ ds: 'http://www.w3.org/2000/09/xmldsig#' }); | ||||
| 		const contentToSign = (new C14n().process(select('//ds:SignedInfo', doc)[0])).replace('xmlns:ds="http://www.w3.org/2000/09/xmldsig#"', 'xmlns="urn:org:ebics:H004" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"'); | ||||
| 		const select = xpath.useNamespaces({ | ||||
| 			ds: "http://www.w3.org/2000/09/xmldsig#", | ||||
| 		}); | ||||
| 		const contentToSign = new C14n() | ||||
| 			.process(select("//ds:SignedInfo", doc)[0]) | ||||
| 			.replace( | ||||
| 				'xmlns:ds="http://www.w3.org/2000/09/xmldsig#"', | ||||
| 				'xmlns="urn:org:ebics:H004" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"' | ||||
| 			); | ||||
|  | ||||
| 		nodeSignatureValue.textContent = Crypto.privateSign(key, contentToSign); // this.keys.x().key.sign(contentToSign, 'base64'); | ||||
| 	} | ||||
| @@ -38,11 +52,11 @@ const sign = (doc, key) => { | ||||
| 	return doc; | ||||
| }; | ||||
|  | ||||
| const toXML = doc => new XMLSerializer().serializeToString(doc); | ||||
| const toXML = (doc) => new XMLSerializer().serializeToString(doc); | ||||
|  | ||||
| module.exports = { | ||||
| 	sign(data, keyX) { | ||||
| 		const doc = new DOMParser().parseFromString(data, 'text/xml'); | ||||
| 		const doc = new DOMParser().parseFromString(data, "text/xml"); | ||||
|  | ||||
| 		return toXML(sign(digest(doc), keyX)); | ||||
| 	}, | ||||
|   | ||||
							
								
								
									
										8811
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										8811
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										24
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								package.json
									
									
									
									
									
								
							| @@ -59,24 +59,24 @@ | ||||
| 	], | ||||
| 	"license": "GPL-3.0-only", | ||||
| 	"dependencies": { | ||||
| 		"handlebars": "^4.7.7", | ||||
| 		"js2xmlparser": "^4.0.1", | ||||
| 		"node-forge": "^0.10.0", | ||||
| 		"handlebars": "^4.7.8", | ||||
| 		"js2xmlparser": "^5.0.0", | ||||
| 		"node-forge": "^1.3.1", | ||||
| 		"request": "^2.88.2", | ||||
| 		"uuid": "^8.3.2", | ||||
| 		"xml-crypto": "^2.1.1", | ||||
| 		"xmldom": "^0.5.0", | ||||
| 		"uuid": "^9.0.1", | ||||
| 		"xml-crypto": "^4.0.1", | ||||
| 		"@xmldom/xmldom": "^0.8.10", | ||||
| 		"xpath": "0.0.32" | ||||
| 	}, | ||||
| 	"devDependencies": { | ||||
| 		"auto-changelog": "^1.16.2", | ||||
| 		"chai": "^4.3.4", | ||||
| 		"coveralls": "^3.1.0", | ||||
| 		"auto-changelog": "^2.4.0", | ||||
| 		"chai": "^4.3.10", | ||||
| 		"coveralls": "^3.1.1", | ||||
| 		"eslint": "^6.7.2", | ||||
| 		"eslint-config-ecollect-base": "^0.1.2", | ||||
| 		"eslint-plugin-import": "^2.18.2", | ||||
| 		"libxmljs": "^0.19.10", | ||||
| 		"mocha": "^7.1.2", | ||||
| 		"eslint-plugin-import": "^2.28.1", | ||||
| 		"libxmljs": "^1.0.10", | ||||
| 		"mocha": "^10.2.0", | ||||
| 		"nyc": "^15.1.0" | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,18 +1,20 @@ | ||||
| 'use strict'; | ||||
| "use strict"; | ||||
|  | ||||
| /* eslint-env node, mocha */ | ||||
|  | ||||
| const { assert } = require('chai'); | ||||
| const { assert } = require("chai"); | ||||
|  | ||||
| const path = require('path'); | ||||
| const fs = require('fs'); | ||||
| const path = require("path"); | ||||
| const fs = require("fs"); | ||||
|  | ||||
| const ebics = require('../../'); | ||||
| const ebics = require("../../"); | ||||
|  | ||||
| const libxml = require('libxmljs'); | ||||
| const libxml = require("libxmljs"); | ||||
|  | ||||
| const schemaPath = path.resolve(__dirname, '../xsd/ebics_H004.xsd'); | ||||
| const schemaDoc = libxml.parseXml(fs.readFileSync(schemaPath, { encoding: 'utf8' })); | ||||
| const schemaPath = path.resolve(__dirname, "../xsd/ebics_H004.xsd"); | ||||
| const schemaDoc = libxml.parseXml( | ||||
| 	fs.readFileSync(schemaPath, { encoding: "utf8" }) | ||||
| ); | ||||
|  | ||||
| const schemaDir = path.dirname(schemaPath); | ||||
| const cwd = process.cwd(); | ||||
| @@ -20,7 +22,7 @@ const cwd = process.cwd(); | ||||
| const validateXML = (str) => { | ||||
| 	try { | ||||
| 		process.chdir(schemaDir); | ||||
| 		const isValid = libxml.parseXmlString(str).validate(schemaDoc); | ||||
| 		const isValid = libxml.parseXml(str).validate(schemaDoc); | ||||
| 		process.chdir(cwd); | ||||
| 		return isValid; | ||||
| 	} catch (e) { | ||||
| @@ -30,12 +32,14 @@ const validateXML = (str) => { | ||||
| }; | ||||
|  | ||||
| const client = new ebics.Client({ | ||||
| 	url: 'https://iso20022test.credit-suisse.com/ebicsweb/ebicsweb', | ||||
| 	partnerId: 'CRS04381', | ||||
| 	userId: 'CRS04381', | ||||
| 	hostId: 'CRSISOTB', | ||||
| 	passphrase: 'test', | ||||
| 	keyStorage: ebics.fsKeysStorage(path.resolve(__dirname, '../support/TEST_KEYS.key')), | ||||
| 	url: "https://iso20022test.credit-suisse.com/ebicsweb/ebicsweb", | ||||
| 	partnerId: "CRS04381", | ||||
| 	userId: "CRS04381", | ||||
| 	hostId: "CRSISOTB", | ||||
| 	passphrase: "test", | ||||
| 	keyStorage: ebics.fsKeysStorage( | ||||
| 		path.resolve(__dirname, "../support/TEST_KEYS.key") | ||||
| 	), | ||||
| }); | ||||
|  | ||||
| const { Orders } = ebics; | ||||
| @@ -52,8 +56,8 @@ const CCS = require('./CCS'); | ||||
| const XE3 = require('./XE3'); | ||||
| const XCT = require('./XCT'); | ||||
| */ | ||||
| const uploadBuilder = fn => fn(''); | ||||
| const dateBuilder = fn => fn('2018-01-01', '2019-01-01'); | ||||
| const uploadBuilder = (fn) => fn(""); | ||||
| const dateBuilder = (fn) => fn("2018-01-01", "2019-01-01"); | ||||
|  | ||||
| const fnOrders = { | ||||
| 	// upload | document | ||||
| @@ -83,19 +87,16 @@ const fnOrders = { | ||||
| }; | ||||
|  | ||||
| const getOrderObject = (name, order) => { | ||||
| 	if (typeof order === 'object') | ||||
| 		return order; | ||||
| 	if (fnOrders[name]) | ||||
| 		return fnOrders[name](order); | ||||
| 	if (typeof order === "object") return order; | ||||
| 	if (fnOrders[name]) return fnOrders[name](order); | ||||
| 	return null; | ||||
| }; | ||||
|  | ||||
| describe('H004 order generation', () => { | ||||
| describe("H004 order generation", () => { | ||||
| 	// eslint-disable-next-line no-restricted-syntax | ||||
| 	for (const [name, orderDefinition] of Object.entries(Orders)) { | ||||
| 		const order = getOrderObject(name, orderDefinition); | ||||
| 		if (!order) | ||||
| 			continue; | ||||
| 		if (!order) continue; | ||||
|  | ||||
| 		const type = order.orderDetails.OrderType; | ||||
| 		const { operation } = order; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user