mirror of
https://github.com/node-ebics/node-ebics-client.git
synced 2024-11-25 07:32:06 +00:00
code optimization
This commit is contained in:
parent
d5d80ee1b8
commit
187636019c
12
index.js
12
index.js
@ -1,5 +1,15 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Client = require('./lib/Client');
|
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');
|
||||||
|
|
||||||
module.exports = Client;
|
module.exports = {
|
||||||
|
Client,
|
||||||
|
OrderBuilder,
|
||||||
|
ISO20022Builder,
|
||||||
|
keysManager,
|
||||||
|
fsKeysStorage,
|
||||||
|
};
|
||||||
|
@ -2,11 +2,12 @@
|
|||||||
|
|
||||||
const $request = require('request');
|
const $request = require('request');
|
||||||
|
|
||||||
const XMLSign = require('./middleware/XMLSign');
|
const signer = require('./middleware/signer');
|
||||||
const ParseResponse = require('./middleware/ParseResponse');
|
const serializer = require('./middleware/serializer');
|
||||||
|
const response = require('./middleware/response');
|
||||||
|
|
||||||
module.exports = class Client {
|
module.exports = class Client {
|
||||||
constructor({ url }) {
|
constructor(url) {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,25 +53,31 @@ module.exports = class Client {
|
|||||||
return [transactionId, orderId];
|
return [transactionId, orderId];
|
||||||
}
|
}
|
||||||
|
|
||||||
async downloadAndUnzip(order) { // eslint-disable-line
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ebicsRequest(order) {
|
ebicsRequest(order) {
|
||||||
return new Promise((resolve, reject) => {
|
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();
|
||||||
$request.post({
|
$request.post({
|
||||||
url: this.url,
|
url: this.url,
|
||||||
body: XMLSign.sign(order),
|
body: signer.version(version).sign(serializer.use(order).toXML(), keys), // s, // new (signer.version(version))(serializer.use(order).toXML(), keys).digest().sign().toXML(),
|
||||||
headers: { 'content-type': 'text/xml;charset=UTF-8' },
|
headers: { 'content-type': 'text/xml;charset=UTF-8' },
|
||||||
}, (err, res, data) => (err ? reject(err) : resolve(ParseResponse.parse(data, order.keys, order.version))));
|
}, (err, res, data) => (err ? reject(err) : resolve(response.version(version)(data, keys))));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
request(order) {
|
ini(order) {
|
||||||
if (order.type.toLowerCase() === 'ini') return this.initialization(order);
|
return this.initialization(order);
|
||||||
if (order.type.toLowerCase() === 'payment') return this.upload(order);
|
}
|
||||||
if (order.type.toLowerCase() === 'status') return this.download(order);
|
|
||||||
|
|
||||||
throw Error('Invalid order type');
|
payment(order) {
|
||||||
|
return this.upload(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
statement(order) {
|
||||||
|
return this.download(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
status(order) {
|
||||||
|
return this.download(order);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
101
lib/ISO20022OrderBuilder.js
Normal file
101
lib/ISO20022OrderBuilder.js
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const OrderBuilder = require('./OrderBuilder');
|
||||||
|
|
||||||
|
module.exports = class ISO20022OrderBuilder extends OrderBuilder {
|
||||||
|
get document() { return this._document; }
|
||||||
|
get ebicsData() { return this._ebicsData; }
|
||||||
|
|
||||||
|
use(dataToUse) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(dataToUse, 'ebicsData')) this._ebicsData = dataToUse.ebicsData;
|
||||||
|
if (Object.prototype.hasOwnProperty.call(dataToUse, 'document')) this._document = dataToUse.document;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
static h004() {
|
||||||
|
const builder = new ISO20022OrderBuilder();
|
||||||
|
|
||||||
|
builder._version = 'H004';
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
INI() {
|
||||||
|
return this.details({
|
||||||
|
ebicsData: this.ebicsData,
|
||||||
|
orderDetails: { OrderType: 'INI', OrderAttribute: 'DZNNN' },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
HIA() {
|
||||||
|
return this.details({
|
||||||
|
ebicsData: this.ebicsData,
|
||||||
|
orderDetails: { OrderType: 'HIA', OrderAttribute: 'DZNNN' },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
HPB() {
|
||||||
|
return this.details({
|
||||||
|
ebicsData: this.ebicsData,
|
||||||
|
orderDetails: { OrderType: 'HPB', OrderAttribute: 'DZHNN' },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
HKD() {
|
||||||
|
return this.details({
|
||||||
|
ebicsData: this.ebicsData,
|
||||||
|
orderDetails: { OrderType: 'HKD', OrderAttribute: 'DZHNN', StandardOrderParams: {} },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
HPD() {
|
||||||
|
return this.details({
|
||||||
|
ebicsData: this.ebicsData,
|
||||||
|
orderDetails: { OrderType: 'HPD', OrderAttribute: 'DZHNN', StandardOrderParams: {} },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
HTD() {
|
||||||
|
return this.details({
|
||||||
|
ebicsData: this.ebicsData,
|
||||||
|
orderDetails: { OrderType: 'HTD', OrderAttribute: 'DZHNN', StandardOrderParams: {} },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
HAA() {
|
||||||
|
return this.details({
|
||||||
|
ebicsData: this.ebicsData,
|
||||||
|
orderDetails: { OrderType: 'HAA', OrderAttribute: 'DZHNN', StandardOrderParams: {} },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
HAC(start = null, end = null) {
|
||||||
|
const params = start && end
|
||||||
|
? { DateRange: { Start: start, End: end } }
|
||||||
|
: {};
|
||||||
|
|
||||||
|
return this.details({
|
||||||
|
ebicsData: this.ebicsData,
|
||||||
|
orderDetails: { OrderType: 'HAC', OrderAttribute: 'DZHNN', StandardOrderParams: params },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
PTK(start = null, end = null) {
|
||||||
|
const params = start && end
|
||||||
|
? { DateRange: { Start: start, End: end } }
|
||||||
|
: {};
|
||||||
|
|
||||||
|
return this.details({
|
||||||
|
ebicsData: this.ebicsData,
|
||||||
|
orderDetails: { OrderType: 'PTK', OrderAttribute: 'DZHNN', StandardOrderParams: params },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Z52() {
|
||||||
|
return this.details({
|
||||||
|
ebicsData: this.ebicsData,
|
||||||
|
orderDetails: { OrderType: 'Z52', OrderAttribute: 'DZHNN', StandardOrderParams: {} },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -2,10 +2,11 @@
|
|||||||
|
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
|
|
||||||
// const orderTypes = ['ini', 'download', 'upload', 'zip'];
|
const constants = require('./consts');
|
||||||
|
|
||||||
module.exports = class OrderBuilder {
|
module.exports = class OrderBuilder {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
this._productString = constants.productString;
|
||||||
this._transactionKey = crypto.randomBytes(16);
|
this._transactionKey = crypto.randomBytes(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,24 +17,6 @@ module.exports = class OrderBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
payment() {
|
|
||||||
this._type = 'payment';
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
status() {
|
|
||||||
this._type = 'status';
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
ini() {
|
|
||||||
this._type = 'ini';
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
static h004() {
|
static h004() {
|
||||||
const builder = new OrderBuilder();
|
const builder = new OrderBuilder();
|
||||||
|
|
||||||
@ -45,7 +28,6 @@ module.exports = class OrderBuilder {
|
|||||||
/**
|
/**
|
||||||
* Getters
|
* Getters
|
||||||
*/
|
*/
|
||||||
get type() { return this._type; }
|
|
||||||
get data() { return this._data; }
|
get data() { return this._data; }
|
||||||
get orderDetails() { return this._data.orderDetails; }
|
get orderDetails() { return this._data.orderDetails; }
|
||||||
get transactionId() { return this._data.transactionId; }
|
get transactionId() { return this._data.transactionId; }
|
||||||
@ -57,6 +39,8 @@ module.exports = class OrderBuilder {
|
|||||||
get userId() { return this._data.ebicsData.userId; }
|
get userId() { return this._data.ebicsData.userId; }
|
||||||
get keys() { return this._data.ebicsData.keysManager.keys(); }
|
get keys() { return this._data.ebicsData.keysManager.keys(); }
|
||||||
get version() { return this._version; }
|
get version() { return this._version; }
|
||||||
|
get productString() { return this._productString; }
|
||||||
|
get orderType() { return this.orderDetails.OrderType; }
|
||||||
|
|
||||||
set transactionId(tid) {
|
set transactionId(tid) {
|
||||||
this._data.transactionId = tid === '' ? null : tid;
|
this._data.transactionId = tid === '' ? null : tid;
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
/* const extractKeys = (keysObject, encryptAlgorithm, passphrase) => Object.entries(keysObject).reduce((keys, [key, data]) => {
|
|
||||||
keys[key] = decrypt(data, encryptAlgorithm, passphrase);
|
|
||||||
return keys;
|
|
||||||
}, {}); */
|
|
||||||
|
|
||||||
module.exports = class FsKeyStorage {
|
|
||||||
/**
|
|
||||||
* @param {String} path - destingiton file to save the keys
|
|
||||||
*/
|
|
||||||
constructor({ path }) {
|
|
||||||
if (!path)
|
|
||||||
throw new Error('Invalid path provided');
|
|
||||||
|
|
||||||
this._path = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
get path() {
|
|
||||||
return this._path;
|
|
||||||
}
|
|
||||||
|
|
||||||
read() {
|
|
||||||
return fs.readFileSync(this._path, { encoding: 'utf8' });
|
|
||||||
// return extractKeys(JSON.parse(fs.readFileSync(this._path, { encoding: 'utf8' })), this.algorithm, this.passphrase);
|
|
||||||
}
|
|
||||||
|
|
||||||
save(data) {
|
|
||||||
fs.writeFileSync(this._path, data, { encoding: 'utf8' });
|
|
||||||
// fs.writeFileSync(this._path, encrypt(JSON.stringify(data), this.algorithm, this.passphrase), { encoding: 'utf8' });
|
|
||||||
}
|
|
||||||
|
|
||||||
hasData() {
|
|
||||||
if (fs.existsSync(this._path))
|
|
||||||
return this.read() !== '';
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
@ -19,76 +19,50 @@ const decrypt = (data, algorithm, passphrase) => {
|
|||||||
return decrypted;
|
return decrypted;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = class KeysManager {
|
module.exports = (keysStorage, passphrase, algorithm = 'aes-256-cbc') => {
|
||||||
constructor(keysStorage, passphrase, algorithm = 'aes-256-cbc', createIfNone = true) {
|
const storage = keysStorage;
|
||||||
this._storage = keysStorage;
|
const pass = passphrase;
|
||||||
this._passphrase = passphrase;
|
const algo = algorithm;
|
||||||
this._algorithm = algorithm;
|
// const createIfNone = createIfNone;
|
||||||
|
|
||||||
if (createIfNone && !this._storage.hasData())
|
return {
|
||||||
this.generate();
|
generate(save = true) {
|
||||||
}
|
const keys = Keys.generate();
|
||||||
|
|
||||||
/**
|
if (save) {
|
||||||
* Generates the keys to work with. Then either
|
this.write(keys);
|
||||||
* saves them to the storage or returnes the keys generated
|
|
||||||
*
|
|
||||||
* @param {Boolean} save
|
|
||||||
* @default true
|
|
||||||
*
|
|
||||||
* @returns void | Keys object
|
|
||||||
*/
|
|
||||||
generate(save = true) {
|
|
||||||
const keys = Keys.generate();
|
|
||||||
|
|
||||||
if (save) this.write(keys);
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
return keys;
|
return keys;
|
||||||
}
|
},
|
||||||
|
|
||||||
/**
|
write(keysObject) {
|
||||||
* Writes the keys to the storage
|
keysObject = keysObject.keys;
|
||||||
*
|
|
||||||
* @param {Keys} keysObject
|
|
||||||
*
|
|
||||||
* @returns void
|
|
||||||
*/
|
|
||||||
write(keysObject) {
|
|
||||||
keysObject = keysObject.keys;
|
|
||||||
|
|
||||||
Object.keys(keysObject).map((key) => {
|
Object.keys(keysObject).map((key) => {
|
||||||
keysObject[key] = keysObject[key] === null ? null : keysObject[key].toPem();
|
keysObject[key] = keysObject[key] === null ? null : keysObject[key].toPem();
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
});
|
});
|
||||||
|
|
||||||
this._storage.save(encrypt(JSON.stringify(keysObject), this._algorithm, this._passphrase));
|
storage.save(encrypt(JSON.stringify(keysObject), algo, pass));
|
||||||
}
|
|
||||||
|
|
||||||
setBankKeys(bankKeys) {
|
return this;
|
||||||
const keys = this.keys();
|
},
|
||||||
|
|
||||||
keys.setBankKeys(bankKeys);
|
setBankKeys(bankKeys) {
|
||||||
this.write(keys);
|
const keys = this.keys();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
keys.setBankKeys(bankKeys);
|
||||||
* Gets the keys
|
this.write(keys);
|
||||||
*
|
},
|
||||||
* @returns Keys object
|
|
||||||
*/
|
|
||||||
keys() {
|
|
||||||
return this._read();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
keys() {
|
||||||
* Reads the keys from the storage
|
const keysString = storage.read();
|
||||||
*
|
|
||||||
* @returns Keys object
|
|
||||||
*/
|
|
||||||
_read() {
|
|
||||||
const keysString = this._storage.read();
|
|
||||||
|
|
||||||
return new Keys(JSON.parse(decrypt(keysString, this._algorithm, this._passphrase)));
|
return new Keys(JSON.parse(decrypt(keysString, algo, pass)));
|
||||||
}
|
},
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
26
lib/keymanagers/fsKeysStorage.js
Normal file
26
lib/keymanagers/fsKeysStorage.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
module.exports = (pathToFile) => {
|
||||||
|
const path = pathToFile;
|
||||||
|
|
||||||
|
return {
|
||||||
|
read() {
|
||||||
|
return fs.readFileSync(path, { encoding: 'utf8' });
|
||||||
|
},
|
||||||
|
|
||||||
|
save(data) {
|
||||||
|
fs.writeFileSync(path, data, { encoding: 'utf8' });
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
hasData() {
|
||||||
|
if (fs.existsSync(path))
|
||||||
|
return this.read() !== '';
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
@ -1,11 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const H004Response = require('../versions/H004/Response');
|
|
||||||
|
|
||||||
module.exports = class ParseResponse {
|
|
||||||
static parse(data, keys, version) {
|
|
||||||
if (version.toUpperCase() === 'H004') return new H004Response(data, keys);
|
|
||||||
|
|
||||||
throw Error('Unknow EBICS response version');
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,15 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const H004Signer = require('../versions/H004/Signer');
|
|
||||||
|
|
||||||
const H004Serializer = require('../versions/H004/OrderSerializer');
|
|
||||||
|
|
||||||
module.exports = class XMLSign {
|
|
||||||
static sign(order) {
|
|
||||||
const { keys } = order;
|
|
||||||
|
|
||||||
if (order.version.toUpperCase() === 'H004') return new H004Signer(H004Serializer.serialize(order).toXML(), keys).digest().sign().toXML();
|
|
||||||
|
|
||||||
throw Error('Error from XMLSign class: Invalid version number');
|
|
||||||
}
|
|
||||||
};
|
|
11
lib/middleware/response.js
Normal file
11
lib/middleware/response.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const H004Response = require('../orders/H004/response');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
version(v) {
|
||||||
|
if (v.toUpperCase() === 'H004') return H004Response;
|
||||||
|
|
||||||
|
throw Error('Error from middleware/response.js: Invalid version number');
|
||||||
|
},
|
||||||
|
};
|
13
lib/middleware/serializer.js
Normal file
13
lib/middleware/serializer.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const H004Serializer = require('../orders/H004/serializer');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
use(order) {
|
||||||
|
const { version } = order;
|
||||||
|
|
||||||
|
if (version.toUpperCase() === 'H004') return H004Serializer.use(order);
|
||||||
|
|
||||||
|
throw Error('Error middleware/serializer.js: Invalid version number');
|
||||||
|
},
|
||||||
|
};
|
11
lib/middleware/signer.js
Normal file
11
lib/middleware/signer.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const H004Signer = require('../orders/H004/signer');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
version(v) {
|
||||||
|
if (v.toUpperCase() === 'H004') return H004Signer;
|
||||||
|
|
||||||
|
throw Error('Error from middleware/signer.js: Invalid version number');
|
||||||
|
},
|
||||||
|
};
|
@ -19,25 +19,23 @@ const lastChild = (node) => {
|
|||||||
return y;
|
return y;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = class Response {
|
module.exports = (xml, keys) => ({
|
||||||
constructor(data, keys) {
|
keys,
|
||||||
this.keys = keys;
|
doc: new DOMParser().parseFromString(xml, 'text/xml'),
|
||||||
this.doc = new DOMParser().parseFromString(data, 'text/xml');
|
|
||||||
}
|
|
||||||
|
|
||||||
isSegmented() {
|
isSegmented() {
|
||||||
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/xmlns:SegmentNumber', this.doc);
|
const node = select('//xmlns:header/xmlns:mutable/xmlns:SegmentNumber', this.doc);
|
||||||
|
|
||||||
return !!node.length;
|
return !!node.length;
|
||||||
}
|
},
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
return !!node.length;
|
return !!node.length;
|
||||||
}
|
},
|
||||||
|
|
||||||
orderData() {
|
orderData() {
|
||||||
const orderDataNode = this.doc.getElementsByTagNameNS('urn:org:ebics:H004', 'OrderData');
|
const orderDataNode = this.doc.getElementsByTagNameNS('urn:org:ebics:H004', 'OrderData');
|
||||||
@ -49,41 +47,41 @@ module.exports = class Response {
|
|||||||
const data = Buffer.from(decipher.update(orderData, 'base64', 'binary') + decipher.final('binary'), 'binary');
|
const data = Buffer.from(decipher.update(orderData, 'base64', 'binary') + decipher.final('binary'), 'binary');
|
||||||
|
|
||||||
return zlib.inflateSync(data).toString();
|
return zlib.inflateSync(data).toString();
|
||||||
}
|
},
|
||||||
|
|
||||||
transactionKey() {
|
transactionKey() {
|
||||||
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'));
|
||||||
}
|
},
|
||||||
|
|
||||||
transactionId() {
|
transactionId() {
|
||||||
const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' });
|
const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' });
|
||||||
const node = select('//xmlns:header/xmlns:static/xmlns:TransactionID', this.doc);
|
const node = select('//xmlns:header/xmlns:static/xmlns:TransactionID', this.doc);
|
||||||
|
|
||||||
return node.length ? node[0].textContent : '';
|
return node.length ? node[0].textContent : '';
|
||||||
}
|
},
|
||||||
|
|
||||||
orderId() {
|
orderId() {
|
||||||
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/xmlns:OrderID', this.doc);
|
const node = select('//xmlns:header/xmlns:mutable/xmlns:OrderID', this.doc);
|
||||||
|
|
||||||
return node.length ? node[0].textContent : '';
|
return node.length ? node[0].textContent : '';
|
||||||
}
|
},
|
||||||
|
|
||||||
returnCode() {
|
returnCode() {
|
||||||
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/xmlns:ReturnCode', this.doc);
|
const node = select('//xmlns:header/xmlns:mutable/xmlns:ReturnCode', this.doc);
|
||||||
|
|
||||||
return node.length ? node[0].textContent : '';
|
return node.length ? node[0].textContent : '';
|
||||||
}
|
},
|
||||||
|
|
||||||
reportText() {
|
reportText() {
|
||||||
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/xmlns:ReportText', this.doc);
|
const node = select('//xmlns:header/xmlns:mutable/xmlns:ReportText', this.doc);
|
||||||
|
|
||||||
return node.length ? node[0].textContent : '';
|
return node.length ? node[0].textContent : '';
|
||||||
}
|
},
|
||||||
|
|
||||||
bankKeys() {
|
bankKeys() {
|
||||||
const orderData = this.orderData();
|
const orderData = this.orderData();
|
||||||
@ -108,9 +106,9 @@ module.exports = class Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return bankKeys;
|
return bankKeys;
|
||||||
}
|
},
|
||||||
|
|
||||||
toXML() {
|
toXML() {
|
||||||
return new XMLSerializer().serializeToString(this.doc);
|
return new XMLSerializer().serializeToString(this.doc);
|
||||||
}
|
},
|
||||||
};
|
});
|
19
lib/orders/H004/serializer.js
Normal file
19
lib/orders/H004/serializer.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const orders = require('../orders');
|
||||||
|
|
||||||
|
const iniSerializer = require('./serializers/ini');
|
||||||
|
const downloadSerializer = require('./serializers/download');
|
||||||
|
const uploadSerializer = require('./serializers/upload');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
use(order) {
|
||||||
|
const { version, orderType } = order;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
throw Error('Error from orders/orders.js: Wrong order version/type.');
|
||||||
|
},
|
||||||
|
};
|
62
lib/orders/H004/serializers/download.js
Normal file
62
lib/orders/H004/serializers/download.js
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const js2xmlparser = require('js2xmlparser');
|
||||||
|
|
||||||
|
const Crypto = require('../../../crypto/Crypto');
|
||||||
|
|
||||||
|
const genericSerializer = require('./generic');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
use(orderBuilder) {
|
||||||
|
const {
|
||||||
|
ebicsData, orderDetails, keys, productString, transactionId,
|
||||||
|
} = orderBuilder;
|
||||||
|
const {
|
||||||
|
rootName, xmlOptions, xmlSchema, receipt, transfer,
|
||||||
|
} = genericSerializer(orderBuilder);
|
||||||
|
|
||||||
|
this.rootName = rootName;
|
||||||
|
this.xmlOptions = xmlOptions;
|
||||||
|
this.xmlSchema = xmlSchema;
|
||||||
|
this.receipt = receipt;
|
||||||
|
this.transfer = transfer;
|
||||||
|
|
||||||
|
if (transactionId) return this.receipt();
|
||||||
|
|
||||||
|
this.xmlSchema.header = {
|
||||||
|
'@': { authenticate: true },
|
||||||
|
static: {
|
||||||
|
HostID: ebicsData.hostId,
|
||||||
|
Nonce: Crypto.nonce(),
|
||||||
|
Timestamp: Crypto.timestamp(),
|
||||||
|
PartnerID: ebicsData.partnerId,
|
||||||
|
UserID: ebicsData.userId,
|
||||||
|
Product: {
|
||||||
|
'@': { Language: 'en' },
|
||||||
|
'#': productString,
|
||||||
|
},
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
mutable: {
|
||||||
|
TransactionPhase: 'Initialisation',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
toXML() {
|
||||||
|
return js2xmlparser.parse(this.rootName, this.xmlSchema, this.xmlOptions);
|
||||||
|
},
|
||||||
|
};
|
133
lib/orders/H004/serializers/generic.js
Normal file
133
lib/orders/H004/serializers/generic.js
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const rootName = 'ebicsRequest';
|
||||||
|
const rootAttributes = {
|
||||||
|
'xmlns:ds': 'http://www.w3.org/2000/09/xmldsig#',
|
||||||
|
xmlns: 'urn:org:ebics:H004',
|
||||||
|
Version: 'H004',
|
||||||
|
Revision: '1',
|
||||||
|
};
|
||||||
|
const header = {};
|
||||||
|
const authSignature = ({
|
||||||
|
'ds:SignedInfo': {
|
||||||
|
'ds:CanonicalizationMethod': {
|
||||||
|
'@': {
|
||||||
|
Algorithm:
|
||||||
|
'http://www.w3.org/TR/2001/REC-xml-c14n-20010315',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'ds:SignatureMethod': {
|
||||||
|
'@': {
|
||||||
|
Algorithm:
|
||||||
|
'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'ds:Reference': {
|
||||||
|
'@': { URI: "#xpointer(//*[@authenticate='true'])" },
|
||||||
|
'ds:Transforms': {
|
||||||
|
'ds:Transform': {
|
||||||
|
'@': {
|
||||||
|
Algorithm:
|
||||||
|
'http://www.w3.org/TR/2001/REC-xml-c14n-20010315',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'ds:DigestMethod': {
|
||||||
|
'@': {
|
||||||
|
Algorithm:
|
||||||
|
'http://www.w3.org/2001/04/xmlenc#sha256',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'ds:DigestValue': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'ds:SignatureValue': {},
|
||||||
|
});
|
||||||
|
const body = {};
|
||||||
|
|
||||||
|
const xmlOptions = {
|
||||||
|
declaration: {
|
||||||
|
include: true,
|
||||||
|
encoding: 'utf-8',
|
||||||
|
},
|
||||||
|
format: {
|
||||||
|
doubleQuotes: true,
|
||||||
|
indent: '',
|
||||||
|
newline: '',
|
||||||
|
pretty: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = (orderBuilder) => {
|
||||||
|
const { ebicsData, transactionId } = orderBuilder;
|
||||||
|
|
||||||
|
return {
|
||||||
|
rootName,
|
||||||
|
xmlOptions,
|
||||||
|
xmlSchema: {
|
||||||
|
'@': rootAttributes,
|
||||||
|
header,
|
||||||
|
AuthSignature: authSignature,
|
||||||
|
body,
|
||||||
|
},
|
||||||
|
|
||||||
|
receipt() {
|
||||||
|
this.xmlSchema = {
|
||||||
|
'@': rootAttributes,
|
||||||
|
|
||||||
|
header: {
|
||||||
|
'@': { authenticate: true },
|
||||||
|
static: {
|
||||||
|
HostID: ebicsData.hostId,
|
||||||
|
TransactionID: transactionId,
|
||||||
|
},
|
||||||
|
mutable: {
|
||||||
|
TransactionPhase: 'Receipt',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
AuthSignature: authSignature,
|
||||||
|
|
||||||
|
body: {
|
||||||
|
TransferReceipt: {
|
||||||
|
'@': { authenticate: true },
|
||||||
|
ReceiptCode: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
144
lib/orders/H004/serializers/ini.js
Normal file
144
lib/orders/H004/serializers/ini.js
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const zlib = require('zlib');
|
||||||
|
|
||||||
|
const js2xmlparser = require('js2xmlparser');
|
||||||
|
|
||||||
|
const Crypto = require('../../../crypto/Crypto');
|
||||||
|
|
||||||
|
const genericSerializer = require('./generic');
|
||||||
|
|
||||||
|
const keySignature = (ebicsData, key, xmlOptions) => {
|
||||||
|
const xmlOrderData = {
|
||||||
|
'@': {
|
||||||
|
'xmlns:ds': 'http://www.w3.org/2000/09/xmldsig#',
|
||||||
|
xmlns: 'http://www.ebics.org/S001',
|
||||||
|
},
|
||||||
|
SignaturePubKeyInfo: {
|
||||||
|
PubKeyValue: {
|
||||||
|
'ds:RSAKeyValue': {
|
||||||
|
'ds:Modulus': key.n().toString('base64'),
|
||||||
|
'ds:Exponent': key.e().toString('base64'),
|
||||||
|
},
|
||||||
|
TimeStamp: Crypto.timestamp(),
|
||||||
|
},
|
||||||
|
SignatureVersion: 'A006',
|
||||||
|
},
|
||||||
|
PartnerID: ebicsData.partnerId,
|
||||||
|
UserID: ebicsData.userId,
|
||||||
|
};
|
||||||
|
|
||||||
|
return js2xmlparser.parse('SignaturePubKeyOrderData', xmlOrderData, xmlOptions);
|
||||||
|
};
|
||||||
|
const orderData = (ebicsData, keys, xmlOptions) => {
|
||||||
|
const xmlOrderData = {
|
||||||
|
'@': {
|
||||||
|
'xmlns:ds': 'http://www.w3.org/2000/09/xmldsig#',
|
||||||
|
xmlns: 'urn:org:ebics:H004',
|
||||||
|
},
|
||||||
|
AuthenticationPubKeyInfo: {
|
||||||
|
PubKeyValue: {
|
||||||
|
'ds:RSAKeyValue': {
|
||||||
|
'ds:Modulus': keys.x().n().toString('base64'),
|
||||||
|
'ds:Exponent': keys.x().e().toString('base64'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
AuthenticationVersion: 'X002',
|
||||||
|
},
|
||||||
|
EncryptionPubKeyInfo: {
|
||||||
|
PubKeyValue: {
|
||||||
|
'ds:RSAKeyValue': {
|
||||||
|
'ds:Modulus': keys.e().n().toString('base64'),
|
||||||
|
'ds:Exponent': keys.e().e().toString('base64'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
EncryptionVersion: 'E002',
|
||||||
|
},
|
||||||
|
PartnerID: ebicsData.partnerId,
|
||||||
|
UserID: ebicsData.userId,
|
||||||
|
};
|
||||||
|
|
||||||
|
return js2xmlparser.parse('HIARequestOrderData', xmlOrderData, xmlOptions);
|
||||||
|
};
|
||||||
|
const commonHeader = (ebicsData, orderDetails, productString) => ({
|
||||||
|
'@': { authenticate: true },
|
||||||
|
static: {
|
||||||
|
HostID: ebicsData.hostId,
|
||||||
|
Nonce: Crypto.nonce(),
|
||||||
|
Timestamp: Crypto.timestamp(),
|
||||||
|
PartnerID: ebicsData.partnerId,
|
||||||
|
UserID: ebicsData.userId,
|
||||||
|
Product: {
|
||||||
|
'@': { Language: 'en' },
|
||||||
|
'#': productString,
|
||||||
|
},
|
||||||
|
OrderDetails: orderDetails,
|
||||||
|
SecurityMedium: '0000',
|
||||||
|
},
|
||||||
|
mutable: {},
|
||||||
|
});
|
||||||
|
const process = {
|
||||||
|
INI: {
|
||||||
|
rootName: 'ebicsUnsecuredRequest',
|
||||||
|
header: (ebicsData, orderDetails, productString) => {
|
||||||
|
const ch = commonHeader(ebicsData, orderDetails, productString);
|
||||||
|
|
||||||
|
delete ch.static.Nonce;
|
||||||
|
delete ch.static.Timestamp;
|
||||||
|
|
||||||
|
return ch;
|
||||||
|
},
|
||||||
|
body: (ebicsData, keys, xmlOptions) => ({
|
||||||
|
DataTransfer: {
|
||||||
|
OrderData: Buffer.from(zlib.deflateSync(keySignature(ebicsData, keys.a(), xmlOptions))).toString('base64'),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
HIA: {
|
||||||
|
rootName: 'ebicsUnsecuredRequest',
|
||||||
|
header: (ebicsData, orderDetails, productString) => {
|
||||||
|
const ch = commonHeader(ebicsData, orderDetails, productString);
|
||||||
|
|
||||||
|
delete ch.static.Nonce;
|
||||||
|
delete ch.static.Timestamp;
|
||||||
|
|
||||||
|
return ch;
|
||||||
|
},
|
||||||
|
body: (ebicsData, keys, xmlOptions) => ({
|
||||||
|
DataTransfer: {
|
||||||
|
OrderData: Buffer.from(zlib.deflateSync(orderData(ebicsData, keys, xmlOptions))).toString('base64'),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
HPB: {
|
||||||
|
rootName: 'ebicsNoPubKeyDigestsRequest',
|
||||||
|
header: (ebicsData, orderDetails, productString) => commonHeader(ebicsData, orderDetails, productString),
|
||||||
|
body: () => ({}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
use(orderBuilder) {
|
||||||
|
const { xmlOptions, xmlSchema } = genericSerializer(orderBuilder);
|
||||||
|
const {
|
||||||
|
ebicsData, orderDetails, keys, productString,
|
||||||
|
} = orderBuilder;
|
||||||
|
const orderType = orderDetails.OrderType.toUpperCase();
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (orderType !== 'HPB' && Object.prototype.hasOwnProperty.call(this.xmlSchema, 'AuthSignature'))
|
||||||
|
delete this.xmlSchema.AuthSignature;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
toXML() {
|
||||||
|
return js2xmlparser.parse(this.rootName, this.xmlSchema, this.xmlOptions);
|
||||||
|
},
|
||||||
|
};
|
88
lib/orders/H004/serializers/upload.js
Normal file
88
lib/orders/H004/serializers/upload.js
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const zlib = require('zlib');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
const js2xmlparser = require('js2xmlparser');
|
||||||
|
|
||||||
|
const Crypto = require('../../../crypto/Crypto');
|
||||||
|
|
||||||
|
const downloadSerializer = require('./download');
|
||||||
|
|
||||||
|
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 xmlObj = {
|
||||||
|
'@': {
|
||||||
|
xmlns: 'http://www.ebics.org/S001',
|
||||||
|
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||||
|
'xsi:schemaLocation': 'http://www.ebics.org/S001 http://www.ebics.org/S001/ebics_signature.xsd',
|
||||||
|
},
|
||||||
|
OrderSignatureData: {
|
||||||
|
SignatureVersion: 'A006',
|
||||||
|
SignatureValue: signatureValue(document, key),
|
||||||
|
PartnerID: ebicsData.partnerId,
|
||||||
|
UserID: ebicsData.userId,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return js2xmlparser.parse('UserSignatureData', xmlObj, xmlOptions);
|
||||||
|
};
|
||||||
|
const encryptedOrderSignature = (ebicsData, document, transactionKey, key, xmlOptions) => {
|
||||||
|
const dst = zlib.deflateSync(orderSignature(ebicsData, 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');
|
||||||
|
};
|
||||||
|
const encryptedOrderData = (document, transactionKey) => {
|
||||||
|
const dst = zlib.deflateSync(document.replace(/\n|\r/g, ''));
|
||||||
|
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');
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
use(orderBuilder) {
|
||||||
|
const {
|
||||||
|
ebicsData, keys, transactionId, transactionKey, document,
|
||||||
|
} = orderBuilder;
|
||||||
|
const {
|
||||||
|
rootName, xmlOptions, xmlSchema, transfer,
|
||||||
|
} = downloadSerializer.use(orderBuilder);
|
||||||
|
|
||||||
|
this.rootName = rootName;
|
||||||
|
this.xmlOptions = xmlOptions;
|
||||||
|
this.xmlSchema = xmlSchema;
|
||||||
|
this.transfer = transfer;
|
||||||
|
|
||||||
|
if (transactionId) return this.transfer(encryptedOrderData(document, transactionKey));
|
||||||
|
|
||||||
|
this.xmlSchema.header.static.NumSegments = 1;
|
||||||
|
|
||||||
|
this.xmlSchema.body = {
|
||||||
|
DataTransfer: {
|
||||||
|
DataEncryptionInfo: {
|
||||||
|
'@': { authenticate: true },
|
||||||
|
EncryptionPubKeyDigest: {
|
||||||
|
'@': { Version: 'E002', Algorithm: 'http://www.w3.org/2001/04/xmlenc#sha256' },
|
||||||
|
'#': Crypto.digestPublicKey(keys.bankE()),
|
||||||
|
},
|
||||||
|
TransactionKey: Crypto.publicEncrypt(keys.bankE(), transactionKey).toString('base64'),
|
||||||
|
},
|
||||||
|
SignatureData: {
|
||||||
|
'@': { authenticate: true },
|
||||||
|
'#': encryptedOrderSignature(ebicsData, document, transactionKey, keys.a(), this.xmlOptions),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
toXML() {
|
||||||
|
return js2xmlparser.parse(this.rootName, this.xmlSchema, this.xmlOptions);
|
||||||
|
},
|
||||||
|
};
|
50
lib/orders/H004/signer.js
Normal file
50
lib/orders/H004/signer.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// const crypto = require('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 digest = (doc) => {
|
||||||
|
// get the xml node, where the digested value is supposed to be
|
||||||
|
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('');
|
||||||
|
|
||||||
|
// 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#"');
|
||||||
|
|
||||||
|
if (nodeDigestValue)
|
||||||
|
nodeDigestValue.textContent = Crypto.digestWithHash(fixedContent).toString('base64').trim();
|
||||||
|
|
||||||
|
return doc;
|
||||||
|
};
|
||||||
|
|
||||||
|
const sign = (doc, key) => {
|
||||||
|
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#"');
|
||||||
|
|
||||||
|
nodeSignatureValue.textContent = Crypto.privateSign(key, contentToSign); // this.keys.x().key.sign(contentToSign, 'base64');
|
||||||
|
}
|
||||||
|
|
||||||
|
return doc;
|
||||||
|
};
|
||||||
|
|
||||||
|
const toXML = doc => new XMLSerializer().serializeToString(doc);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
sign(data, keys) {
|
||||||
|
const keyX = keys.x();
|
||||||
|
const doc = new DOMParser().parseFromString(data, 'text/xml');
|
||||||
|
|
||||||
|
return toXML(sign(digest(doc), keyX));
|
||||||
|
},
|
||||||
|
};
|
35
lib/orders/orders.js
Normal file
35
lib/orders/orders.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
'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());
|
||||||
|
},
|
||||||
|
};
|
@ -1,15 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const InitializationSerializer = require('./serializers/InitializationSerializer');
|
|
||||||
const StatusSerializer = require('./serializers/StatusSerializer');
|
|
||||||
const PaymentSerializer = require('./serializers/PaymentSerializer');
|
|
||||||
|
|
||||||
module.exports = class OrderSerializer {
|
|
||||||
static serialize(order) {
|
|
||||||
if (order.type === 'ini') return new InitializationSerializer(order);
|
|
||||||
if (order.type === 'payment') return new PaymentSerializer(order);
|
|
||||||
if (order.type === 'status') return new StatusSerializer(order);
|
|
||||||
|
|
||||||
throw Error('Incorect order type. Available types: ini, status, payment, statement');
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,67 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
// const crypto = require('crypto');
|
|
||||||
const Crypto = require('../../crypto/Crypto');
|
|
||||||
|
|
||||||
const { DOMParser, XMLSerializer } = require('xmldom');
|
|
||||||
const xpath = require('xpath');
|
|
||||||
const C14n = require('xml-crypto/lib/c14n-canonicalization').C14nCanonicalization;
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = class Signer {
|
|
||||||
/**
|
|
||||||
* Contructor.
|
|
||||||
*
|
|
||||||
* @param {Keys} keys
|
|
||||||
* @param {String} data
|
|
||||||
*/
|
|
||||||
constructor(data, keys) {
|
|
||||||
/**
|
|
||||||
* Keys to operate with
|
|
||||||
*
|
|
||||||
* @type {Keys}
|
|
||||||
*/
|
|
||||||
this.keys = keys;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request data - generated xml
|
|
||||||
*
|
|
||||||
* @type {String}
|
|
||||||
*/
|
|
||||||
this.doc = new DOMParser().parseFromString(data, 'text/xml');
|
|
||||||
}
|
|
||||||
|
|
||||||
digest() {
|
|
||||||
// get the xml node, where the digested value is supposed to be
|
|
||||||
const nodeDigestValue = this.doc.getElementsByTagName('ds:DigestValue')[0];
|
|
||||||
|
|
||||||
// canonicalize the node that has authenticate='true' attribute
|
|
||||||
const contentToDigest = xpath.select("//*[@authenticate='true']", this.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#"');
|
|
||||||
|
|
||||||
if (nodeDigestValue)
|
|
||||||
nodeDigestValue.textContent = Crypto.digestWithHash(fixedContent).toString('base64').trim();
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
sign() {
|
|
||||||
const nodeSignatureValue = this.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', this.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(this.keys.x(), contentToSign); // this.keys.x().key.sign(contentToSign, 'base64');
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
toXML() {
|
|
||||||
return new XMLSerializer().serializeToString(this.doc);
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,87 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const js2xmlparser = require('js2xmlparser');
|
|
||||||
|
|
||||||
const consts = require('../../../consts');
|
|
||||||
const xmlOptions = {
|
|
||||||
declaration: {
|
|
||||||
include: true,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
},
|
|
||||||
format: {
|
|
||||||
doubleQuotes: true,
|
|
||||||
indent: '',
|
|
||||||
newline: '',
|
|
||||||
pretty: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const authSignature = ({
|
|
||||||
'ds:SignedInfo': {
|
|
||||||
'ds:CanonicalizationMethod': {
|
|
||||||
'@': {
|
|
||||||
Algorithm:
|
|
||||||
'http://www.w3.org/TR/2001/REC-xml-c14n-20010315',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'ds:SignatureMethod': {
|
|
||||||
'@': {
|
|
||||||
Algorithm:
|
|
||||||
'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'ds:Reference': {
|
|
||||||
'@': { URI: "#xpointer(//*[@authenticate='true'])" },
|
|
||||||
'ds:Transforms': {
|
|
||||||
'ds:Transform': {
|
|
||||||
'@': {
|
|
||||||
Algorithm:
|
|
||||||
'http://www.w3.org/TR/2001/REC-xml-c14n-20010315',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'ds:DigestMethod': {
|
|
||||||
'@': {
|
|
||||||
Algorithm:
|
|
||||||
'http://www.w3.org/2001/04/xmlenc#sha256',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'ds:DigestValue': {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'ds:SignatureValue': {},
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = class GenericSerializer {
|
|
||||||
constructor(orderBuilder) {
|
|
||||||
this._order = orderBuilder;
|
|
||||||
this._rootName = 'ebicsRequest';
|
|
||||||
this._rootAttributes = {
|
|
||||||
'xmlns:ds': 'http://www.w3.org/2000/09/xmldsig#',
|
|
||||||
xmlns: 'urn:org:ebics:H004',
|
|
||||||
Version: 'H004',
|
|
||||||
Revision: '1',
|
|
||||||
};
|
|
||||||
this._orderDetails = orderBuilder.orderDetails;
|
|
||||||
this._hostId = orderBuilder.hostId;
|
|
||||||
this._partnerId = orderBuilder.partnerId;
|
|
||||||
this._userId = orderBuilder.userId;
|
|
||||||
this._keys = orderBuilder.keys;
|
|
||||||
this._transactionId = orderBuilder.transactionId;
|
|
||||||
this._xmlOptions = xmlOptions;
|
|
||||||
this._xml = {};
|
|
||||||
this._productString = consts.productString;
|
|
||||||
}
|
|
||||||
|
|
||||||
static authSignature() {
|
|
||||||
return authSignature;
|
|
||||||
}
|
|
||||||
|
|
||||||
get keys() {
|
|
||||||
return this._keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
toXML() {
|
|
||||||
return js2xmlparser.parse(this._rootName, this._xml, this._xmlOptions);
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,128 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const zlib = require('zlib');
|
|
||||||
const js2xmlparser = require('js2xmlparser');
|
|
||||||
|
|
||||||
const Crypto = require('../../../crypto/Crypto');
|
|
||||||
|
|
||||||
const GenericSerializer = require('./GenericSerializer');
|
|
||||||
|
|
||||||
module.exports = class InitializationSerializer extends GenericSerializer {
|
|
||||||
constructor(order) {
|
|
||||||
super(order);
|
|
||||||
|
|
||||||
this._xml = {
|
|
||||||
'@': this._rootAttributes,
|
|
||||||
header: {
|
|
||||||
'@': { authenticate: true },
|
|
||||||
static: {
|
|
||||||
HostID: this._hostId,
|
|
||||||
Nonce: Crypto.nonce(),
|
|
||||||
Timestamp: Crypto.timestamp(),
|
|
||||||
PartnerID: this._partnerId,
|
|
||||||
UserID: this._userId,
|
|
||||||
Product: {
|
|
||||||
'@': { Language: 'en' },
|
|
||||||
'#': this._productString,
|
|
||||||
},
|
|
||||||
OrderDetails: this._orderDetails,
|
|
||||||
SecurityMedium: '0000',
|
|
||||||
},
|
|
||||||
mutable: {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this._isINI() || this._isHIA()) {
|
|
||||||
delete this._xml.header.static.Nonce;
|
|
||||||
delete this._xml.header.static.Timestamp;
|
|
||||||
|
|
||||||
this._rootName = 'ebicsUnsecuredRequest';
|
|
||||||
this._xml.body = {
|
|
||||||
DataTransfer: {
|
|
||||||
OrderData: this.orderData(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
this._rootName = 'ebicsNoPubKeyDigestsRequest';
|
|
||||||
this._xml.AuthSignature = GenericSerializer.authSignature();
|
|
||||||
this._xml.body = {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
orderData() {
|
|
||||||
if (this._isINI()) return this._iniKeySignature();
|
|
||||||
if (this._isHIA()) return this._hiaOrderData();
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
_iniKeySignature() {
|
|
||||||
const xmlOrderData = {
|
|
||||||
'@': {
|
|
||||||
'xmlns:ds': 'http://www.w3.org/2000/09/xmldsig#',
|
|
||||||
xmlns: 'http://www.ebics.org/S001',
|
|
||||||
},
|
|
||||||
SignaturePubKeyInfo: {
|
|
||||||
PubKeyValue: {
|
|
||||||
'ds:RSAKeyValue': {
|
|
||||||
'ds:Modulus': Buffer.from(this._keys.a().n(), 'HEX').toString('base64'),
|
|
||||||
'ds:Exponent': this._keys.a().e().toString('base64'),
|
|
||||||
},
|
|
||||||
TimeStamp: Crypto.timestamp(),
|
|
||||||
},
|
|
||||||
SignatureVersion: 'A006',
|
|
||||||
},
|
|
||||||
PartnerID: this._partnerId,
|
|
||||||
UserID: this._userId,
|
|
||||||
};
|
|
||||||
|
|
||||||
const signature = js2xmlparser.parse('SignaturePubKeyOrderData', xmlOrderData, this._xmlOptions);
|
|
||||||
|
|
||||||
return Buffer.from(zlib.deflateSync(signature)).toString('base64');
|
|
||||||
}
|
|
||||||
|
|
||||||
_hiaOrderData() {
|
|
||||||
const xmlOrderData = {
|
|
||||||
'@': {
|
|
||||||
'xmlns:ds': 'http://www.w3.org/2000/09/xmldsig#',
|
|
||||||
xmlns: 'urn:org:ebics:H004',
|
|
||||||
},
|
|
||||||
AuthenticationPubKeyInfo: {
|
|
||||||
PubKeyValue: {
|
|
||||||
'ds:RSAKeyValue': {
|
|
||||||
'ds:Modulus': Buffer.from(this._keys.x().n(), 'HEX').toString('base64'),
|
|
||||||
'ds:Exponent': this._keys.x().e().toString('base64'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
AuthenticationVersion: 'X002',
|
|
||||||
},
|
|
||||||
EncryptionPubKeyInfo: {
|
|
||||||
PubKeyValue: {
|
|
||||||
'ds:RSAKeyValue': {
|
|
||||||
'ds:Modulus': Buffer.from(this.keys.e().n(), 'HEX').toString('base64'),
|
|
||||||
'ds:Exponent': this._keys.e().e().toString('base64'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
EncryptionVersion: 'E002',
|
|
||||||
},
|
|
||||||
PartnerID: this._partnerId,
|
|
||||||
UserID: this._userId,
|
|
||||||
};
|
|
||||||
|
|
||||||
const order = js2xmlparser.parse('HIARequestOrderData', xmlOrderData, this._xmlOptions);
|
|
||||||
|
|
||||||
return Buffer.from(zlib.deflateSync(order)).toString('base64');
|
|
||||||
}
|
|
||||||
|
|
||||||
_isINI() {
|
|
||||||
return this._orderDetails.OrderType.toUpperCase() === 'INI';
|
|
||||||
}
|
|
||||||
|
|
||||||
_isHIA() {
|
|
||||||
return this._orderDetails.OrderType.toUpperCase() === 'HIA';
|
|
||||||
}
|
|
||||||
|
|
||||||
_isHPB() {
|
|
||||||
return this._orderDetails.OrderType.toUpperCase() === 'HPB';
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,130 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const zlib = require('zlib');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
|
|
||||||
const js2xmlparser = require('js2xmlparser');
|
|
||||||
|
|
||||||
const Crypto = require('../../../crypto/Crypto');
|
|
||||||
|
|
||||||
const GenericSerializer = require('./GenericSerializer');
|
|
||||||
|
|
||||||
module.exports = class PaymentSerializer extends GenericSerializer {
|
|
||||||
constructor(order) {
|
|
||||||
super(order);
|
|
||||||
|
|
||||||
this._transactionKey = order.transactionKey;
|
|
||||||
|
|
||||||
this._xml = {
|
|
||||||
'@': this._rootAttributes,
|
|
||||||
header: {
|
|
||||||
'@': { authenticate: true },
|
|
||||||
static: {
|
|
||||||
HostID: this._hostId,
|
|
||||||
Nonce: Crypto.nonce(),
|
|
||||||
Timestamp: Crypto.timestamp(),
|
|
||||||
PartnerID: this._partnerId,
|
|
||||||
UserID: this._userId,
|
|
||||||
Product: {
|
|
||||||
'@': { Language: 'en' },
|
|
||||||
'#': this._productString,
|
|
||||||
},
|
|
||||||
OrderDetails: this._orderDetails,
|
|
||||||
BankPubKeyDigests: {
|
|
||||||
Authentication: {
|
|
||||||
'@': { Version: 'X002', Algorithm: 'http://www.w3.org/2001/04/xmlenc#sha256' },
|
|
||||||
'#': Crypto.digestPublicKey(this._keys.bankX()),
|
|
||||||
},
|
|
||||||
Encryption: {
|
|
||||||
'@': { Version: 'E002', Algorithm: 'http://www.w3.org/2001/04/xmlenc#sha256' },
|
|
||||||
'#': Crypto.digestPublicKey(this._keys.bankE()),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
SecurityMedium: '0000',
|
|
||||||
NumSegments: 1,
|
|
||||||
},
|
|
||||||
mutable: {
|
|
||||||
TransactionPhase: 'Initialisation',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
AuthSignature: GenericSerializer.authSignature(),
|
|
||||||
body: {
|
|
||||||
DataTransfer: {
|
|
||||||
DataEncryptionInfo: {
|
|
||||||
'@': { authenticate: true },
|
|
||||||
EncryptionPubKeyDigest: {
|
|
||||||
'@': { Version: 'E002', Algorithm: 'http://www.w3.org/2001/04/xmlenc#sha256' },
|
|
||||||
'#': Crypto.digestPublicKey(this._keys.bankE()),
|
|
||||||
},
|
|
||||||
TransactionKey: Crypto.publicEncrypt(this._keys.bankE(), this._transactionKey).toString('base64'),
|
|
||||||
},
|
|
||||||
SignatureData: {
|
|
||||||
'@': { authenticate: true },
|
|
||||||
'#': this.encryptedOrderSignature(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (order.hasTransactionId()) {
|
|
||||||
this._xml.header = {
|
|
||||||
'@': { authenticate: true },
|
|
||||||
static: {
|
|
||||||
HostID: this._hostId,
|
|
||||||
TransactionID: this._transactionId,
|
|
||||||
},
|
|
||||||
mutable: {
|
|
||||||
TransactionPhase: 'Transfer',
|
|
||||||
SegmentNumber: {
|
|
||||||
'@': { lastSegment: true },
|
|
||||||
'#': 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
this._xml.body = {
|
|
||||||
DataTransfer: {
|
|
||||||
OrderData: this.encryptedOrderData(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
orderSignature() {
|
|
||||||
const xmlObj = {
|
|
||||||
'@': {
|
|
||||||
xmlns: 'http://www.ebics.org/S001',
|
|
||||||
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
|
||||||
'xsi:schemaLocation': 'http://www.ebics.org/S001 http://www.ebics.org/S001/ebics_signature.xsd',
|
|
||||||
},
|
|
||||||
OrderSignatureData: {
|
|
||||||
SignatureVersion: 'A006',
|
|
||||||
SignatureValue: this.signatureValue(),
|
|
||||||
PartnerID: this._partnerId,
|
|
||||||
UserID: this._userId,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return js2xmlparser.parse('UserSignatureData', xmlObj, this._xmlOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
signatureValue() {
|
|
||||||
const digested = Crypto.digestWithHash(this._order.document.replace(/\n|\r/g, ''));
|
|
||||||
|
|
||||||
return Crypto.sign(this._keys.a(), digested);
|
|
||||||
}
|
|
||||||
|
|
||||||
encryptedOrderData() {
|
|
||||||
const dst = zlib.deflateSync(this._order.document.replace(/\n|\r/g, ''));
|
|
||||||
const cipher = crypto.createCipheriv('aes-128-cbc', this._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');
|
|
||||||
}
|
|
||||||
|
|
||||||
encryptedOrderSignature() {
|
|
||||||
const dst = zlib.deflateSync(this.orderSignature());
|
|
||||||
const cipher = crypto.createCipheriv('aes-128-cbc', this._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');
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,66 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const Crypto = require('../../../crypto/Crypto');
|
|
||||||
|
|
||||||
const GenericSerializer = require('./GenericSerializer');
|
|
||||||
|
|
||||||
module.exports = class StatusSerializer extends GenericSerializer {
|
|
||||||
constructor(order) {
|
|
||||||
super(order);
|
|
||||||
|
|
||||||
this._xml = {
|
|
||||||
'@': this._rootAttributes,
|
|
||||||
header: {
|
|
||||||
'@': { authenticate: true },
|
|
||||||
static: {
|
|
||||||
HostID: this._hostId,
|
|
||||||
Nonce: Crypto.nonce(),
|
|
||||||
Timestamp: Crypto.timestamp(),
|
|
||||||
PartnerID: this._partnerId,
|
|
||||||
UserID: this._userId,
|
|
||||||
Product: {
|
|
||||||
'@': { Language: 'en' },
|
|
||||||
'#': this._productString,
|
|
||||||
},
|
|
||||||
OrderDetails: this._orderDetails,
|
|
||||||
BankPubKeyDigests: {
|
|
||||||
Authentication: {
|
|
||||||
'@': { Version: 'X002', Algorithm: 'http://www.w3.org/2001/04/xmlenc#sha256' },
|
|
||||||
'#': Crypto.digestPublicKey(this._keys.bankX()),
|
|
||||||
},
|
|
||||||
Encryption: {
|
|
||||||
'@': { Version: 'E002', Algorithm: 'http://www.w3.org/2001/04/xmlenc#sha256' },
|
|
||||||
'#': Crypto.digestPublicKey(this._keys.bankE()),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
SecurityMedium: '0000',
|
|
||||||
},
|
|
||||||
mutable: {
|
|
||||||
TransactionPhase: 'Initialisation',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
AuthSignature: GenericSerializer.authSignature(),
|
|
||||||
body: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (order.hasTransactionId()) {
|
|
||||||
this._xml.header = {
|
|
||||||
'@': { authenticate: true },
|
|
||||||
static: {
|
|
||||||
HostID: this._hostId,
|
|
||||||
TransactionID: this._transactionId,
|
|
||||||
},
|
|
||||||
mutable: {
|
|
||||||
TransactionPhase: 'Receipt',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
this._xml.body = {
|
|
||||||
TransferReceipt: {
|
|
||||||
'@': { authenticate: true },
|
|
||||||
ReceiptCode: 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
Loading…
Reference in New Issue
Block a user