mirror of
https://github.com/node-ebics/node-ebics-client.git
synced 2024-11-24 07:02:08 +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) {
|
async download(order) {
|
||||||
if (this.tracesStorage)
|
if (this.tracesStorage)
|
||||||
this.tracesStorage.new().ofType('ORDER.DOWNLOAD');
|
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.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 (res.isSegmented() && res.isLastSegment()) {
|
||||||
if (this.tracesStorage)
|
if (this.tracesStorage)
|
||||||
this.tracesStorage.connect().ofType('RECEIPT.ORDER.DOWNLOAD');
|
this.tracesStorage.connect().ofType('RECEIPT.ORDER.DOWNLOAD');
|
||||||
|
|
||||||
|
order.segmentNumber = null; // Clear segment number for receipt request
|
||||||
await this.ebicsRequest(order);
|
await this.ebicsRequest(order);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,7 +183,7 @@ module.exports = class Client {
|
|||||||
const returnedBusinessCode = res.businessCode();
|
const returnedBusinessCode = res.businessCode();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
orderData: res.orderData(),
|
orderData: orderData.length === 1 ? orderData[0] : orderData, // backward compatibility
|
||||||
orderId: res.orderId(),
|
orderId: res.orderId(),
|
||||||
|
|
||||||
technicalCode: returnedTechnicalCode,
|
technicalCode: returnedTechnicalCode,
|
||||||
|
@ -22,6 +22,7 @@ const lastChild = (node) => {
|
|||||||
module.exports = (xml, keys) => ({
|
module.exports = (xml, keys) => ({
|
||||||
keys,
|
keys,
|
||||||
doc: new DOMParser().parseFromString(xml, 'text/xml'),
|
doc: new DOMParser().parseFromString(xml, 'text/xml'),
|
||||||
|
obtainedTransactionKey: null,
|
||||||
|
|
||||||
isSegmented() {
|
isSegmented() {
|
||||||
const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' });
|
const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' });
|
||||||
@ -30,6 +31,13 @@ module.exports = (xml, keys) => ({
|
|||||||
return !!node.length;
|
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() {
|
isLastSegment() {
|
||||||
const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' });
|
const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' });
|
||||||
const node = select("//xmlns:header/xmlns:mutable/*[@lastSegment='true']", this.doc);
|
const node = select("//xmlns:header/xmlns:mutable/*[@lastSegment='true']", this.doc);
|
||||||
@ -40,7 +48,7 @@ module.exports = (xml, keys) => ({
|
|||||||
orderData() {
|
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 {};
|
if (!orderDataNode.length) return null;
|
||||||
|
|
||||||
const orderData = orderDataNode[0].textContent;
|
const orderData = orderDataNode[0].textContent;
|
||||||
const decipher = crypto.createDecipheriv('aes-128-cbc', this.transactionKey(), DEFAULT_IV).setAutoPadding(false);
|
const decipher = crypto.createDecipheriv('aes-128-cbc', this.transactionKey(), DEFAULT_IV).setAutoPadding(false);
|
||||||
@ -50,6 +58,7 @@ module.exports = (xml, keys) => ({
|
|||||||
},
|
},
|
||||||
|
|
||||||
transactionKey() {
|
transactionKey() {
|
||||||
|
if (this.obtainedTransactionKey) return this.obtainedTransactionKey;
|
||||||
const keyNodeText = this.doc.getElementsByTagNameNS('urn:org:ebics:H004', 'TransactionKey')[0].textContent;
|
const keyNodeText = this.doc.getElementsByTagNameNS('urn:org:ebics:H004', 'TransactionKey')[0].textContent;
|
||||||
return Crypto.privateDecrypt(this.keys.e(), Buffer.from(keyNodeText, 'base64'));
|
return Crypto.privateDecrypt(this.keys.e(), Buffer.from(keyNodeText, 'base64'));
|
||||||
},
|
},
|
||||||
|
@ -13,7 +13,7 @@ module.exports = {
|
|||||||
userId: client.userId,
|
userId: client.userId,
|
||||||
hostId: client.hostId,
|
hostId: client.hostId,
|
||||||
};
|
};
|
||||||
const { orderDetails, transactionId } = order;
|
const { orderDetails, transactionId, segmentNumber } = order;
|
||||||
const {
|
const {
|
||||||
rootName, xmlOptions, xmlSchema, receipt, transfer, productString,
|
rootName, xmlOptions, xmlSchema, receipt, transfer, productString,
|
||||||
} = genericSerializer(client.hostId, transactionId);
|
} = genericSerializer(client.hostId, transactionId);
|
||||||
@ -25,35 +25,46 @@ module.exports = {
|
|||||||
this.receipt = receipt;
|
this.receipt = receipt;
|
||||||
this.transfer = transfer;
|
this.transfer = transfer;
|
||||||
|
|
||||||
if (transactionId) return this.receipt();
|
if (!segmentNumber && transactionId) return this.receipt();
|
||||||
|
|
||||||
this.xmlSchema.header = {
|
this.xmlSchema.header = {
|
||||||
'@': { authenticate: true },
|
'@': { authenticate: true },
|
||||||
static: {
|
static: {
|
||||||
HostID: ebicsAccount.hostId,
|
HostID: ebicsAccount.hostId,
|
||||||
Nonce: Crypto.nonce(),
|
...!transactionId && {
|
||||||
Timestamp: Crypto.timestamp(),
|
Nonce: Crypto.nonce(),
|
||||||
PartnerID: ebicsAccount.partnerId,
|
Timestamp: Crypto.timestamp(),
|
||||||
UserID: ebicsAccount.userId,
|
PartnerID: ebicsAccount.partnerId,
|
||||||
Product: {
|
UserID: ebicsAccount.userId,
|
||||||
'@': { Language: 'en' },
|
Product: {
|
||||||
'#': productString,
|
'@': { Language: 'en' },
|
||||||
},
|
'#': productString,
|
||||||
OrderDetails: orderDetails,
|
|
||||||
BankPubKeyDigests: {
|
|
||||||
Authentication: {
|
|
||||||
'@': { Version: 'X002', Algorithm: 'http://www.w3.org/2001/04/xmlenc#sha256' },
|
|
||||||
'#': Crypto.digestPublicKey(keys.bankX()),
|
|
||||||
},
|
},
|
||||||
Encryption: {
|
OrderDetails: orderDetails,
|
||||||
'@': { Version: 'E002', Algorithm: 'http://www.w3.org/2001/04/xmlenc#sha256' },
|
BankPubKeyDigests: {
|
||||||
'#': Crypto.digestPublicKey(keys.bankE()),
|
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: {
|
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
|
"dev": true
|
||||||
},
|
},
|
||||||
"hosted-git-info": {
|
"hosted-git-info": {
|
||||||
"version": "2.8.5",
|
"version": "2.8.9",
|
||||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
|
||||||
"integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==",
|
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"html-escaper": {
|
"html-escaper": {
|
||||||
@ -2536,9 +2536,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.19",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"lodash.flattendeep": {
|
"lodash.flattendeep": {
|
||||||
|
Loading…
Reference in New Issue
Block a user