mirror of
				https://github.com/node-ebics/node-ebics-client.git
				synced 2025-10-31 11:37:05 +00:00 
			
		
		
		
	client and order optimization
This commit is contained in:
		
							
								
								
									
										8
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								index.js
									
									
									
									
									
								
							| @@ -1,15 +1,9 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const Client = require('./lib/Client'); | ||||
| const OrderBuilder = require('./lib/OrderBuilder'); | ||||
| const ISO20022Builder = require('./lib/ISO20022OrderBuilder'); | ||||
| const keysManager = require('./lib/keymanagers/keysManager'); | ||||
| const fsKeysStorage = require('./lib/keymanagers/fsKeysStorage'); | ||||
| const fsKeysStorage = require('./lib/storages/fsKeysStorage'); | ||||
|  | ||||
| module.exports = { | ||||
| 	Client, | ||||
| 	OrderBuilder, | ||||
| 	ISO20022Builder, | ||||
| 	keysManager, | ||||
| 	fsKeysStorage, | ||||
| }; | ||||
|   | ||||
| @@ -2,13 +2,55 @@ | ||||
|  | ||||
| const $request = require('request'); | ||||
|  | ||||
| const constants = require('./consts'); | ||||
| const Keys = require('./keymanagers/Keys'); | ||||
| const defaultKeyEncryptor = require('./keymanagers/defaultKeyEncryptor'); | ||||
|  | ||||
| const signer = require('./middleware/signer'); | ||||
| const serializer = require('./middleware/serializer'); | ||||
| const response = require('./middleware/response'); | ||||
|  | ||||
| module.exports = class Client { | ||||
| 	constructor(url) { | ||||
| 	constructor({ | ||||
| 		url, | ||||
| 		partnerId, | ||||
| 		userId, | ||||
| 		hostId, | ||||
| 		passphrase, | ||||
| 		keyStorage, | ||||
| 	}) { | ||||
| 		if (!url) | ||||
| 			throw new Error('EBICS URL is requierd'); | ||||
| 		if (!partnerId) | ||||
| 			throw new Error('partnerId is requierd'); | ||||
| 		if (!userId) | ||||
| 			throw new Error('userId is requierd'); | ||||
| 		if (!hostId) | ||||
| 			throw new Error('hostId is requierd'); | ||||
| 		if (!passphrase) | ||||
| 			throw new Error('passphrase is requierd'); | ||||
|  | ||||
| 		if (!keyStorage || typeof keyStorage.read !== 'function' || typeof keyStorage.write !== 'function') | ||||
| 			throw new Error('keyStorage implemntation missing or wrong'); | ||||
|  | ||||
| 		this.url = url; | ||||
| 		this.partnerId = partnerId; | ||||
| 		this.userId = userId; | ||||
| 		this.hostId = hostId; | ||||
| 		this.keyStorage = keyStorage; | ||||
| 		this.keyEncryptor = defaultKeyEncryptor({ passphrase }); | ||||
| 	} | ||||
|  | ||||
| 	send(order) { | ||||
| 		const isInObject = ('operation' in order); | ||||
|  | ||||
| 		if (!isInObject) throw new Error('Operation for the order needed'); | ||||
|  | ||||
| 		if (order.operation.toUpperCase() === constants.orderOperations.ini) return this.initialization(order); | ||||
| 		if (order.operation.toUpperCase() === constants.orderOperations.upload) return this.upload(order); | ||||
| 		if (order.operation.toUpperCase() === constants.orderOperations.download) return this.download(order); | ||||
|  | ||||
| 		throw new Error('Wrong order operation provided'); | ||||
| 	} | ||||
|  | ||||
| 	async initialization(order) { | ||||
| @@ -32,7 +74,6 @@ module.exports = class Client { | ||||
| 		if (res.isSegmented() && res.isLastSegment()) | ||||
| 			await this.ebicsRequest(order); | ||||
|  | ||||
| 		// return res.orderData(); | ||||
| 		return { | ||||
| 			orderData: res.orderData(), | ||||
| 			orderId: res.orderId(), | ||||
| @@ -55,11 +96,12 @@ module.exports = class Client { | ||||
|  | ||||
| 	ebicsRequest(order) { | ||||
| 		return new Promise((resolve, reject) => { | ||||
| 			const { version, keys } = order; | ||||
| 			// const s = signer.version(version).use(serializer.use(order).toXML(), keys).digest().sign().toXML(); // new (signer.version(version))(serializer.use(order).toXML(), keys).digest().sign().toXML(); | ||||
| 			const { version } = order; | ||||
| 			const keys = this.keys(); | ||||
|  | ||||
| 			$request.post({ | ||||
| 				url: this.url, | ||||
| 				body: signer.version(version).sign(serializer.use(order).toXML(), keys), // s, // new (signer.version(version))(serializer.use(order).toXML(), keys).digest().sign().toXML(), | ||||
| 				body: signer.version(version).sign(serializer.use(order, this).toXML(), keys.x()), // s, // new (signer.version(version))(serializer.use(order).toXML(), keys).digest().sign().toXML(), | ||||
| 				headers: { 'content-type': 'text/xml;charset=UTF-8' }, | ||||
| 			}, (err, res, data) => (err ? reject(err) : resolve(response.version(version)(data, keys)))); | ||||
| 		}); | ||||
| @@ -80,4 +122,25 @@ module.exports = class Client { | ||||
| 	status(order) { | ||||
| 		return this.download(order); | ||||
| 	} | ||||
|  | ||||
| 	keys() { | ||||
| 		const keysString = this.keyStorage.read(); | ||||
|  | ||||
| 		return new Keys(JSON.parse(this.keyEncryptor.decrypt(keysString))); | ||||
| 	} | ||||
|  | ||||
| 	setBankKeys(bankKeys) { | ||||
| 		const keysObject = this.keys(); | ||||
|  | ||||
| 		keysObject.setBankKeys(bankKeys); | ||||
| 		const { keys } = keysObject; | ||||
|  | ||||
| 		Object.keys(keys).map((key) => { | ||||
| 			keys[key] = keys[key] === null ? null : keys[key].toPem(); | ||||
|  | ||||
| 			return key; | ||||
| 		}); | ||||
|  | ||||
| 		this.keyStorage.write(this.keyEncryptor.encrypt(JSON.stringify(keys))); | ||||
| 	} | ||||
| }; | ||||
|   | ||||
| @@ -4,9 +4,15 @@ const packageJson = require('../package.json'); | ||||
|  | ||||
| const name = 'eCollect Node Ebics Client'; | ||||
| const { version } = packageJson; | ||||
| const orderOperations = { | ||||
| 	ini: 'INI', | ||||
| 	upload: 'UPLOAD', | ||||
| 	download: 'DOWNLOAD', | ||||
| }; | ||||
|  | ||||
| module.exports = { | ||||
| 	name, | ||||
| 	version, | ||||
| 	orderOperations, | ||||
| 	productString: `${name} ${version}`, | ||||
| }; | ||||
|   | ||||
| @@ -3,26 +3,22 @@ | ||||
| const BN = require('bn.js'); | ||||
| const NodeRSA = require('node-rsa'); | ||||
|  | ||||
| module.exports = class Key { | ||||
| 	constructor(encodedKey/* , passphrase = null */) { | ||||
| 		this._key = (encodedKey instanceof NodeRSA) ? encodedKey : new NodeRSA(encodedKey); | ||||
| 	} | ||||
| const keyOrNull = (encodedKey) => { | ||||
| 	if (encodedKey === null) return new NodeRSA(); | ||||
|  | ||||
| 	static generate(keysize = 2048) { | ||||
| 		return new NodeRSA({ b: keysize }); | ||||
| 	} | ||||
| 	return (encodedKey instanceof NodeRSA) ? encodedKey : new NodeRSA(encodedKey); | ||||
| }; | ||||
|  | ||||
| 	static importKey({ mod, exp }) { | ||||
| 		const key = new NodeRSA(); | ||||
| module.exports = encodedKey => ({ | ||||
| 	key: keyOrNull(encodedKey), | ||||
|  | ||||
| 		key.importKey({ n: mod, e: exp }, 'components-public'); | ||||
| 	generate(keySize = 2048) { | ||||
| 		return new NodeRSA({ b: keySize }); | ||||
| 	}, | ||||
|  | ||||
| 		return new Key(key); | ||||
| 	} | ||||
|  | ||||
| 	get key() { | ||||
| 		return this._key; | ||||
| 	} | ||||
| 	importKey({ mod, exp }) { | ||||
| 		this.key.importKey({ n: mod, e: exp }, 'components-public'); | ||||
| 	}, | ||||
|  | ||||
| 	n(to = 'buff') { | ||||
| 		const keyN = Buffer.from(this.key.exportKey('components-public').n); | ||||
| @@ -30,7 +26,7 @@ module.exports = class Key { | ||||
| 		return to === 'hex' | ||||
| 			? keyN.toString('hex', 1) | ||||
| 			: keyN; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	e(to = 'buff') { | ||||
| 		const eKey = new BN(this.key.exportKey('components-public').e).toBuffer(); | ||||
| @@ -38,13 +34,13 @@ module.exports = class Key { | ||||
| 		return to === 'hex' | ||||
| 			? eKey.toString('hex') | ||||
| 			: eKey; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	d() { | ||||
| 		return this.key.keyPair.d.toBuffer(); | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	toPem() { | ||||
| 		return this.key.isPrivate() ? this.key.exportKey('pkcs1-private-pem') : this.key.exportKey('pkcs8-public-pem'); | ||||
| 	} | ||||
| }; | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const Key = require('./Key'); | ||||
| const Key = require('./key'); | ||||
|  | ||||
| const keyOrNull = key => (key ? new Key(key) : null); | ||||
| const keyOrNull = key => (key ? Key(key) : null); | ||||
|  | ||||
| module.exports = class Keys { | ||||
| 	constructor({ | ||||
| @@ -32,8 +32,8 @@ module.exports = class Keys { | ||||
| 	} | ||||
|  | ||||
| 	setBankKeys(bankKeys) { | ||||
| 		this.keys.bankX002 = Key.importKey(bankKeys.bankX002); | ||||
| 		this.keys.bankE002 = Key.importKey(bankKeys.bankE002); | ||||
| 		this.keys.bankX002.importKey(bankKeys.bankX002); | ||||
| 		this.keys.bankE002.importKey(bankKeys.bankE002); | ||||
| 	} | ||||
|  | ||||
| 	a() { | ||||
|   | ||||
							
								
								
									
										24
									
								
								lib/keymanagers/defaultKeyEncryptor.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								lib/keymanagers/defaultKeyEncryptor.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const crypto = require('crypto'); | ||||
|  | ||||
| const encrypt = (data, algorithm, passphrase) => { | ||||
| 	const cipher = crypto.createCipher(algorithm, passphrase); | ||||
| 	const encrypted = cipher.update(data, 'utf8', 'hex') + cipher.final('hex'); | ||||
| 	return Buffer.from(encrypted).toString('base64'); | ||||
| }; | ||||
| const decrypt = (data, algorithm, passphrase) => { | ||||
| 	data = (Buffer.from(data, 'base64')).toString(); | ||||
| 	const decipher = crypto.createDecipher(algorithm, passphrase); | ||||
| 	const decrypted = decipher.update(data, 'hex', 'utf8') + decipher.final('utf8'); | ||||
|  | ||||
| 	return decrypted; | ||||
| }; | ||||
|  | ||||
| module.exports = ({ | ||||
| 	passphrase, | ||||
| 	algorithm = 'aes-256-cbc', | ||||
| }) => ({ | ||||
| 	encrypt: data => encrypt(data, algorithm, passphrase), | ||||
| 	decrypt: data => decrypt(data, algorithm, passphrase), | ||||
| }); | ||||
| @@ -3,10 +3,10 @@ | ||||
| const H004Serializer = require('../orders/H004/serializer'); | ||||
|  | ||||
| module.exports = { | ||||
| 	use(order) { | ||||
| 	use(order, client) { | ||||
| 		const { version } = order; | ||||
|  | ||||
| 		if (version.toUpperCase() === 'H004') return H004Serializer.use(order); | ||||
| 		if (version.toUpperCase() === 'H004') return H004Serializer.use(order, client); | ||||
|  | ||||
| 		throw Error('Error middleware/serializer.js: Invalid version number'); | ||||
| 	}, | ||||
|   | ||||
| @@ -1,18 +1,18 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const orders = require('../orders'); | ||||
| const constants = require('../../consts'); | ||||
|  | ||||
| const iniSerializer = require('./serializers/ini'); | ||||
| const downloadSerializer = require('./serializers/download'); | ||||
| const uploadSerializer = require('./serializers/upload'); | ||||
|  | ||||
| module.exports = { | ||||
| 	use(order) { | ||||
| 		const { version, orderType } = order; | ||||
| 	use(order, client) { | ||||
| 		const operation = order.operation.toUpperCase(); | ||||
|  | ||||
| 		if (orders.version(version).isIni(orderType)) return iniSerializer.use(order); | ||||
| 		if (orders.version(version).isDownload(orderType)) return downloadSerializer.use(order); | ||||
| 		if (orders.version(version).isUpload(orderType)) return uploadSerializer.use(order); | ||||
| 		if (operation === constants.orderOperations.ini) return iniSerializer.use(order, client); | ||||
| 		if (operation === constants.orderOperations.download) return downloadSerializer.use(order, client); | ||||
| 		if (operation === constants.orderOperations.upload) return uploadSerializer.use(order, client); | ||||
|  | ||||
| 		throw Error('Error from orders/orders.js: Wrong order version/type.'); | ||||
| 	}, | ||||
|   | ||||
| @@ -7,14 +7,19 @@ const Crypto = require('../../../crypto/Crypto'); | ||||
| const genericSerializer = require('./generic'); | ||||
|  | ||||
| module.exports = { | ||||
| 	use(orderBuilder) { | ||||
| 	use(order, client) { | ||||
| 		const keys = client.keys(); | ||||
| 		const ebicsAccount = { | ||||
| 			partnerId: client.partnerId, | ||||
| 			userId: client.userId, | ||||
| 			hostId: client.hostId, | ||||
| 		}; | ||||
| 		const { orderDetails, transactionId } = order; | ||||
| 		const { | ||||
| 			ebicsData, orderDetails, keys, productString, transactionId, | ||||
| 		} = orderBuilder; | ||||
| 		const { | ||||
| 			rootName, xmlOptions, xmlSchema, receipt, transfer, | ||||
| 		} = genericSerializer(orderBuilder); | ||||
| 			rootName, xmlOptions, xmlSchema, receipt, transfer, productString, | ||||
| 		} = genericSerializer(client.hostId, transactionId); | ||||
|  | ||||
| 		this.productString = productString; | ||||
| 		this.rootName = rootName; | ||||
| 		this.xmlOptions = xmlOptions; | ||||
| 		this.xmlSchema = xmlSchema; | ||||
| @@ -26,11 +31,11 @@ module.exports = { | ||||
| 		this.xmlSchema.header = { | ||||
| 			'@': { authenticate: true }, | ||||
| 			static: { | ||||
| 				HostID: ebicsData.hostId, | ||||
| 				HostID: ebicsAccount.hostId, | ||||
| 				Nonce: Crypto.nonce(), | ||||
| 				Timestamp: Crypto.timestamp(), | ||||
| 				PartnerID: ebicsData.partnerId, | ||||
| 				UserID: ebicsData.userId, | ||||
| 				PartnerID: ebicsAccount.partnerId, | ||||
| 				UserID: ebicsAccount.userId, | ||||
| 				Product: { | ||||
| 					'@': { Language: 'en' }, | ||||
| 					'#': productString, | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const constants = require('../../../consts'); | ||||
|  | ||||
| const rootName = 'ebicsRequest'; | ||||
| const rootAttributes = { | ||||
| 	'xmlns:ds': 'http://www.w3.org/2000/09/xmldsig#', | ||||
| @@ -58,76 +60,75 @@ const xmlOptions = { | ||||
| 	}, | ||||
| }; | ||||
|  | ||||
| module.exports = (orderBuilder) => { | ||||
| 	const { ebicsData, transactionId } = orderBuilder; | ||||
| module.exports = (hostId, transactionId) => ({ | ||||
| 	// return { | ||||
| 	productString: constants.productString, | ||||
| 	rootName, | ||||
| 	xmlOptions, | ||||
| 	xmlSchema: { | ||||
| 		'@': rootAttributes, | ||||
| 		header, | ||||
| 		AuthSignature: authSignature, | ||||
| 		body, | ||||
| 	}, | ||||
|  | ||||
| 	return { | ||||
| 		rootName, | ||||
| 		xmlOptions, | ||||
| 		xmlSchema: { | ||||
| 	receipt() { | ||||
| 		this.xmlSchema = { | ||||
| 			'@': rootAttributes, | ||||
| 			header, | ||||
|  | ||||
| 			header: { | ||||
| 				'@': { authenticate: true }, | ||||
| 				static: { | ||||
| 					HostID: hostId, | ||||
| 					TransactionID: transactionId, | ||||
| 				}, | ||||
| 				mutable: { | ||||
| 					TransactionPhase: 'Receipt', | ||||
| 				}, | ||||
| 			}, | ||||
|  | ||||
| 			AuthSignature: authSignature, | ||||
| 			body, | ||||
| 		}, | ||||
|  | ||||
| 		receipt() { | ||||
| 			this.xmlSchema = { | ||||
| 				'@': rootAttributes, | ||||
|  | ||||
| 				header: { | ||||
| 			body: { | ||||
| 				TransferReceipt: { | ||||
| 					'@': { authenticate: true }, | ||||
| 					static: { | ||||
| 						HostID: ebicsData.hostId, | ||||
| 						TransactionID: transactionId, | ||||
| 					}, | ||||
| 					mutable: { | ||||
| 						TransactionPhase: 'Receipt', | ||||
| 					ReceiptCode: 0, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}; | ||||
|  | ||||
| 		return this; | ||||
| 	}, | ||||
|  | ||||
| 	transfer(encryptedOrderData) { | ||||
| 		this.xmlSchema = { | ||||
| 			'@': rootAttributes, | ||||
|  | ||||
| 			header: { | ||||
| 				'@': { authenticate: true }, | ||||
| 				static: { | ||||
| 					HostID: hostId, | ||||
| 					TransactionID: transactionId, | ||||
| 				}, | ||||
| 				mutable: { | ||||
| 					TransactionPhase: 'Transfer', | ||||
| 					SegmentNumber: { | ||||
| 						'@': { lastSegment: true }, | ||||
| 						'#': 1, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
|  | ||||
| 				AuthSignature: authSignature, | ||||
| 			AuthSignature: authSignature, | ||||
|  | ||||
| 				body: { | ||||
| 					TransferReceipt: { | ||||
| 						'@': { authenticate: true }, | ||||
| 						ReceiptCode: 0, | ||||
| 					}, | ||||
| 			body: { | ||||
| 				DataTransfer: { | ||||
| 					OrderData: encryptedOrderData, | ||||
| 				}, | ||||
| 			}; | ||||
| 			}, | ||||
| 		}; | ||||
|  | ||||
| 			return this; | ||||
| 		}, | ||||
|  | ||||
| 		transfer(encryptedOrderData) { | ||||
| 			this.xmlSchema = { | ||||
| 				'@': rootAttributes, | ||||
|  | ||||
| 				header: { | ||||
| 					'@': { authenticate: true }, | ||||
| 					static: { | ||||
| 						HostID: ebicsData.hostId, | ||||
| 						TransactionID: transactionId, | ||||
| 					}, | ||||
| 					mutable: { | ||||
| 						TransactionPhase: 'Transfer', | ||||
| 						SegmentNumber: { | ||||
| 							'@': { lastSegment: true }, | ||||
| 							'#': 1, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
|  | ||||
| 				AuthSignature: authSignature, | ||||
|  | ||||
| 				body: { | ||||
| 					DataTransfer: { | ||||
| 						OrderData: encryptedOrderData, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}; | ||||
|  | ||||
| 			return this; | ||||
| 		}, | ||||
| 	}; | ||||
| }; | ||||
| 		return this; | ||||
| 	}, | ||||
| 	// }; | ||||
| }); | ||||
|   | ||||
| @@ -8,7 +8,7 @@ const Crypto = require('../../../crypto/Crypto'); | ||||
|  | ||||
| const genericSerializer = require('./generic'); | ||||
|  | ||||
| const keySignature = (ebicsData, key, xmlOptions) => { | ||||
| const keySignature = (ebicsAccount, key, xmlOptions) => { | ||||
| 	const xmlOrderData = { | ||||
| 		'@': { | ||||
| 			'xmlns:ds': 'http://www.w3.org/2000/09/xmldsig#', | ||||
| @@ -24,13 +24,13 @@ const keySignature = (ebicsData, key, xmlOptions) => { | ||||
| 			}, | ||||
| 			SignatureVersion: 'A006', | ||||
| 		}, | ||||
| 		PartnerID: ebicsData.partnerId, | ||||
| 		UserID: ebicsData.userId, | ||||
| 		PartnerID: ebicsAccount.partnerId, | ||||
| 		UserID: ebicsAccount.userId, | ||||
| 	}; | ||||
|  | ||||
| 	return js2xmlparser.parse('SignaturePubKeyOrderData', xmlOrderData, xmlOptions); | ||||
| }; | ||||
| const orderData = (ebicsData, keys, xmlOptions) => { | ||||
| const orderData = (ebicsAccount, keys, xmlOptions) => { | ||||
| 	const xmlOrderData = { | ||||
| 		'@': { | ||||
| 			'xmlns:ds': 'http://www.w3.org/2000/09/xmldsig#', | ||||
| @@ -54,20 +54,20 @@ const orderData = (ebicsData, keys, xmlOptions) => { | ||||
| 			}, | ||||
| 			EncryptionVersion: 'E002', | ||||
| 		}, | ||||
| 		PartnerID: ebicsData.partnerId, | ||||
| 		UserID: ebicsData.userId, | ||||
| 		PartnerID: ebicsAccount.partnerId, | ||||
| 		UserID: ebicsAccount.userId, | ||||
| 	}; | ||||
|  | ||||
| 	return js2xmlparser.parse('HIARequestOrderData', xmlOrderData, xmlOptions); | ||||
| }; | ||||
| const commonHeader = (ebicsData, orderDetails, productString) => ({ | ||||
| const commonHeader = (ebicsAccount, orderDetails, productString) => ({ | ||||
| 	'@': { authenticate: true }, | ||||
| 	static: { | ||||
| 		HostID: ebicsData.hostId, | ||||
| 		HostID: ebicsAccount.hostId, | ||||
| 		Nonce: Crypto.nonce(), | ||||
| 		Timestamp: Crypto.timestamp(), | ||||
| 		PartnerID: ebicsData.partnerId, | ||||
| 		UserID: ebicsData.userId, | ||||
| 		PartnerID: ebicsAccount.partnerId, | ||||
| 		UserID: ebicsAccount.userId, | ||||
| 		Product: { | ||||
| 			'@': { Language: 'en' }, | ||||
| 			'#': productString, | ||||
| @@ -80,57 +80,61 @@ const commonHeader = (ebicsData, orderDetails, productString) => ({ | ||||
| const process = { | ||||
| 	INI: { | ||||
| 		rootName: 'ebicsUnsecuredRequest', | ||||
| 		header: (ebicsData, orderDetails, productString) => { | ||||
| 			const ch = commonHeader(ebicsData, orderDetails, productString); | ||||
| 		header: (ebicsAccount, orderDetails, productString) => { | ||||
| 			const ch = commonHeader(ebicsAccount, orderDetails, productString); | ||||
|  | ||||
| 			delete ch.static.Nonce; | ||||
| 			delete ch.static.Timestamp; | ||||
|  | ||||
| 			return ch; | ||||
| 		}, | ||||
| 		body: (ebicsData, keys, xmlOptions) => ({ | ||||
| 		body: (ebicsAccount, keys, xmlOptions) => ({ | ||||
| 			DataTransfer: { | ||||
| 				OrderData: Buffer.from(zlib.deflateSync(keySignature(ebicsData, keys.a(), xmlOptions))).toString('base64'), | ||||
| 				OrderData: Buffer.from(zlib.deflateSync(keySignature(ebicsAccount, keys.a(), xmlOptions))).toString('base64'), | ||||
| 			}, | ||||
| 		}), | ||||
| 	}, | ||||
| 	HIA: { | ||||
| 		rootName: 'ebicsUnsecuredRequest', | ||||
| 		header: (ebicsData, orderDetails, productString) => { | ||||
| 			const ch = commonHeader(ebicsData, orderDetails, productString); | ||||
| 		header: (ebicsAccount, orderDetails, productString) => { | ||||
| 			const ch = commonHeader(ebicsAccount, orderDetails, productString); | ||||
|  | ||||
| 			delete ch.static.Nonce; | ||||
| 			delete ch.static.Timestamp; | ||||
|  | ||||
| 			return ch; | ||||
| 		}, | ||||
| 		body: (ebicsData, keys, xmlOptions) => ({ | ||||
| 		body: (ebicsAccount, keys, xmlOptions) => ({ | ||||
| 			DataTransfer: { | ||||
| 				OrderData: Buffer.from(zlib.deflateSync(orderData(ebicsData, keys, xmlOptions))).toString('base64'), | ||||
| 				OrderData: Buffer.from(zlib.deflateSync(orderData(ebicsAccount, keys, xmlOptions))).toString('base64'), | ||||
| 			}, | ||||
| 		}), | ||||
| 	}, | ||||
| 	HPB: { | ||||
| 		rootName: 'ebicsNoPubKeyDigestsRequest', | ||||
| 		header: (ebicsData, orderDetails, productString) => commonHeader(ebicsData, orderDetails, productString), | ||||
| 		header: (ebicsAccount, orderDetails, productString) => commonHeader(ebicsAccount, orderDetails, productString), | ||||
| 		body: () => ({}), | ||||
| 	}, | ||||
| }; | ||||
|  | ||||
| module.exports = { | ||||
| 	use(orderBuilder) { | ||||
| 		const { xmlOptions, xmlSchema } = genericSerializer(orderBuilder); | ||||
| 		const { | ||||
| 			ebicsData, orderDetails, keys, productString, | ||||
| 		} = orderBuilder; | ||||
| 	use(order, client) { | ||||
| 		const keys = client.keys(); | ||||
| 		const { orderDetails, transactionId } = order; | ||||
| 		const { xmlOptions, xmlSchema, productString } = genericSerializer(client.host, transactionId); | ||||
| 		const orderType = orderDetails.OrderType.toUpperCase(); | ||||
| 		const ebicsAccount = { | ||||
| 			partnerId: client.partnerId, | ||||
| 			userId: client.userId, | ||||
| 			hostId: client.hostId, | ||||
| 		}; | ||||
|  | ||||
| 		this.rootName = process[orderType].rootName; | ||||
| 		this.xmlOptions = xmlOptions; | ||||
| 		this.xmlSchema = xmlSchema; | ||||
|  | ||||
| 		this.xmlSchema.header = process[orderType].header(ebicsData, orderDetails, productString); | ||||
| 		this.xmlSchema.body = process[orderType].body(ebicsData, keys, this.xmlOptions); | ||||
| 		this.xmlSchema.header = process[orderType].header(ebicsAccount, orderDetails, productString); | ||||
| 		this.xmlSchema.body = process[orderType].body(ebicsAccount, keys, this.xmlOptions); | ||||
|  | ||||
| 		if (orderType !== 'HPB' && Object.prototype.hasOwnProperty.call(this.xmlSchema, 'AuthSignature')) | ||||
| 			delete this.xmlSchema.AuthSignature; | ||||
|   | ||||
| @@ -9,12 +9,14 @@ const Crypto = require('../../../crypto/Crypto'); | ||||
|  | ||||
| const downloadSerializer = require('./download'); | ||||
|  | ||||
| const transKey = crypto.randomBytes(16); | ||||
|  | ||||
| const signatureValue = (document, key) => { | ||||
| 	const digested = Crypto.digestWithHash(document.replace(/\n|\r/g, '')); | ||||
|  | ||||
| 	return Crypto.sign(key, digested); | ||||
| }; | ||||
| const orderSignature = (ebicsData, document, key, xmlOptions) => { | ||||
| const orderSignature = (ebicsAccount, document, key, xmlOptions) => { | ||||
| 	const xmlObj = { | ||||
| 		'@': { | ||||
| 			xmlns: 'http://www.ebics.org/S001', | ||||
| @@ -24,15 +26,15 @@ const orderSignature = (ebicsData, document, key, xmlOptions) => { | ||||
| 		OrderSignatureData: { | ||||
| 			SignatureVersion: 'A006', | ||||
| 			SignatureValue: signatureValue(document, key), | ||||
| 			PartnerID: ebicsData.partnerId, | ||||
| 			UserID: ebicsData.userId, | ||||
| 			PartnerID: ebicsAccount.partnerId, | ||||
| 			UserID: ebicsAccount.userId, | ||||
| 		}, | ||||
| 	}; | ||||
|  | ||||
| 	return js2xmlparser.parse('UserSignatureData', xmlObj, xmlOptions); | ||||
| }; | ||||
| const encryptedOrderSignature = (ebicsData, document, transactionKey, key, xmlOptions) => { | ||||
| 	const dst = zlib.deflateSync(orderSignature(ebicsData, document, key, xmlOptions)); | ||||
| const encryptedOrderSignature = (ebicsAccount, document, transactionKey, key, xmlOptions) => { | ||||
| 	const dst = zlib.deflateSync(orderSignature(ebicsAccount, document, key, xmlOptions)); | ||||
| 	const cipher = crypto.createCipheriv('aes-128-cbc', transactionKey, Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])).setAutoPadding(false); | ||||
|  | ||||
| 	return Buffer.concat([cipher.update(Crypto.pad(dst)), cipher.final()]).toString('base64'); | ||||
| @@ -45,23 +47,28 @@ const encryptedOrderData = (document, transactionKey) => { | ||||
| }; | ||||
|  | ||||
| module.exports = { | ||||
| 	use(orderBuilder) { | ||||
| 	use(order, client) { | ||||
| 		const keys = client.keys(); | ||||
| 		const ebicsAccount = { | ||||
| 			partnerId: client.partnerId, | ||||
| 			userId: client.userId, | ||||
| 			hostId: client.hostId, | ||||
| 		}; | ||||
| 		const { | ||||
| 			ebicsData, keys, transactionId, transactionKey, document, | ||||
| 		} = orderBuilder; | ||||
| 			transactionId, document, | ||||
| 		} = order; | ||||
| 		const { | ||||
| 			rootName, xmlOptions, xmlSchema, transfer, | ||||
| 		} = downloadSerializer.use(orderBuilder); | ||||
| 		} = downloadSerializer.use(order, client); | ||||
|  | ||||
| 		this.rootName = rootName; | ||||
| 		this.xmlOptions = xmlOptions; | ||||
| 		this.xmlSchema = xmlSchema; | ||||
| 		this.transfer = transfer; | ||||
|  | ||||
| 		if (transactionId) return this.transfer(encryptedOrderData(document, transactionKey)); | ||||
| 		if (transactionId) return this.transfer(encryptedOrderData(document, transKey)); | ||||
|  | ||||
| 		this.xmlSchema.header.static.NumSegments = 1; | ||||
|  | ||||
| 		this.xmlSchema.body = { | ||||
| 			DataTransfer: { | ||||
| 				DataEncryptionInfo: { | ||||
| @@ -70,11 +77,11 @@ module.exports = { | ||||
| 						'@': { Version: 'E002', Algorithm: 'http://www.w3.org/2001/04/xmlenc#sha256' }, | ||||
| 						'#': Crypto.digestPublicKey(keys.bankE()), | ||||
| 					}, | ||||
| 					TransactionKey: Crypto.publicEncrypt(keys.bankE(), transactionKey).toString('base64'), | ||||
| 					TransactionKey: Crypto.publicEncrypt(keys.bankE(), transKey).toString('base64'), | ||||
| 				}, | ||||
| 				SignatureData: { | ||||
| 					'@': { authenticate: true }, | ||||
| 					'#': encryptedOrderSignature(ebicsData, document, transactionKey, keys.a(), this.xmlOptions), | ||||
| 					'#': encryptedOrderSignature(ebicsAccount, document, transKey, keys.a(), this.xmlOptions), | ||||
| 				}, | ||||
| 			}, | ||||
| 		}; | ||||
|   | ||||
| @@ -41,8 +41,7 @@ const sign = (doc, key) => { | ||||
| const toXML = doc => new XMLSerializer().serializeToString(doc); | ||||
|  | ||||
| module.exports = { | ||||
| 	sign(data, keys) { | ||||
| 		const keyX = keys.x(); | ||||
| 	sign(data, keyX) { | ||||
| 		const doc = new DOMParser().parseFromString(data, 'text/xml'); | ||||
|  | ||||
| 		return toXML(sign(digest(doc), keyX)); | ||||
|   | ||||
| @@ -1,35 +0,0 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const orders = { | ||||
| 	H004: { | ||||
| 		ini: ['INI', 'HIA', 'HPB'], | ||||
| 		download: ['HAA', 'HTD', 'XTD', 'HPD', 'HKD', 'PTK', 'HAC', 'STA', 'VMK', 'C52', 'C53', 'C54', 'Z01'], | ||||
| 		upload: ['AZV', 'CD1', 'CDB', 'CDD', 'CDS', 'CCT', 'CCS', 'XE3'], | ||||
| 	}, | ||||
| }; | ||||
|  | ||||
| module.exports = { | ||||
| 	version(v) { | ||||
| 		this.orders = orders[v.toUpperCase()]; | ||||
|  | ||||
| 		return this; | ||||
| 	}, | ||||
|  | ||||
| 	isIni(orderType) { | ||||
| 		const { ini } = this.orders; | ||||
|  | ||||
| 		return ini.includes(orderType.toUpperCase()); | ||||
| 	}, | ||||
|  | ||||
| 	isDownload(orderType) { | ||||
| 		const { download } = this.orders; | ||||
|  | ||||
| 		return download.includes(orderType.toUpperCase()); | ||||
| 	}, | ||||
|  | ||||
| 	isUpload(orderType) { | ||||
| 		const { upload } = this.orders; | ||||
|  | ||||
| 		return upload.includes(orderType.toUpperCase()); | ||||
| 	}, | ||||
| }; | ||||
| @@ -7,12 +7,13 @@ module.exports = (pathToFile) => { | ||||
| 
 | ||||
| 	return { | ||||
| 		read() { | ||||
| 			if (!fs.existsSync(path)) | ||||
| 				return null; | ||||
| 			return fs.readFileSync(path, { encoding: 'utf8' }); | ||||
| 		}, | ||||
| 
 | ||||
| 		save(data) { | ||||
| 		write(data) { | ||||
| 			fs.writeFileSync(path, data, { encoding: 'utf8' }); | ||||
| 
 | ||||
| 			return this; | ||||
| 		}, | ||||
| 
 | ||||
		Reference in New Issue
	
	Block a user