mirror of
https://github.com/node-ebics/node-ebics-client.git
synced 2024-12-25 05:41:49 +00:00
chore(download): Add support for segmented download
This commit is contained in:
parent
fe0f585b27
commit
59515f21e3
@ -147,14 +147,35 @@ module.exports = class Client {
|
||||
async download(order) {
|
||||
if (this.tracesStorage)
|
||||
this.tracesStorage.new().ofType('ORDER.DOWNLOAD');
|
||||
const res = await this.ebicsRequest(order);
|
||||
|
||||
const orderData = [];
|
||||
|
||||
let res = await this.ebicsRequest(order);
|
||||
let transactionKey = res.transactionKey();
|
||||
|
||||
order.transactionId = res.transactionId();
|
||||
order.segmentNumber = res.segmentNumber();
|
||||
|
||||
if (res.orderData()) orderData.push(res.orderData());
|
||||
|
||||
// In case of multi-segment download transaction is
|
||||
// usually supplied during INITIALISATION phase,
|
||||
// whereas the actual data is delivered in following segments
|
||||
while (res.isSegmented() && !res.isLastSegment()) {
|
||||
order.segmentNumber = res.segmentNumber() + 1;
|
||||
|
||||
res = await this.ebicsRequest(order);
|
||||
transactionKey = transactionKey || res.transactionKey();
|
||||
res.obtainedTransactionKey = transactionKey;
|
||||
|
||||
if (res.orderData()) orderData.push(res.orderData());
|
||||
}
|
||||
|
||||
if (res.isSegmented() && res.isLastSegment()) {
|
||||
if (this.tracesStorage)
|
||||
this.tracesStorage.connect().ofType('RECEIPT.ORDER.DOWNLOAD');
|
||||
|
||||
order.segmentNumber = null; // Clear segment number for receipt request
|
||||
await this.ebicsRequest(order);
|
||||
}
|
||||
|
||||
@ -162,7 +183,7 @@ module.exports = class Client {
|
||||
const returnedBusinessCode = res.businessCode();
|
||||
|
||||
return {
|
||||
orderData: res.orderData(),
|
||||
orderData: orderData.length === 1 ? orderData[0] : orderData, // backward compatibility
|
||||
orderId: res.orderId(),
|
||||
|
||||
technicalCode: returnedTechnicalCode,
|
||||
|
@ -22,6 +22,7 @@ const lastChild = (node) => {
|
||||
module.exports = (xml, keys) => ({
|
||||
keys,
|
||||
doc: new DOMParser().parseFromString(xml, 'text/xml'),
|
||||
obtainedTransactionKey: null,
|
||||
|
||||
isSegmented() {
|
||||
const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' });
|
||||
@ -30,6 +31,13 @@ module.exports = (xml, keys) => ({
|
||||
return !!node.length;
|
||||
},
|
||||
|
||||
segmentNumber() {
|
||||
const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' });
|
||||
const node = select('//xmlns:header/xmlns:mutable/xmlns:SegmentNumber', this.doc);
|
||||
|
||||
return node.length ? Number.parseInt(node[0].textContent, 10) : null;
|
||||
},
|
||||
|
||||
isLastSegment() {
|
||||
const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' });
|
||||
const node = select("//xmlns:header/xmlns:mutable/*[@lastSegment='true']", this.doc);
|
||||
@ -40,7 +48,7 @@ module.exports = (xml, keys) => ({
|
||||
orderData() {
|
||||
const orderDataNode = this.doc.getElementsByTagNameNS('urn:org:ebics:H004', 'OrderData');
|
||||
|
||||
if (!orderDataNode.length) return {};
|
||||
if (!orderDataNode.length) return null;
|
||||
|
||||
const orderData = orderDataNode[0].textContent;
|
||||
const decipher = crypto.createDecipheriv('aes-128-cbc', this.transactionKey(), DEFAULT_IV).setAutoPadding(false);
|
||||
@ -50,6 +58,7 @@ module.exports = (xml, keys) => ({
|
||||
},
|
||||
|
||||
transactionKey() {
|
||||
if (this.obtainedTransactionKey) return this.obtainedTransactionKey;
|
||||
const keyNodeText = this.doc.getElementsByTagNameNS('urn:org:ebics:H004', 'TransactionKey')[0].textContent;
|
||||
return Crypto.privateDecrypt(this.keys.e(), Buffer.from(keyNodeText, 'base64'));
|
||||
},
|
||||
|
@ -13,7 +13,7 @@ module.exports = {
|
||||
userId: client.userId,
|
||||
hostId: client.hostId,
|
||||
};
|
||||
const { orderDetails, transactionId } = order;
|
||||
const { orderDetails, transactionId, segmentNumber } = order;
|
||||
const {
|
||||
rootName, xmlOptions, xmlSchema, receipt, transfer, productString,
|
||||
} = genericSerializer(client.hostId, transactionId);
|
||||
@ -25,35 +25,46 @@ module.exports = {
|
||||
this.receipt = receipt;
|
||||
this.transfer = transfer;
|
||||
|
||||
if (transactionId) return this.receipt();
|
||||
if (!segmentNumber && transactionId) return this.receipt();
|
||||
|
||||
this.xmlSchema.header = {
|
||||
'@': { authenticate: true },
|
||||
static: {
|
||||
HostID: ebicsAccount.hostId,
|
||||
Nonce: Crypto.nonce(),
|
||||
Timestamp: Crypto.timestamp(),
|
||||
PartnerID: ebicsAccount.partnerId,
|
||||
UserID: ebicsAccount.userId,
|
||||
Product: {
|
||||
'@': { Language: 'en' },
|
||||
'#': productString,
|
||||
},
|
||||
OrderDetails: orderDetails,
|
||||
BankPubKeyDigests: {
|
||||
Authentication: {
|
||||
'@': { Version: 'X002', Algorithm: 'http://www.w3.org/2001/04/xmlenc#sha256' },
|
||||
'#': Crypto.digestPublicKey(keys.bankX()),
|
||||
...!transactionId && {
|
||||
Nonce: Crypto.nonce(),
|
||||
Timestamp: Crypto.timestamp(),
|
||||
PartnerID: ebicsAccount.partnerId,
|
||||
UserID: ebicsAccount.userId,
|
||||
Product: {
|
||||
'@': { Language: 'en' },
|
||||
'#': productString,
|
||||
},
|
||||
Encryption: {
|
||||
'@': { Version: 'E002', Algorithm: 'http://www.w3.org/2001/04/xmlenc#sha256' },
|
||||
'#': Crypto.digestPublicKey(keys.bankE()),
|
||||
OrderDetails: orderDetails,
|
||||
BankPubKeyDigests: {
|
||||
Authentication: {
|
||||
'@': { Version: 'X002', Algorithm: 'http://www.w3.org/2001/04/xmlenc#sha256' },
|
||||
'#': Crypto.digestPublicKey(keys.bankX()),
|
||||
},
|
||||
Encryption: {
|
||||
'@': { Version: 'E002', Algorithm: 'http://www.w3.org/2001/04/xmlenc#sha256' },
|
||||
'#': Crypto.digestPublicKey(keys.bankE()),
|
||||
},
|
||||
},
|
||||
SecurityMedium: '0000',
|
||||
},
|
||||
...transactionId && {
|
||||
TransactionID: transactionId,
|
||||
},
|
||||
SecurityMedium: '0000',
|
||||
},
|
||||
mutable: {
|
||||
TransactionPhase: 'Initialisation',
|
||||
TransactionPhase: segmentNumber ? 'Transfer' : 'Initialisation',
|
||||
...segmentNumber && {
|
||||
SegmentNumber: {
|
||||
'@': { lastSegment: false },
|
||||
'#': segmentNumber,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
12
package-lock.json
generated
12
package-lock.json
generated
@ -1967,9 +1967,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"hosted-git-info": {
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz",
|
||||
"integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==",
|
||||
"version": "2.8.9",
|
||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
|
||||
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
|
||||
"dev": true
|
||||
},
|
||||
"html-escaper": {
|
||||
@ -2536,9 +2536,9 @@
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.19",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
|
||||
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.flattendeep": {
|
||||
|
Loading…
Reference in New Issue
Block a user