62 Commits

Author SHA1 Message Date
nanov
5e73d3ce5e bump 2019-12-18 16:53:18 +02:00
nanov
c7e739f767 lock 2019-12-18 16:49:26 +02:00
nanov
478571e447 chore: update deps 2019-12-18 16:49:20 +02:00
nanov
f6dfdf4c40 feat: generalize examples 2019-12-18 16:48:05 +02:00
Dimitar Nanov
fcbf4ca165 Merge pull request #28 from Herrie82/herrie/config
examples: Externalize configuration values and allow for multiple env…
2019-12-18 10:37:02 +02:00
nanov
6187902ae5 chore: transfer to new repository 2019-12-16 14:28:35 +02:00
Dimitar Nanov
65658ab131 Merge pull request #29 from Herrie82/herrie/send-XG1
Add XG1 order type and example
2019-12-13 10:36:30 +02:00
Herrie
d38460011c Add XG1 order type and example
XG1 order type is used for ISO XML 20022 CGI (Common Global Implementation) which should be a unified format that works within a country (irrespective of bank).

Signed-off-by: Herman van Hazendonk <github.com@herrie.org>
2019-11-29 14:38:46 +01:00
Dimitar Nanov
b9058fac93 Merge pull request #27 from Herrie82/herrie/SupportedBank
README.md: Add Bank GPB International S.A. to supported bank list
2019-11-29 14:14:10 +02:00
Herrie
c3d3decd6a examples: Externalize configuration values and allow for multiple environments
In order to more easily manage testing of various order types as well as production, development etc. environments, externalize this config values.

Signed-off-by: Herman van Hazendonk <github.com@herrie.org>
2019-11-29 13:12:15 +01:00
Herrie
a5b65f815e README.md: Add Bank GPB International S.A. to supported bank list
I was able to test DKI, INI, HAA, HAC, HEV, HVD, STA, VMK, XG1 with Bank GPB International S.A., so I think we're good to add it to the supported bank list.

Signed-off-by: Herman van Hazendonk <github.com@herrie.org>
2019-11-29 11:46:53 +01:00
nanov
5f57a072ea chore: changelog 2019-11-26 18:25:29 +02:00
nanov
f95ecc60b8 chore: changelog 2019-11-26 18:24:35 +02:00
nanov
3873ff49d1 bump version 2019-11-26 18:23:52 +02:00
nanov
9725380edd feat: add C53, C52 and DKI orders 2019-11-26 18:22:09 +02:00
nanov
f2a3d6f067 chore: gitignore 2019-11-26 18:21:56 +02:00
Dimitar Nanov
6d882f56fe Merge pull request #26 from Herrie82/herrie/DKI
* Add DKI, C52, C53 order types.
* Some examples for STA, VMK, C52, C53, DKI and HKD order types.
* Rename example for HBT into HTD.
2019-11-26 18:15:32 +02:00
nanov
88ba543784 feat: add ebics 061011 error 2019-11-26 18:13:30 +02:00
Herrie
f8c9cc7ba8 Add C52/C53 order types and examples
Signed-off-by: Herman van Hazendonk <github.com@herrie.org>
2019-11-25 16:22:39 +01:00
Herrie
0c08d534ff Add examples for MT940 and MT942
Signed-off-by: Herman van Hazendonk <github.com@herrie.org>
2019-11-25 16:22:39 +01:00
Herrie
ad7d55ce7c Add example for HKD order type
Signed-off-by: Herman van Hazendonk <github.com@herrie.org>
2019-11-25 16:20:59 +01:00
Herrie
c15e19d22f Rename send-hbt-order.js to send-htd-order.js
To reflect the name of the order type correctly.

Signed-off-by: Herman van Hazendonk <github.com@herrie.org>
2019-11-25 16:20:59 +01:00
Herrie
d2473bb81d Add DKI order type
To download Exchange rate files and fix syntax error.

Signed-off-by: Herman van Hazendonk <github.com@herrie.org>
2019-11-25 16:20:59 +01:00
nanov
4e6383e23c chore: add coveralls to travis 2019-11-20 19:46:39 +02:00
nanov
a4a64709f0 chore: update dependencies 2019-11-20 19:40:23 +02:00
nanov
7533a861e5 chore: add coveralls badge 2019-11-20 19:38:57 +02:00
nanov
e56e7f224b test: add coveralls support 2019-11-20 19:37:32 +02:00
nanov
6d73ef77d4 test: add additional tests 2019-11-20 14:42:22 +02:00
nanov
a10a3a8d63 feat: async letter serialization 2019-11-20 14:40:18 +02:00
nanov
67d74cfa00 test: add more tests 2019-11-20 11:12:37 +02:00
nanov
ddd0933c0b chore: add Herrie82 to contributors list 2019-11-19 19:48:05 +02:00
Dimitar Nanov
ea52c71fb2 Merge pull request #24 from Herrie82/herrie/english
feat: Add English template & flexible generation
2019-11-19 19:46:46 +02:00
Dimitar Nanov
ddcd31a5c0 Merge pull request #23 from Herrie82/master
chore: Various fixes for spelling
2019-11-19 19:44:11 +02:00
Herrie
95403cbe6f Bank Letter: Add English template & flexible generation
Allow for both German (de) and English (en) initialization letters.

Signed-off-by: Herman van Hazendonk <github.com@herrie.org>
2019-11-19 16:57:13 +01:00
Herman van Hazendonk
0b9d93f745 Various fixes for spelling
Various minor spelling mistake fixes.

Signed-off-by: Herman van Hazendonk <github.com@herrie.org>
2019-11-19 14:48:26 +01:00
nanov
6ecb256483 tests: start Client tests 2019-11-08 11:24:59 +02:00
nanov
d482b1dde1 chore: update readme 2019-11-07 11:53:09 +02:00
nanov
ecf51680c5 chore: add logo 2019-11-07 11:49:22 +02:00
nanov
9a748fa2bc chore: changelog and files settings 2019-11-07 11:42:37 +02:00
nanov
7355096dfd v0.1.2 2019-11-07 11:37:34 +02:00
nanov
25eedd5071 chore: update package.json 2019-11-07 11:36:04 +02:00
Dimitar Nanov
4182e7956a Merge pull request #22 from eCollect/release-it
chore: add changelog configoration
2019-11-07 11:35:34 +02:00
nanov
fee2aa4681 chore: add version script 2019-11-07 11:35:11 +02:00
nanov
1f34dcbfb6 add changelog configoration 2019-11-07 11:20:34 +02:00
nanov
3a64d95eb5 chore: add tags 2019-11-07 10:58:38 +02:00
Dimitar Nanov
926d1bca18 Merge pull request #21 from eCollect/feat/drop-bn.js
Closes #17 and #13
2019-11-07 10:52:01 +02:00
nanov
6d601f4186 chore: fix package json syntax 2019-11-07 10:42:11 +02:00
nanov
2d05bf88f9 chore: add contributors to package json 2019-11-07 10:41:43 +02:00
nanov
10e0d602bd chore: update license expression in package.json 2019-11-07 10:38:01 +02:00
nanov
eea0a49130 feat: drop bn.js 2019-11-07 10:37:31 +02:00
nanov
3e95478b3b feat: add nyc and cleanup .gitignore 2019-11-07 10:35:31 +02:00
nanov
4496cbf560 feat: remove toBuffer from number 2019-11-07 10:30:03 +02:00
nanov
0efc46b014 feat add BigNumber tests 2019-11-07 10:27:20 +02:00
nanov
eafe2f9f55 chore: restructure BigNumber 2019-11-07 10:27:08 +02:00
nanov
24afdeb257 chroe: import consts 2019-11-07 10:26:53 +02:00
nanov
34051f0a9f feat: migrate Crypto to own BigNumber 2019-11-07 08:58:52 +02:00
nanov
14779088f1 chore: lint 2019-11-07 08:57:54 +02:00
nanov
aad0bd97c8 feat: implement all needed BigNumber methods 2019-11-07 08:57:44 +02:00
nanov
429e807994 fix number generarion 2019-11-06 17:27:48 +02:00
nanov
bb8d1cfaa0 wip: migrate MFG1 to BigNumber 2019-11-06 17:16:56 +02:00
nanov
cda36bfcb3 wip: implement BigNumber wrapper 2019-11-06 17:16:15 +02:00
Dimitar Nanov
d21d89fb36 Merge pull request #20 from eCollect/feat/drop-moment
Drop moment dependency
2019-11-06 16:55:15 +02:00
51 changed files with 5194 additions and 134 deletions

View File

@@ -10,6 +10,9 @@ charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.xml]
insert_final_newline = false
[*.json]
indent_size = 2

30
.gitignore vendored
View File

@@ -1,13 +1,23 @@
npm-debug.log
node_modules
# mac shit
.DS_Store
*.local.json5
yarn.lock
/project.sublime-workspace
/public/css/style.css.map
/.idea
# nyc test coverage
.nyc_output
coverage/
# Dependency directories
node_modules/
# Optional npm cache directory
.npm
npm-debug.log
# Optional eslint cache
.eslintcache
# vscode
/.vscode
*.pid
/coverage
package-lock.json
*.html
# Tests temporary
.test_tmp

View File

@@ -5,3 +5,4 @@ node_js:
- "10"
- "11"
- "12"
after_success: npm run coverage

108
CHANGELOG.md Normal file
View File

@@ -0,0 +1,108 @@
### Changelog
#### [v0.1.3](https://github.com/eCollect/node-ebics-client/compare/v0.1.2...v0.1.3)
> 26 November 2019
- * Add DKI, C52, C53 order types. [`#26`](https://github.com/eCollect/node-ebics-client/pull/26)
- Bank Letter: Add English template & flexible generation [`95403cb`](https://github.com/eCollect/node-ebics-client/commit/95403cbe6f90c81a696bb589533d713a4ba04873)
#### [v0.1.2](https://github.com/eCollect/node-ebics-client/compare/v0.1.1...v0.1.2)
> 7 November 2019
- chore: add changelog configoration [`#22`](https://github.com/eCollect/node-ebics-client/pull/22)
- Closes #17 and #13 [`#21`](https://github.com/eCollect/node-ebics-client/pull/21)
- Drop moment dependency [`#20`](https://github.com/eCollect/node-ebics-client/pull/20)
- feat: add nyc and cleanup .gitignore [`3e95478`](https://github.com/eCollect/node-ebics-client/commit/3e95478b3be719c86f32c7df10c42e46b7518669)
- feat: drop bn.js [`eea0a49`](https://github.com/eCollect/node-ebics-client/commit/eea0a49130e30c123b110120c69d7b7c19fd12ba)
- add changelog configoration [`1f34dcb`](https://github.com/eCollect/node-ebics-client/commit/1f34dcbfb6e0febbb93d5356fa36ac57d697a990)
#### [v0.1.1](https://github.com/eCollect/node-ebics-client/compare/v0.1.0...v0.1.1)
> 5 November 2019
- chore: update license [`9aabe93`](https://github.com/eCollect/node-ebics-client/commit/9aabe933e91b506ea38820b952ce8e5e58b4c2ff)
#### [v0.1.0](https://github.com/eCollect/node-ebics-client/compare/v0.0.8...v0.1.0)
> 5 November 2019
- Feat: handle unsual exponent migrate to node-forge [`#16`](https://github.com/eCollect/node-ebics-client/pull/16)
- Add order generation tests and fix linting [`#15`](https://github.com/eCollect/node-ebics-client/pull/15)
- test script run mocha [`#14`](https://github.com/eCollect/node-ebics-client/pull/14)
- feat: prepare order generation tests [`e40f79c`](https://github.com/eCollect/node-ebics-client/commit/e40f79cee68a194272c93f07e763175b213a77a1)
- chore: cleanup [`0c01420`](https://github.com/eCollect/node-ebics-client/commit/0c01420c1e14992a4169098ccd47cd196b899f06)
#### [v0.0.36](https://github.com/eCollect/node-ebics-client/compare/v0.0.35...v0.0.36)
> 1 June 2018
- various modular fixes [`8492d94`](https://github.com/eCollect/node-ebics-client/commit/8492d940542f61b17aa3a2da7de23f6539ffaad5)
#### [v0.0.35](https://github.com/eCollect/node-ebics-client/compare/v0.0.3...v0.0.35)
> 31 May 2018
- update License to GPL v3 [`babcf76`](https://github.com/eCollect/node-ebics-client/commit/babcf76b61af6eb737ab291a301e71bb84621820)
- Add MGF1.js file - mask generation utility class [`7e6e2ff`](https://github.com/eCollect/node-ebics-client/commit/7e6e2ff142688b0c453369fa7137b49e8b89cd81)
- Add sign, _emsaPSS and _modPowe methods in Key.js file [`5ace213`](https://github.com/eCollect/node-ebics-client/commit/5ace2137231af9a3563ab31fa0f70fbdf4b148cb)
#### [v0.0.8](https://github.com/eCollect/node-ebics-client/compare/v0.0.7...v0.0.8)
> 8 October 2019
- chore: readme maintenance [`#11`](https://github.com/eCollect/node-ebics-client/pull/11)
- Provide examples [`#10`](https://github.com/eCollect/node-ebics-client/pull/10)
- initialize.js [`7dad7c8`](https://github.com/eCollect/node-ebics-client/commit/7dad7c878722be94e03808cef3af38d34019c623)
- examples/bankLetter.js [`ce6e58b`](https://github.com/eCollect/node-ebics-client/commit/ce6e58b3f33017967e5b26fe15a2c435012b8af6)
- examples/send-hbt-order.js [`166c61a`](https://github.com/eCollect/node-ebics-client/commit/166c61aec4a247d923de82278271ec02cbef815f)
#### [v0.0.7](https://github.com/eCollect/node-ebics-client/compare/v0.0.6...v0.0.7)
> 2 August 2019
- * Add Z53 order type [`#7`](https://github.com/eCollect/node-ebics-client/pull/7)
- remove eCollect from constant and minor verbose error handeling [`#2`](https://github.com/eCollect/node-ebics-client/pull/2)
- add iso pain format XCT order type [`#1`](https://github.com/eCollect/node-ebics-client/pull/1)
- add new order type XZ53 and removed repeated dateRange to consts [`5ff3147`](https://github.com/eCollect/node-ebics-client/commit/5ff314712443c4c8465f46292b010cfedfed8c2e)
- move dateRange from constants to utils [`aa761cf`](https://github.com/eCollect/node-ebics-client/commit/aa761cf7ad87a271d6e6d9eed40e04eb4376f6c5)
- bump version [`79f17e1`](https://github.com/eCollect/node-ebics-client/commit/79f17e14045d121c9505eb3118967f5f88ae79e2)
#### [v0.0.6](https://github.com/eCollect/node-ebics-client/compare/v0.0.5...v0.0.6)
> 24 July 2019
- remove eCollect from constant and minor verbose error handaling [`#4`](https://github.com/eCollect/node-ebics-client/pull/4)
- add iso pain format XCT order type [`#5`](https://github.com/eCollect/node-ebics-client/pull/5)
- remove eCollect from constant and minor verbose error handeling [`cb2062a`](https://github.com/eCollect/node-ebics-client/commit/cb2062ae2fbd8e8881de26561efddad1f272e065)
- bump [`c9f52d3`](https://github.com/eCollect/node-ebics-client/commit/c9f52d3bd99b9f8761652365b217d9580fa34632)
#### [v0.0.5](https://github.com/eCollect/node-ebics-client/compare/v0.0.4...v0.0.5)
> 28 June 2019
- Fix parsing of the bank keys in the HPB response [`#3`](https://github.com/eCollect/node-ebics-client/pull/3)
- tc for bank keys parsing error [`c571ef1`](https://github.com/eCollect/node-ebics-client/commit/c571ef181bca2e0cbec70bc6df53c706acd6c829)
- #2 corrected bank keys parsing [`5f0b6cd`](https://github.com/eCollect/node-ebics-client/commit/5f0b6cd3747c4613920d2f71f3c04ce13225d397)
#### [v0.0.4](https://github.com/eCollect/node-ebics-client/compare/v0.0.36...v0.0.4)
> 3 September 2018
- Major changes. Separating responsibilities. Orders builder, serializer. [`ff9a3a1`](https://github.com/eCollect/node-ebics-client/commit/ff9a3a16b47d0a25674134c875bfd651995837e4)
- code optimization [`1876360`](https://github.com/eCollect/node-ebics-client/commit/187636019c290d757aca77d4c14fb4f2519acd38)
- client and order optimization [`9454992`](https://github.com/eCollect/node-ebics-client/commit/945499290a8698aed504b573019de2c23148006a)
#### v0.0.3
> 17 May 2018
- initial commit [`1f947ff`](https://github.com/eCollect/node-ebics-client/commit/1f947ff1480c522f89fa1f547581b55e2378d920)
- Initial commit [`cd37de3`](https://github.com/eCollect/node-ebics-client/commit/cd37de3895e32a61798c79ce3a6447e2f269019d)

View File

@@ -1,4 +1,8 @@
# node-ebics-client
<p align="center">
<img src="assets/logo.png" width="300px" height="auto"/>
</p>
<h1 align="center">node-ebics-client</h1>
<p align="center">
<a href="https://travis-ci.org/eCollect/node-ebics-client" title="Build Status"><img src="https://travis-ci.org/eCollect/node-ebics-client.svg?branch=master" alt="Build Status" /></a>
<a href="https://www.npmjs.com/package/ebics-client" title="Build Status">
@@ -8,6 +12,7 @@
<img src="https://snyk.io/test/github/ecollect/node-ebics-client/badge.svg" alt="Known Vulnerabilities">
</a>
<a href="/eCollect/node-ebics-client/blob/master/LICENSE" title="GPL-3.0"><img alt="GPL-3.0" src="https://img.shields.io/github/license/eCollect/node-ebics-client"></a>
<a href='https://coveralls.io/github/eCollect/node-ebics-client?branch=master' title="Coverage Status"><img src='https://coveralls.io/repos/github/eCollect/node-ebics-client/badge.svg?branch=master' alt='Coverage Status' /></a>
</p>
Pure node.js ( >=8 ) implementation of [EBICS](https://en.wikipedia.org/wiki/Electronic_Banking_Internet_Communication_Standard) ( Electronic Banking Internet Communication ).
@@ -22,6 +27,7 @@ The client is currently tested and verified to work with the following banks:
* [Zürcher Kantonalbank](https://www.zkb.ch/en/lg/ew.html)
* [Raiffeisen Schweiz](https://www.raiffeisen.ch/rch/de.html)
* [BW Bank](https://www.bw-bank.de/de/home.html)
* [Bank GPB International S.A.](https://gazprombank.lu/e-banking)
## Inspiration

BIN
assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

25
changelog-template.hbs Normal file
View File

@@ -0,0 +1,25 @@
### Changelog
{{#each releases}}
{{#if href}}
###{{#unless major}}#{{/unless}} [{{title}}]({{href}})
{{else}}
#### {{title}}
{{/if}}
{{#if tag}}
> {{niceDate}}
{{/if}}
{{#if summary}}
{{summary}}
{{/if}}
{{#each merges}}
- {{message}}{{#if href}} [`#{{id}}`]({{href}}){{/if}}
{{/each}}
{{#commit-list commits heading='' message='' exclude='wip: '}}
- {{#if breaking}}**Breaking change:** {{/if}}{{subject}}{{#if href}} [`{{shorthash}}`]({{href}}){{/if}}
{{/commit-list}}
{{/each}}

View File

@@ -6,20 +6,15 @@ const ebics = require('../index');
const path = require('path');
const fs = require('fs');
const os = require('os');
const configjs = require('./config.js');
const client = new ebics.Client({
url: 'https://ebics.server',
partnerId: '',
userId: '',
hostId: '',
passphrase: 'test', // keys-test will be decrypted with this passphrase
keyStorage: ebics.fsKeysStorage('./keys-test'),
});
const client = gClient;
const bankName = 'Bank name';
const template = fs.readFileSync('./templates/ini.hbs').toString();
const bankName = gConfig.bankName;
const languageCode = gConfig.languageCode;
const template = fs.readFileSync('../templates/ini_'+languageCode+'.hbs').toString();
const letter = new ebics.BankLetter({ client, bankName, template });
const bankLetterFile = path.join(os.homedir(), 'bankLetter.html');
const bankLetterFile = path.join(os.homedir(), 'bankLetter_'+languageCode+'.html');
letter.serialize(bankLetterFile)
.then(() => {

View File

@@ -0,0 +1,10 @@
{
"serverAddress": "https://ebics-test.server",
"partnerId": "EBICS ParnerID Test",
"userId": "MyUserIdTest",
"hostId": "MyHostIdTest",
"passphrase": "MyPasswordTest",
"keyStorage": "./keys-test",
"bankName":"Test Bank",
"languageCode":"en"
}

View File

@@ -0,0 +1,10 @@
{
"serverAddress": "https://ebics.server",
"partnerId": "EBICS ParnerID Production",
"userId": "MyUserIdProduction",
"hostId": "MyHostIdProduction",
"passphrase": "MyPasswordProduction",
"keyStorage": "./keys-prod",
"bankName":"Production Bank",
"languageCode":"en"
}

21
examples/getClient.js Normal file
View File

@@ -0,0 +1,21 @@
'use strict';
const { Client, fsKeysStorage } = require('../index');
const loadConfig = require('./loadConfig');
module.exports = ({
serverAddress,
partnerId,
userId,
hostId,
passphrase,
keyStoragePath,
} = loadConfig()) => new Client({
serverAddress,
partnerId,
userId,
hostId,
passphrase,
keyStorage: fsKeysStorage(keyStoragePath),
});

View File

@@ -3,24 +3,18 @@
'use strict';
const ebics = require('../index');
const configjs = require('./config.js');
const client = new ebics.Client({
url: 'https://ebics.server',
partnerId: 'PARTNER',
userId: 'USER',
hostId: 'HOST',
passphrase: 'test', // keys-test will be encrypted with this passphrase
keyStorage: ebics.fsKeysStorage('./keys-test'),
});
const client = gClient;
// New keys will be generated and saved in ./keys-test
client.send(ebics.Orders.INI)
.then((resp) => {
console.log('Respose for INI order %j', resp);
console.log('Response for INI order %j', resp);
return client.send(ebics.Orders.HIA);
})
.then((resp) => {
console.log('Reponse for HIA order %j', resp);
console.log('Response for HIA order %j', resp);
if (resp.technicalCode !== '000000')
throw new Error('Something might went wrong');

35
examples/loadConfig.js Normal file
View File

@@ -0,0 +1,35 @@
'use strict';
const fs = require('fs');
const path = require('path');
const safeLoadJson = (file) => {
if (!file)
return {};
try {
return JSON.parse(fs.readFileSync(file));
} catch (e) {
console.warn(`Couldn't load ${file} config file.`);
return {};
}
}
const getDefaultEnv = () => {
const [,,parArg] = process.argv;
return parArg || process.env.NODE_ENV;
}
const loadConfig = (configDirectory = path.join(__dirname, './config'), env = getDefaultEnv()) => {
console.log(`Loading config form ${configDirectory} with env set to ${env}.`);
const baseConfigFile = path.join(configDirectory, 'config.json');
const envConfigFile = env ? path.join(configDirectory, `config.${env}.json`) : null;
return {
...safeLoadJson(baseConfigFile),
...safeLoadJson(envConfigFile),
}
}
module.exports = loadConfig();

View File

@@ -2,22 +2,13 @@
'use strict';
const ebics = require('../index');
const client = new ebics.Client({
url: 'https://ebics.server',
partnerId: '',
userId: '',
hostId: '',
passphrase: 'test', // keys-test will be decrypted with this passphrase
keyStorage: ebics.fsKeysStorage('./keys-test'),
});
const client = require('./getClient')();
// Client keys must be already generated and send by letter.
// The bank should have enabled the user
client.send(ebics.Orders.HPB)
.then((resp) => {
console.log('Respose for HPB order %j', resp);
console.log('Response for HPB order %j', resp);
if (resp.technicalCode !== '000000')
throw new Error('Something went wrong');

View File

@@ -0,0 +1,21 @@
#! /usr/bin/env node
'use strict';
const client = require('./getClient')();
// The bank keys must have been already saved
client.send(ebics.Orders.C52(null, null)) // startDate 'YYYY-MM-DD', endDate 'YYYY-MM-DD'
.then((resp) => {
console.log('Response for C52 order %j', resp);
if (resp.technicalCode !== '000000')
throw new Error('Something went wrong');
// Parsing and processing the CAMT052 file should happen somewhere here, ideally after saving it to disk
const data = Buffer.from(resp.orderData);
console.log(data.toString('utf8'));
})
.catch((err) => {
console.error(err);
process.exit(1);
});

View File

@@ -0,0 +1,21 @@
#! /usr/bin/env node
'use strict';
const client = require('./getClient')();
// The bank keys must have been already saved
client.send(ebics.Orders.C53(null, null)) // startDate 'YYYY-MM-DD', endDate 'YYYY-MM-DD'
.then((resp) => {
console.log('Response for C53 order %j', resp);
if (resp.technicalCode !== '000000')
throw new Error('Something went wrong');
// Parsing and processing the CAMT053 file should happen somewhere here, ideally after saving it to disk
const data = Buffer.from(resp.orderData);
console.log(data.toString('utf8'));
})
.catch((err) => {
console.error(err);
process.exit(1);
});

View File

@@ -0,0 +1,21 @@
#! /usr/bin/env node
'use strict';
const client = require('./getClient')();
// The bank keys must have been already saved
client.send(ebics.Orders.DKI(null, null)) // startDate 'YYYY-MM-DD', endDate 'YYYY-MM-DD'
.then((resp) => {
console.log('Response for DKI order %j', resp);
if (resp.technicalCode !== '000000')
throw new Error('Something went wrong');
// Processing of the Exchange Rate file should go here, ideally after saving it to disk
const data = Buffer.from(resp.orderData);
console.log(data.toString('utf8'));
})
.catch((err) => {
console.error(err);
process.exit(1);
});

View File

@@ -0,0 +1,20 @@
#! /usr/bin/env node
'use strict';
const client = require('./getClient')();
// The bank keys must have been already saved
client.send(ebics.Orders.HKD)
.then((resp) => {
console.log('Response for HKD order %j', resp);
if (resp.technicalCode !== '000000')
throw new Error('Something went wrong');
const data = Buffer.from(resp.orderData);
console.log(data.toString('utf8'));
})
.catch((err) => {
console.error(err);
process.exit(1);
});

View File

@@ -2,21 +2,12 @@
'use strict';
const ebics = require('../index');
const client = new ebics.Client({
url: 'https://ebics.server',
partnerId: '',
userId: '',
hostId: '',
passphrase: 'test', // keys-test will be decrypted with this passphrase
keyStorage: ebics.fsKeysStorage('./keys-test'),
});
const client = require('./getClient')();
// The bank keys must have been already saved
client.send(ebics.Orders.HTD)
.then((resp) => {
console.log('Respose for HTD order %j', resp);
console.log('Response for HTD order %j', resp);
if (resp.technicalCode !== '000000')
throw new Error('Something went wrong');

View File

@@ -0,0 +1,21 @@
#! /usr/bin/env node
'use strict';
const client = require('./getClient')();
// The bank keys must have been already saved
client.send(ebics.Orders.STA(null, null)) // startDate 'YYYY-MM-DD', endDate 'YYYY-MM-DD'
.then((resp) => {
console.log('Response for STA order %j', resp);
if (resp.technicalCode !== '000000')
throw new Error('Something went wrong');
// Parsing and processing the MT940 file should happen somewhere here, ideally after saving it to disk
const data = Buffer.from(resp.orderData);
console.log(data.toString('utf8'));
})
.catch((err) => {
console.error(err);
process.exit(1);
});

View File

@@ -0,0 +1,21 @@
#! /usr/bin/env node
'use strict';
const client = require('./getClient')();
// The bank keys must have been already saved
client.send(ebics.Orders.VMK(null, null)) // startDate 'YYYY-MM-DD', endDate 'YYYY-MM-DD'
.then((resp) => {
console.log('Response for VMK order %j', resp);
if (resp.technicalCode !== '000000')
throw new Error('Something went wrong');
// Parsing and processing the MT942 file should happen somewhere here, ideally after saving it to disk
const data = Buffer.from(resp.orderData);
console.log(data.toString('utf8'));
})
.catch((err) => {
console.error(err);
process.exit(1);
});

View File

@@ -0,0 +1,20 @@
#! /usr/bin/env node
'use strict';
const ebics = require('../index');
const fs = require('fs');
const client = require('./getClient')();
// The bank keys must have been already saved
const paymentFile = fs.readFileSync('mytestfile.xml').toString();
client.send(ebics.Orders.XG1(paymentFile))
.then((resp) => {
console.log('Response for XG1 order %j', resp);
})
.catch((err) => {
console.error(err);
process.exit(1);
});

View File

@@ -5,7 +5,6 @@ const fs = require('fs');
const handlebars = require('handlebars');
const Crypto = require('./crypto/Crypto');
const { date } = require('./utils.js');
// const BN = require('bn.js');
const registerHelpers = () => {
handlebars.registerHelper('today', () => date.toISODate(Date.now(), false));
@@ -25,6 +24,12 @@ const registerHelpers = () => {
return digest.toUpperCase().match(/.{1,2}/g).join(' ');
});
};
const writeFile = (file, content) => new Promise((resolve, reject) => fs.writeFile(file, content, (err, result) => {
if (err)
return reject(err);
return resolve(result);
}));
module.exports = class BankLetter {
constructor({
client,
@@ -56,13 +61,7 @@ module.exports = class BankLetter {
async serialize(path) {
const letter = await this.generate();
try {
fs.writeFileSync(path, letter);
} catch (error) {
throw error;
}
return new Promise(resolve => resolve(true));
await writeFile(path, letter);
return true;
}
};

View File

@@ -37,13 +37,13 @@ const stringifyKeys = (keys) => {
*/
/**
* Client initilization options
* Client initialization options
* @typedef {Object} EbicClientOptions
* @property {string} url - EBICS URL provided by the bank
* @property {string} partnerId - PARTNERID provided by the bank
* @property {string} hostId - HOSTID provided by the bank
* @property {string} userId - USERID provided by the bank
* @property {string} passphrase - passphrase for keys encyprion
* @property {string} passphrase - passphrase for keys encryption
* @property {KeyStorage} keyStorage - keyStorage implementation
* @property {object} [tracesStorage] - traces (logs) storage implementation
*/
@@ -64,15 +64,15 @@ module.exports = class Client {
tracesStorage,
}) {
if (!url)
throw new Error('EBICS URL is requierd');
throw new Error('EBICS URL is required');
if (!partnerId)
throw new Error('partnerId is requierd');
throw new Error('partnerId is required');
if (!userId)
throw new Error('userId is requierd');
throw new Error('userId is required');
if (!hostId)
throw new Error('hostId is requierd');
throw new Error('hostId is required');
if (!passphrase)
throw new Error('passphrase is requierd');
throw new Error('passphrase is required');
if (!keyStorage || typeof keyStorage.read !== 'function' || typeof keyStorage.write !== 'function')
throw new Error('keyStorage implementation missing or wrong');

View File

@@ -1,9 +1,8 @@
'use strict';
const packageJson = require('../package.json');
const { version } = require('../package.json');
const name = 'Node Ebics Client';
const { version } = packageJson;
const orderOperations = {
ini: 'INI',
upload: 'UPLOAD',

66
lib/crypto/BigNumber.js Normal file
View File

@@ -0,0 +1,66 @@
'use strict';
const { jsbn: { BigInteger } } = require('node-forge');
class BigNumber {
constructor(value, radix = 10) {
if (value === null || value === undefined)
throw new Error('value is missing.');
this._n = new BigInteger(null);
if (value instanceof BigNumber)
this._n = value._n;
else if (value instanceof BigInteger)
this._n = value;
else if (typeof value === 'number')
this._n.fromInt(value);
else if (typeof value === 'string')
this._n.fromString(value, radix);
else if (Buffer.isBuffer(value))
this._n.fromString(value.toString('hex'), 16);
else if (Array.isArray(value))
this._n.fromString(Buffer.from(value).toString('hex'), 16);
else
throw new TypeError('Unsupported value type.');
}
toBEBuffer(length) {
const arr = this._n.toByteArray();
if (length === undefined)
return Buffer.from(arr);
if (arr.length > length)
throw new Error('Number out of range.');
while (arr.length < length)
arr.unshift(0);
return Buffer.from(arr);
}
toString(radix = 10) {
const result = this._n.toString(radix);
if (radix === 16)
return result.padStart(2, '0');
return result;
}
and(num) {
return new BigNumber(this._n.and(new BigNumber(num)._n));
}
mul(num) {
return new BigNumber(this._n.multiply(new BigNumber(num)._n));
}
mod(num) {
return new BigNumber(this._n.mod(new BigNumber(num)._n));
}
shrn(num) {
return new BigNumber(this._n.shiftRight(new BigNumber(num)._n));
}
}
module.exports = BigNumber;

View File

@@ -2,15 +2,14 @@
const crypto = require('crypto');
const BN = require('bn.js');
const BigNumber = require('./BigNumber.js');
const mgf1 = require('./MGF1');
const modPow = (base, power, mod) => {
let result = new BN(1);
let result = new BigNumber(1);
while (power > 0) {
result = power.and(new BN(1)) == 1 ? (result.mul(base)).mod(mod) : result; // eslint-disable-line
result = power.and(new BigNumber(1)) == 1 ? (result.mul(base)).mod(mod) : result; // eslint-disable-line
base = (base.mul(base)).mod(mod);
power = power.shrn(1);
}
@@ -28,10 +27,13 @@ const emsaPSS = (msg, salt) => {
const dbMask = mgf1.generate(mTickHash, db.length);
const maskedDb = mgf1.xor(db, dbMask);
let maskedDbMsb = mgf1.rjust(new BN(maskedDb.slice(0, 1), 2).toString(2), 8, '0');
let maskedDbMsb = mgf1.rjust(new BigNumber(maskedDb.slice(0, 1)).toString(2), 8, '0');
maskedDbMsb = `0${maskedDbMsb.substr(1)}`;
maskedDb[0] = (new BN(maskedDbMsb, 2).toBuffer())[0]; // eslint-disable-line
// console.log((new BN(maskedDbMsb, 2).toBuffer())[0], new BigNumber(maskedDbMsb, 2).toBuffer()[0]);
// maskedDb[0] = (new BN(maskedDbMsb, 2).toBuffer())[0]; // eslint-disable-line
maskedDb[0] = new BigNumber(maskedDbMsb, 2).toBEBuffer()[0]; // eslint-disable-line
return Buffer.concat([maskedDb, mTickHash, Buffer.from('BC', 'hex')]);
};
@@ -65,11 +67,12 @@ module.exports = class Crypto {
}
static sign(key, msg, salt = crypto.randomBytes(32)) {
const base = new BN(emsaPSS(msg, salt));
const power = new BN(key.d());
const mod = new BN(key.n());
// console.log(key.d());
const base = new BigNumber(emsaPSS(msg, salt));
const power = new BigNumber(key.d());
const mod = new BigNumber(key.n());
return (modPow(base, power, mod)).toBuffer().toString('base64');
return (modPow(base, power, mod)).toBEBuffer().toString('base64');
}
static pad(d) {

View File

@@ -1,13 +1,13 @@
'use strict';
const crypto = require('crypto');
const BN = require('bn.js');
const BigNumber = require('./BigNumber.js');
const MFG_LEN = 32;
const divceil = (a, b) => ~~(((a + b) - 1) / b); // eslint-disable-line no-bitwise
const rjust = (string, width, padding) => {
padding = padding || ' ';
const rjust = (string, width, padding = ' ') => {
padding = padding.substr(0, 1);
if (string.length < width)
return padding.repeat(width - string.length) + string;
@@ -26,7 +26,7 @@ const i2osp = (x, len) => {
if (x >= 256 ** len)
throw new Error('Integer too large');
return Buffer.from(rjust((Buffer.from((new BN(x)).toArray('be', 4)).toString()).replace(/\x00/gi, ''), len, '\x00')); // eslint-disable-line no-control-regex
return Buffer.from(rjust(new BigNumber(x).toBEBuffer(4).toString().replace(/\x00/gi, ''), len, '\x00')); // eslint-disable-line no-control-regex
};
module.exports = {

View File

@@ -10,12 +10,12 @@ const errors = {
'011000': {
symbol: 'EBICS_DOWNLOAD_POSTPROCESS_DONE',
short_text: 'Positive acknowledgement received',
meaning: "After receipt of a positive acknowledgement the download task was finished at the server's end and the EBICS transaction ended.",
meaning: "After receipt of a positive acknowledgment the download task was finished at the server's end and the EBICS transaction ended.",
},
'011001': {
symbol: 'EBICS_DOWNLOAD_POSTPROCESS_SKIPPED',
short_text: 'Negative acknowledgement received',
meaning: "After receipt of a negative acknowledgement the transaction was ended at the server's end without finishing the download task",
short_text: 'Negative acknowledgment received',
meaning: "After receipt of a negative acknowledgment the transaction was ended at the server's end without finishing the download task",
},
'011101': {
symbol: 'EBICS_TX_SEGMENT_NUMBER_UNDERRUN',
@@ -32,6 +32,11 @@ const errors = {
short_text: 'Authentication signature error',
meaning: 'Verification of the authentication signature was not successful',
},
'061011': {
symbol: 'EBICS_INVALID_HOST_ID',
short_text: 'The transmitted HostID is unknown on the bank side',
meaning: 'The transmitted HostID is unknown on the bank side',
},
'061002': {
symbol: 'EBICS_INVALID_REQUEST',
short_text: 'Message not EBICSconformant',
@@ -104,8 +109,8 @@ const errors = {
},
'091102': {
symbol: 'EBICS_TX_ABORT',
short_text: 'Transaction cancelled',
meaning: "The transaction was cancelled at the server's end since recovery of the transaction is not supported or is no longer possible due to the recovery counter being too high",
short_text: 'Transaction canceled',
meaning: "The transaction was canceled at the server's end since recovery of the transaction is not supported or is no longer possible due to the recovery counter being too high",
},
'091103': {
symbol: 'EBICS_TX_MESSAGE_REPLAY',

View File

@@ -51,7 +51,6 @@ module.exports = (xml, keys) => ({
transactionKey() {
const keyNodeText = this.doc.getElementsByTagNameNS('urn:org:ebics:H004', 'TransactionKey')[0].textContent;
return Crypto.privateDecrypt(this.keys.e(), Buffer.from(keyNodeText, 'base64'));
},
@@ -64,7 +63,7 @@ module.exports = (xml, keys) => ({
orderId() {
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 : '';
},

View File

@@ -0,0 +1,13 @@
'use strict';
const utils = require('../utils');
module.exports = (start = null, end = null) => ({
version: 'h004',
orderDetails: {
OrderType: 'C52',
OrderAttribute: 'DZHNN',
StandardOrderParams: utils.dateRange(start, end),
},
operation: 'download',
});

View File

@@ -0,0 +1,13 @@
'use strict';
const utils = require('../utils');
module.exports = (start = null, end = null) => ({
version: 'h004',
orderDetails: {
OrderType: 'C53',
OrderAttribute: 'DZHNN',
StandardOrderParams: utils.dateRange(start, end),
},
operation: 'download',
});

View File

@@ -0,0 +1,13 @@
'use strict';
const utils = require('../utils');
module.exports = (start = null, end = null) => ({
version: 'h004',
orderDetails: {
OrderType: 'DKI',
OrderAttribute: 'DZHNN',
StandardOrderParams: utils.dateRange(start, end),
},
operation: 'download',
});

View File

@@ -0,0 +1,8 @@
'use strict';
module.exports = document => ({
version: 'h004',
orderDetails: { OrderType: 'XG1', OrderAttribute: 'OZHNN', StandardOrderParams: {} },
operation: 'upload',
document,
});

View File

@@ -13,6 +13,7 @@ const CCT = require('./CCT');
const CCS = require('./CCS');
const XE3 = require('./XE3');
const XCT = require('./XCT');
const XG1 = require('./XG1');
const STA = require('./STA');
const VMK = require('./VMK');
@@ -23,6 +24,9 @@ const HKD = require('./HKD');
const PTK = require('./PTK');
const HAC = require('./HAC');
const Z53 = require('./Z53');
const DKI = require('./DKI');
const C52 = require('./C52');
const C53 = require('./C53');
module.exports = {
INI,
@@ -39,6 +43,8 @@ module.exports = {
CCS,
XE3,
XCT,
XG1,
STA,
VMK,
HAA,
@@ -47,4 +53,7 @@ module.exports = {
HKD,
PTK,
HAC,
DKI,
C52,
C53,
};

3866
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,24 +1,41 @@
{
"name": "ebics-client",
"version": "0.1.1",
"version": "0.1.4",
"description": "Node.js ISO 20022 Compliant EBICS Client",
"main": "index.js",
"files": [
"lib/**/*",
"templates/**/*"
],
"scripts": {
"lint": "eslint .",
"test": "mocha test/**/*.js"
"test": "nyc mocha test/**/*.js",
"coverage": "nyc report --reporter=text-lcov | coveralls",
"version": "auto-changelog -p -t changelog-template.hbs && git add CHANGELOG.md"
},
"repository": {
"type": "git",
"url": "https://github.com/eCollect/node-ebics-client"
"url": "https://github.com/node-ebics/node-ebics-client"
},
"keywords": [
"EBICS",
"ISO20022",
"nodejs",
"api"
"api",
"banking"
],
"author": "eCollect Sofia Tech Team",
"contributors": [
{
"name": "Dimitar Nanov",
"url": "https://nanov.io",
"email": "dimitar@nanov.io"
},
{
"name": "Vladislav Hristov",
"url": "https://github.com/vladhristov",
"email": "vlad.s.ch@gmail.com"
},
{
"name": "Vasyl Stashuk",
"url": "https://github.com/vasyas"
@@ -26,12 +43,16 @@
{
"name": "Yago",
"url": "https://github.com/yagop"
},
{
"name": "Herman van Hazendonk",
"email": "github.com@herrie.org"
}
],
"license": "GPLv3",
"license": "GPL-3.0-only",
"dependencies": {
"bn.js": "^5.0.0",
"handlebars": "^4.4.3",
"auto-changelog": "^1.16.2",
"handlebars": "^4.5.3",
"js2xmlparser": "^4.0.0",
"node-forge": "^0.9.1",
"request": "^2.88.0",
@@ -42,10 +63,12 @@
},
"devDependencies": {
"chai": "^4.2.0",
"eslint": "^6.6.0",
"coveralls": "^3.0.9",
"eslint": "^6.7.2",
"eslint-config-ecollect-base": "^0.1.2",
"eslint-plugin-import": "^2.18.2",
"libxmljs": "^0.19.7",
"mocha": "^6.2.2"
"mocha": "^6.2.2",
"nyc": "^14.1.1"
}
}

164
templates/ini_en.hbs Normal file
View File

@@ -0,0 +1,164 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta charset="UTF-8" />
<title>EBICS ini</title>
</head>
<body>
<div>
<h2>EBICS-Initialization letter (INI)</h2>
<table>
<tr>
<td>Date</td>
<td>{{ today }}</td>
</tr>
<tr>
<td>Time</td>
<td>{{ now }}</td>
</tr>
<tr>
<td>Recipient</td>
<td>{{ bankName }}</td>
</tr>
<tr>
<td>User ID</td>
<td>{{ userId }}</td>
</tr>
<tr>
<td>Customer ID</td>
<td>{{ partnerId }}</td>
</tr>
</table>
<p>Public authentication key (A006)</p>
<p>Exponent ({{ keyExponentBits A006 }} Bit):</p>
<p>
<code>{{ keyExponent A006 }}</code>
</p>
<p>Modulus ({{ keyModulusBits A006 }} Bit):</p>
<p>
<code>{{ keyModulus A006 }}</code>
</p>
<p>SHA-256 Hash:</p>
<p>
<code>{{ sha256 A006 }}</code>
</p>
<p>I hereby confirm the above public key for my electronic signature.</p>
<br/>
<br/>
<br/>
<br/>
<table>
<tr>
<td>_________________________</td>
<td>_________________________</td>
<td>_________________________</td>
</tr>
<tr>
<td>City/Date</td>
<td>Name/Company</td>
<td>Signature</td>
</tr>
</table>
</div>
<div style="page-break-after:always"></div>
<h2>EBICS-Initialization letter (HIA) - Page 1/2</h2>
<table>
<tr>
<td>Date</td>
<td>{{ today }}</td>
</tr>
<tr>
<td>Time</td>
<td>{{ now }}</td>
</tr>
<tr>
<td>Recipient</td>
<td>{{ bankName }}</td>
</tr>
<tr>
<td>User ID</td>
<td>{{ userId }}</td>
</tr>
<tr>
<td>Customer ID</td>
<td>{{ partnerId }}</td>
</tr>
</table>
<div>
<p>Public Identification Key (X002)</p>
<p>Exponent ({{ keyExponentBits X002 }} Bit):</p>
<p>
<code>{{ keyExponent X002 }}</code>
</p>
<p>Modulus ({{ keyModulusBits X002 }} Bit):</p>
<p>
<code>{{ keyModulus X002 }}</code>
</p>
<p>SHA-256 Hash:</p>
<p>
<code>{{ sha256 X002 }}</code>
</p>
<p> Continuation on Page 2 ...</p>
<div style="page-break-after:always"></div>
<h2>EBICS-Initialization letter (HIA) - Page 2/2</h2>
<table>
<tr>
<td>Date</td>
<td>{{ today }}</td>
</tr>
<tr>
<td>Time</td>
<td>{{ now }}</td>
</tr>
<tr>
<td>Recipient</td>
<td>{{ bankName }}</td>
</tr>
<tr>
<td>User ID</td>
<td>{{ userId }}</td>
</tr>
<tr>
<td>Customer ID</td>
<td>{{ partnerId }}</td>
</tr>
</table>
</div>
<div>
<p>Public Encryption Key (E002)</p>
<p>Exponent ({{ keyExponentBits E002 }} Bit):</p>
<p>
<code>{{ keyExponent E002 }}</code>
</p>
<p>Modulus ({{ keyModulusBits E002 }} Bit):</p>
<p>
<code>{{ keyModulus E002 }}</code>
</p>
<p>SHA-256 Hash:</p>
<p>
<code>{{ sha256 E002 }}</code>
</p>
<p>I hereby confirm the above public keys for my EBICS access.</p>
<br/>
<br/>
<br/>
<br/>
<table>
<tr>
<td>_________________________</td>
<td>_________________________</td>
<td>_________________________</td>
</tr>
<tr>
<td>City/Date</td>
<td>Name/Company</td>
<td>Signature</td>
</tr>
</table>
</div>
</body>
</html>

21
test/fixtures/HPB_response.xml vendored Normal file
View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<ebicsKeyManagementResponse xmlns="urn:org:ebics:H004" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Revision="1" Version="H004" xsi:schemaLocation="urn:org:ebics:H004 ebics_keymgmt_response_H004.xsd">
<header authenticate="true">
<static/>
<mutable>
<ReturnCode>000000</ReturnCode>
<ReportText>[EBICS_OK] OK</ReportText>
</mutable>
</header>
<body>
<DataTransfer>
<DataEncryptionInfo authenticate="true">
<EncryptionPubKeyDigest Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" Version="E002">nuZyAjQoIvH4MwnrCWB82TC/vcNqigpqPtMXwO1Xk9U=</EncryptionPubKeyDigest>
<TransactionKey>QgfTQqhocARTcpcgySGxn5a+uBuFsHCX0oBINQQIfsgMRR+wEZ3zlXQMUm5GUwwOci2wjkRHJ3PoO4Yd0KzDNWiXFuX/9n00bpnNN5MsTCRgDqJRzZrA1jDxWRBVY/sv3l1gS/ERwyWqub456VZ7DYlXlRA8yp5lormoxftpIt6/Cf0ShmhS8qlUkLYSn/8ugQRl1KRTID5ZSXPjDYAIVZ0izVxblaBYXgs6RH9VvP4uKSn4CFYiFp+alo6EcxFNgMVUnfzaEbsPH/aX9Y3tbdWhATBZSxTT8iMoi2ARhz9VB711aavB8vgzcD6jH3ZtIm+sCb3UC3A/KehEn9GjIA==</TransactionKey>
</DataEncryptionInfo>
<OrderData>xlQf5zxlUo4LwjkoDsh926OISQwn6PhpxF3CkZI34EO84tfK25zLbqriXiqwDycl2YjYrQxbj8B4k1auNe86a+JigQOoBBCL8gvsoxO+NlziPNzf8sP99dQSp436q7KOhVm4gz2ZZT3D3O5FSqpOKsQ0fJku7D76beoxqxUT+hD0UxgsGLsbGgNLzHPalnFJctuaZtqQmo24Uk6hOwLrFJoQwUbPEffU5GGARWrZVxGQr5Zw4zrtLlZzP1RXk9JZFnhx00KvKiaoxAQXxXUC0BeDM97tIMEiaRNbO3ne+mHtK8vXzc305X5yR0B6ocwbFAmzGQ/e6Fyy6XPIGsbXoLjJGod6ayIU1SJGx/JRyOU4cLkjJZLUQMyCdJ6bA5uYf1AePUDvUA3tAOd6W0cC7DPAlwcrWhSZkPLIawequyjO39LTkEcmINEigd4i3sCrG4e1k303gyIKUg79kApl46onW2vruN3DwswunI10JGXxqex7ccvd2JvD6Pc8cAH1RMg8FIucYd//Joh1XK+QkRdIZMWKg4/lkoWmgVN7ssMmrtsKE2pNFAsIRfgxd8bB64sHZ3XKSyZKTk4LnWdJHZopP/xTs9a+/G3Kd/sIsy4W4sIKZCWU8NL11YOaqfwxY/rYNMaQzhAmawFfWvt74iisFG81Wv+Ijja/dPFmbk3Mup2Dfnlfu26MDblC8+aiaPHypmPuzREqGjW/9d2vtLQz0IXX3X6H4pFXneSjKlwXlDk1WGuiOvXH4gmXEpfWTX9rq+rUyskwwL8ssW5eeeyJ5W2LhVKQllOi/bvrAL5kyrfDMxvOuFIBLxBf//xE</OrderData>
</DataTransfer>
<ReturnCode authenticate="true">000000</ReturnCode>
<TimestampBankParameter authenticate="true">2016-08-10T16:16:17.512Z</TimestampBankParameter>
</body>
</ebicsKeyManagementResponse>

22
test/fixtures/HPB_response_data.xml vendored Normal file
View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<HPBResponseOrderData xmlns="urn:org:ebics:H004" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xsi:schemaLocation="urn:org:ebics:H004 ebics_orders_H004.xsd">
<AuthenticationPubKeyInfo>
<PubKeyValue>
<ds:RSAKeyValue>
<ds:Modulus>AJWVHQIfP0H1fr5Y7IjSlDmFksqQ+0E+CjzbEeE6r444LCuSXwbGKF6DJqguyX1qGYxjHRvVtdkNa+GNAtlZnmuPeLHPBUOs5Zx9J5JP4JZOcKd/wnRDIasTkg3NrtZ22tjOrWx26VuR6h7dUH2oJRnFDHmbXoCDMxkqJUNr/TM89p5slJ9Oj5+NAaOzm+7AlwbJ95EI/xc2jEfhp+GdF9CYdS/m2AZaAt79y6QDtBSDdAs0OHTgsOIjbjZkptBF/Gkip2sOordjsChRNLHLDcAOWbsg1NVMuhXs1b6+bCVLXQcGhFydYhqvrXB7pFS0++hlyzqGhbZK5cwEe/v8EJk=</ds:Modulus>
<ds:Exponent>AQAB</ds:Exponent>
</ds:RSAKeyValue>
</PubKeyValue>
<AuthenticationVersion>X002</AuthenticationVersion>
</AuthenticationPubKeyInfo>
<EncryptionPubKeyInfo>
<PubKeyValue>
<ds:RSAKeyValue>
<ds:Modulus>AJWVHQIfP0H1fr5Y7IjSlDmFksqQ+0E+CjzbEeE6r444LCuSXwbGKF6DJqguyX1qGYxjHRvVtdkNa+GNAtlZnmuPeLHPBUOs5Zx9J5JP4JZOcKd/wnRDIasTkg3NrtZ22tjOrWx26VuR6h7dUH2oJRnFDHmbXoCDMxkqJUNr/TM89p5slJ9Oj5+NAaOzm+7AlwbJ95EI/xc2jEfhp+GdF9CYdS/m2AZaAt79y6QDtBSDdAs0OHTgsOIjbjZkptBF/Gkip2sOordjsChRNLHLDcAOWbsg1NVMuhXs1b6+bCVLXQcGhFydYhqvrXB7pFS0++hlyzqGhbZK5cwEe/v8EJk=</ds:Modulus>
<ds:Exponent>AQAB</ds:Exponent>
</ds:RSAKeyValue>
</PubKeyValue>
<EncryptionVersion>E002</EncryptionVersion>
</EncryptionPubKeyInfo>
<HostID>CRSISOTB</HostID>
</HPBResponseOrderData>

13
test/fixtures/INI_reposne.xml vendored Normal file
View File

@@ -0,0 +1,13 @@
<h004:ebicsKeyManagementResponse xmlns:h004="urn:org:ebics:H004" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:org:ebics:H004 ebics_H004.xsd" Version="H004" Revision="1">
<h004:header authenticate="true">
<h004:static />
<h004:mutable>
<h004:OrderID>B004</h004:OrderID>
<h004:ReturnCode>000000</h004:ReturnCode>
<h004:ReportText>[EBICS_OK] OK</h004:ReportText>
</h004:mutable>
</h004:header>
<h004:body>
<h004:ReturnCode authenticate="true">000000</h004:ReturnCode>
</h004:body>
</h004:ebicsKeyManagementResponse>

164
test/fixtures/Letter_DE.html vendored Normal file
View File

@@ -0,0 +1,164 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta charset="UTF-8" />
<title>EBICS ini</title>
</head>
<body>
<div>
<h2>EBICS-Initialisierungsbrief (INI)</h2>
<table>
<tr>
<td>Datum</td>
<td>2019-11-20</td>
</tr>
<tr>
<td>Uhrzeit</td>
<td>14:14:03</td>
</tr>
<tr>
<td>Empfänger</td>
<td>Credit Suisse AG</td>
</tr>
<tr>
<td>User-ID</td>
<td>CRS04381</td>
</tr>
<tr>
<td>Kunden-ID</td>
<td>CRS04381</td>
</tr>
</table>
<p>Öffentlicher Schlüssel für die elektronische Unterschrift (A006)</p>
<p>Exponent (24 Bit):</p>
<p>
<code>010001</code>
</p>
<p>Modulus (2048 Bit):</p>
<p>
<code>AB E6 54 CA EF B8 AD 81 C2 79 74 9C 42 39 82 A7 A4 1C 76 C8 00 69 68 90 79 59 22 DA 6F 1B C6 12 DA B1 32 8F 97 57 D0 71 2F 09 90 63 96 CA 80 00 8B D3 B8 1A D9 D2 91 14 08 84 BA F7 CF 78 6D E6 40 74 7B FF 48 44 9D D6 DE 1D 9A F3 07 F4 48 AC A2 3C E2 2C 79 34 98 59 E3 48 64 EF 9E E2 C4 9C BC CE DA 1E 31 EC 4D 51 85 62 05 6B FC CB 8D B1 09 DF 17 3C 2C 68 D4 C7 3F 15 BF 4C A6 65 E4 D9 A3 CD 3E 3F 1F 20 16 5E A2 27 93 35 86 DE D7 A8 5D 8F E1 0C A5 02 AF C7 7B 51 9C D0 00 5C 2D 46 E8 42 D3 2F 8A 8C 31 C2 ED 61 01 4F B5 B2 E7 3E 11 18 8C D7 83 23 1E D5 24 BE A9 A4 5C 56 8C CC 52 75 E1 15 63 39 90 AB 36 CE 30 1D 3B 50 85 7D CE 7A 72 77 67 77 4C 5E 37 BE 95 31 91 A7 51 A7 BC C6 C6 BD 2B 85 3D 08 29 90 B1 F6 77 2F 23 9F FD 2A 03 03 04 E1 CB F6 66 6A D9 EC B5 66 60 89</code>
</p>
<p>Hash (SHA-256):</p>
<p>
<code>85 F0 4F 8B 97 6A F0 E2 FD 9F 21 2B 0B B3 A2 7A 97 B3 BB 57 B3 1B 55 14 F7 ED B5 CB CD E4 FE 79</code>
</p>
<p>Ich bestätige hiermit den obigen öffentlichen Schlüssel für meine elektronische Unterschrift.</p>
<br/>
<br/>
<br/>
<br/>
<table>
<tr>
<td>_________________________</td>
<td>_________________________</td>
<td>_________________________</td>
</tr>
<tr>
<td>Ort/Datum</td>
<td>Name/Firma</td>
<td>Unterschrift</td>
</tr>
</table>
</div>
<div style="page-break-after:always"></div>
<h2>EBICS-Initialisierungsbrief (HIA) - Seite 1/2</h2>
<table>
<tr>
<td>Datum</td>
<td>2019-11-20</td>
</tr>
<tr>
<td>Uhrzeit</td>
<td>14:14:03</td>
</tr>
<tr>
<td>Empfänger</td>
<td>Credit Suisse AG</td>
</tr>
<tr>
<td>User-ID</td>
<td>CRS04381</td>
</tr>
<tr>
<td>Kunden-ID</td>
<td>CRS04381</td>
</tr>
</table>
<div>
<p>Öffentlicher Authentifikationsschlüssel (X002)</p>
<p>Exponent (24 Bit):</p>
<p>
<code>010001</code>
</p>
<p>Modulus (2048 Bit):</p>
<p>
<code>8A ED FC 0F 2C 86 EA E3 07 D9 0D 75 DD E6 25 4F 20 40 41 43 D6 22 C0 59 A9 38 F6 54 42 74 ED 5C 38 C4 6C 63 F2 0F A2 65 85 D9 58 1A 1E F5 1E C4 9E E3 66 5B 67 6B 37 B0 FA BD 8C FE 12 D3 F0 3A C8 23 22 56 3F 30 B0 FB 70 C5 7B 17 41 15 A8 EE 54 F3 1F AF DE 13 7E 96 38 AF 9B 69 28 22 1F 9A 7C C4 C6 1D 35 59 66 40 81 7F D7 48 DA B9 51 EF A9 0C 96 C5 7A 55 25 66 A5 63 B6 4A 45 F0 97 0F 56 60 18 5B CE 08 A2 7D 87 64 18 A2 4A E1 B3 8E 75 24 3F FC AC 23 A5 33 BF 0C 41 E3 96 B5 D2 54 CA 37 07 40 A9 E3 2B 01 17 A6 21 AE 07 1E 52 0A 00 E1 95 F3 BE BC 19 EA E9 90 48 17 38 60 DE 68 BD 85 36 37 59 14 E0 BC 07 C5 B8 50 0A 87 87 90 13 91 6C 4F 03 2B 40 27 14 2B 7F A9 D7 71 12 57 E5 A9 72 CE 16 B7 7B 5E 7D A2 52 D6 CE 9D 39 DA 44 C0 41 EF 02 37 7B 93 98 CC 35 D8 06 D1 79 57</code>
</p>
<p>Hash (SHA-256):</p>
<p>
<code>F8 3B D7 EB 6F 2B 48 4B 2B 0A BD CA C7 EF F8 56 11 D1 90 32 D6 CC 67 3B 8A 3E 74 F5 F8 B4 E1 AA</code>
</p>
<p> Fortsetzung auf Seite 2 ...</p>
<div style="page-break-after:always"></div>
<h2>EBICS-Initialisierungsbrief (HIA) - Seite 2/2</h2>
<table>
<tr>
<td>Datum</td>
<td>2019-11-20</td>
</tr>
<tr>
<td>Uhrzeit</td>
<td>14:14:03</td>
</tr>
<tr>
<td>Empfänger</td>
<td>Credit Suisse AG</td>
</tr>
<tr>
<td>User-ID</td>
<td>CRS04381</td>
</tr>
<tr>
<td>Kunden-ID</td>
<td>CRS04381</td>
</tr>
</table>
</div>
<div>
<p>Öffentlicher Verschlüsselungsschlüssel (E002)</p>
<p>Exponent (24 Bit):</p>
<p>
<code>010001</code>
</p>
<p>Modulus (2048 Bit):</p>
<p>
<code>93 10 E9 40 2A B1 77 DB 31 C7 EB 13 5A E6 21 FD 6B 18 2B 74 40 67 B1 C9 6D B6 09 4A 1D CD F0 A7 DC 51 A4 53 EF AE 14 0D 9E A0 FB E4 EE D0 2E CF 6C 4C 5E 99 83 F3 A3 8E C3 FE F5 C1 DA E2 E6 52 96 A1 5B 9C 10 2D D1 F1 A2 0F 8E 3E 5D 81 55 DF 19 11 5B 5E 62 DB 95 56 0E 19 4C EF F3 87 50 EB 5F B7 42 3C 5D CB 47 51 81 E7 3F 39 6A 4A CA 6E 29 55 2B 22 14 FE 24 DA 5D DB 0C 99 D2 61 7A FB 40 B7 61 B8 82 89 BE 59 4C 64 92 9A F2 5E 82 62 3A 98 11 61 A3 77 0F 13 38 5D FD 13 BD 9C 4A 96 F9 34 8A 3B 99 4D 25 7B 1B A8 3F 90 F7 6F 9D 09 74 DB 4C B7 27 A3 0B EC 7C 05 E5 F3 1C F7 C2 59 0D 3A 57 86 D5 AD AF 1E CC 84 9F B8 4C DF 8A 35 22 CF D5 B8 12 2B 44 E4 12 BE 26 F7 D7 31 31 31 BB 3D 3C 49 7E C6 AF 44 4D 00 1F FC 04 84 2F 10 8B 2C 78 15 0F 22 46 70 78 2B 25 56 16 36 FB 9F</code>
</p>
<p>Hash (SHA-256):</p>
<p>
<code>9E E6 72 02 34 28 22 F1 F8 33 09 EB 09 60 7C D9 30 BF BD C3 6A 8A 0A 6A 3E D3 17 C0 ED 57 93 D5</code>
</p>
<p>Ich bestätige hiermit die obigen öffentlichen Schlüssel für meinen EBICS-Zugang.</p>
<br/>
<br/>
<br/>
<br/>
<table>
<tr>
<td>_________________________</td>
<td>_________________________</td>
<td>_________________________</td>
</tr>
<tr>
<td>Ort/Datum</td>
<td>Name/Firma</td>
<td>Unterschrift</td>
</tr>
</table>
</div>
</body>
</html>

40
test/fixtures/STA_response_part1.xml vendored Normal file
View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<ebicsResponse xmlns="urn:org:ebics:H004" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:org:ebics:H004 http://www.ebics.org/H004/ebics_response_H004.xsd" Version="H004" Revision="1">
<header authenticate="true">
<static>
<TransactionID>ECD6F062AAEDFA77250526A68CBEC549</TransactionID>
<NumSegments>2</NumSegments>
</static>
<mutable>
<TransactionPhase>Initialisation</TransactionPhase>
<SegmentNumber lastSegment="false">1</SegmentNumber>
<ReturnCode>000000</ReturnCode>
<ReportText>[EBICS_OK] OK</ReportText>
</mutable>
</header>
<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:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>OnY4VczV+1XfplpMS/SCKFWn+FDMge40X8TJ9pA6HEI=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>Qiz8clr/Ym+wLpB8CzTuxKP5rgIR2P4SaX8O4gGZx0Di8Lzd4hsBO3koqIuX11NRZo0RYA5E/IKQCoYLepkcM4QHvLT37YidbrXsTZe6cml/yF8OdyRAcd/9U7AoA9GKENFk4lnBFfZYmM4ADK6wVOCE/ABaOk0NeCDDbxrKA75tfTxwxTvQBfUOHZ87LrZxuQf//L9pzmtI07/7GbsQX8ZceQq40SpBFZn/oRvT/Q38Qu2ZO59MZexJn+BTzlhpfv9fQGF/sgXkdhUkPTEW3nL4j7ehasq3CtySGO2RnEppohEvJ4m07RDtEY3OWyAAZoPFVpvnECM6pOLbIuR40w==</ds:SignatureValue>
</AuthSignature>
<body>
<DataTransfer>
<DataEncryptionInfo authenticate="true">
<EncryptionPubKeyDigest Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" Version="E002">IUW05JB5cuCzRYYa4kIAZ2ehYVrLI3lKvxZvo1uP+ug=</EncryptionPubKeyDigest>
<TransactionKey>CPdd6ODXrCxHWpYrwS/5a3NIZ1R2SDscHHJSONc2I7g8ara7qv5Ra7H03W+336DPQLZQxH+EBRWdE2FQ1vrVTcypK6fkFarmO1dEtQt6Ka89AozC7aQMyp4yGl+zlF+XvFkJXZbRXgoEOPsgcG0xM6nKLXnr1ThYRFOoAasigLDGwqxliyhoR94F9dL7YB8Le/uZeRj78mNp4smkE5ZKKyPhwVx+0IW78YuVCSC2c2qbsMmm4evAvycdpLfuuoG4KVlNMIlvkKeBfMZFELcmeKKm85D2zPYkZ7cqG2IfAAp5qdS6K8P7RY4gtjUhOtP5mi8bZt/ZcjioUmIR9dAMnA==</TransactionKey>
</DataEncryptionInfo>
<OrderData>lJ/v1HvOYAZKTPkxULH4mOcUy01+EaAsxLzCPhtieAo9m5AtU5URdyBVfmclHbtWe3ELb02lR37bChynq0Esqpljxx7CiB+kl/bVs7XkNQQmtGPlh08O7ApJ7AHdKPFFvE+SM2OWpSwUrqJGtmyaU6s+RM66o/3Q0wvKi4y3+Q2jm8nkiWZpPfNt52g4ReE9Ge86o+L+EBOBgZm634L5Z/i6pq908mXBAklPdk1ERdEgWONaOeYYmB70FToplR1gINJEF2CnfAtD/wV+DuQFPDth+EWHqhe3a4xO0d9eJ55ou2QCYOPUC2g/qz1sp7GR74W7P5IWJdmnUEuPFsKJ6OvM+1V8S06jZGDa/QhUGDK8F3G/TMP09W1MsrlQTRr3YQ5H43+pMY7I6Jysze+X9OKZZTTpv4GmYm1USjmraGyMuPF3j9hrlmpttK+1gg2WzytCJO44YsZp9ckls8JNK4bT5uwTuomKZoRgmiIOTcMh4VP7V28TWj2XdF+T6rBFILTvQyXMOzvbe1kLwg2O31JDBdJ8X1fHCYJxKsIrYCSDPz4sha8h7QmHrCSFmjoXb+LUElnbLXZVRkY5/Dc73EM6Es3wAgjwSJK2asRqdqU0PhbS5qpIlgYKsNcb+Wes</OrderData>
</DataTransfer>
<ReturnCode authenticate="true">000000</ReturnCode>
<TimestampBankParameter authenticate="true">2013-12-09T15:14:30.000Z</TimestampBankParameter>
</body>
</ebicsResponse>

40
test/fixtures/STA_response_part2.xml vendored Normal file
View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<ebicsResponse xmlns="urn:org:ebics:H004" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:org:ebics:H004 http://www.ebics.org/H004/ebics_response_H004.xsd" Version="H004" Revision="1">
<header authenticate="true">
<static>
<TransactionID>ECD6F062AAEDFA77250526A68CBEC549</TransactionID>
<NumSegments>1</NumSegments>
</static>
<mutable>
<TransactionPhase>Initialisation</TransactionPhase>
<SegmentNumber lastSegment="true">1</SegmentNumber>
<ReturnCode>000000</ReturnCode>
<ReportText>[EBICS_OK] OK</ReportText>
</mutable>
</header>
<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:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>OnY4VczV+1XfplpMS/SCKFWn+FDMge40X8TJ9pA6HEI=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>Qiz8clr/Ym+wLpB8CzTuxKP5rgIR2P4SaX8O4gGZx0Di8Lzd4hsBO3koqIuX11NRZo0RYA5E/IKQCoYLepkcM4QHvLT37YidbrXsTZe6cml/yF8OdyRAcd/9U7AoA9GKENFk4lnBFfZYmM4ADK6wVOCE/ABaOk0NeCDDbxrKA75tfTxwxTvQBfUOHZ87LrZxuQf//L9pzmtI07/7GbsQX8ZceQq40SpBFZn/oRvT/Q38Qu2ZO59MZexJn+BTzlhpfv9fQGF/sgXkdhUkPTEW3nL4j7ehasq3CtySGO2RnEppohEvJ4m07RDtEY3OWyAAZoPFVpvnECM6pOLbIuR40w==</ds:SignatureValue>
</AuthSignature>
<body>
<DataTransfer>
<DataEncryptionInfo authenticate="true">
<EncryptionPubKeyDigest Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" Version="E002">IUW05JB5cuCzRYYa4kIAZ2ehYVrLI3lKvxZvo1uP+ug=</EncryptionPubKeyDigest>
<TransactionKey>CPdd6ODXrCxHWpYrwS/5a3NIZ1R2SDscHHJSONc2I7g8ara7qv5Ra7H03W+336DPQLZQxH+EBRWdE2FQ1vrVTcypK6fkFarmO1dEtQt6Ka89AozC7aQMyp4yGl+zlF+XvFkJXZbRXgoEOPsgcG0xM6nKLXnr1ThYRFOoAasigLDGwqxliyhoR94F9dL7YB8Le/uZeRj78mNp4smkE5ZKKyPhwVx+0IW78YuVCSC2c2qbsMmm4evAvycdpLfuuoG4KVlNMIlvkKeBfMZFELcmeKKm85D2zPYkZ7cqG2IfAAp5qdS6K8P7RY4gtjUhOtP5mi8bZt/ZcjioUmIR9dAMnA==</TransactionKey>
</DataEncryptionInfo>
<OrderData>lJ/v1HvOYAZKTPkxULH4mOcUy01+EaAsxLzCPhtieAo9m5AtU5URdyBVfmclHbtWe3ELb02lR37bChynq0Esqpljxx7CiB+kl/bVs7XkNQQmtGPlh08O7ApJ7AHdKPFFvE+SM2OWpSwUrqJGtmyaU6s+RM66o/3Q0wvKi4y3+Q2jm8nkiWZpPfNt52g4ReE9Ge86o+L+EBOBgZm634L5Z/i6pq908mXBAklPdk1ERdEgWONaOeYYmB70FToplR1gINJEF2CnfAtD/wV+DuQFPDth+EWHqhe3a4xO0d9eJ55ou2QCYOPUC2g/qz1sp7GR74W7P5IWJdmnUEuPFsKJ6OvM+1V8S06jZGDa/QhUGDK8F3G/TMP09W1MsrlQTRr3YQ5H43+pMY7I6Jysze+X9OKZZTTpv4GmYm1USjmraGyMuPF3j9hrlmpttK+1gg2WzytCJO44YsZp9ckls8JNK4bT5uwTuomKZoRgmiIOTcMh4VP7V28TWj2XdF+T6rBFILTvQyXMOzvbe1kLwg2O31JDBdJ8X1fHCYJxKsIrYCSDPz4sha8h7QmHrCSFmjoXb+LUElnbLXZVRkY5/Dc73EM6Es3wAgjwSJK2asRqdqU0PhbS5qpIlgYKsNcb+Wes</OrderData>
</DataTransfer>
<ReturnCode authenticate="true">000000</ReturnCode>
<TimestampBankParameter authenticate="true">2013-12-09T15:14:30.000Z</TimestampBankParameter>
</body>
</ebicsResponse>

View File

@@ -77,6 +77,9 @@ const fnOrders = {
PTK: dateBuilder,
HAC: dateBuilder,
Z53: dateBuilder,
DKI: dateBuilder,
C53: dateBuilder,
C52: dateBuilder,
};
const getOrderObject = (name, order) => {

View File

@@ -0,0 +1,49 @@
'use strict';
/* eslint-env node, mocha */
const { assert } = require('chai');
const { join, resolve } = require('path');
const { readFileSync, mkdirSync, existsSync } = require('fs');
const BankLetter = require('../../lib/BankLetter');
const ebics = require('../../');
const client = new ebics.Client({
url: 'https://iso20022test.credit-suisse.com/ebicsweb/ebicsweb',
partnerId: 'CRS04381',
userId: 'CRS04381',
hostId: 'CRSISOTB',
passphrase: 'test',
keyStorage: ebics.fsKeysStorage(resolve(__dirname, '../support/TEST_KEYS.key')),
});
const createDir = (where) => {
try {
mkdirSync(where);
} catch (e) {
if (e.code !== 'EEXIST')
throw e;
}
};
describe('BankLetter', () => {
let bankLetterGenerator = null;
it('creates an instance', () => assert.doesNotThrow(() => {
bankLetterGenerator = new BankLetter({
client,
bankName: 'Credit Suisse AG',
template: readFileSync(join(__dirname, '../../templates/ini_de.hbs'), { encoding: 'utf8' }),
});
}));
it('genrates a letter', async () => assert.doesNotThrow(async () => bankLetterGenerator.generate()));
it('throws with invalid serliazitaion path', async () => bankLetterGenerator.serialize('').catch(e => assert.instanceOf(e, Error)));
it('serliaziers a letter to disk', async () => {
createDir('.test_tmp');
await bankLetterGenerator.serialize('.test_tmp/test_letter.html').then(t => assert.equal(t, true));
assert.equal(existsSync('.test_tmp/test_letter.html'), true);
});
});

47
test/unit/BigNumber.js Normal file
View File

@@ -0,0 +1,47 @@
'use strict';
/* eslint-env node, mocha */
const { assert } = require('chai');
const { jsbn: { BigInteger } } = require('node-forge');
const BigNumber = require('../../lib/crypto/BigNumber');
const types = [
{ name: 'BigNumber', value: new BigNumber(11) },
{ name: 'BigInteger', value: new BigInteger('11') },
{ name: 'string with default radix', value: '11' },
{ name: 'string with radix 16', value: '0b', radix: 16 },
{ name: 'Buffer', value: Buffer.from('0b', 'hex') },
{ name: 'Array', value: [11] },
];
describe('BigNumber', () => {
describe('creating an instance', () => {
it('should throw with no value given', () => assert.throws(() => new BigNumber()));
it('should throw wrong value type', () => assert.throws(() => new BigNumber({})));
for (const { name, value, radix } of types) {
let instance;
describe(`out of ${name}`, () => {
it('create instance', () => assert.doesNotThrow(() => {
instance = new BigNumber(value, radix);
}));
it('toString with radix 10', () => assert.equal(instance.toString(), '11'));
it('toString with radix 16', () => assert.equal(instance.toString(16), '0b'));
it('toBEBuffer without length', () => assert.equal(instance.toBEBuffer().toString('hex'), '0b'));
it('toBEBuffer with length', () => assert.equal(instance.toBEBuffer(4).toString('hex'), '0000000b'));
});
}
});
describe('exports', () => {
it('toBEBuffer with too short length should throw', () => assert.throw(() => new BigNumber(837462187362).toBEBuffer(1)));
});
describe('operators', () => {
const num = new BigNumber(1);
it('and', () => assert.equal(num.and(1), 1));
it('mul', () => assert.equal(num.mul(2), 2));
it('mod', () => assert.equal(num.mod(1), 0));
it('shrn', () => assert.equal(num.shrn(1), 0));
});
});

29
test/unit/ClientTest.js Normal file
View File

@@ -0,0 +1,29 @@
'use strict';
/* eslint-env node, mocha */
const { assert } = require('chai');
const { Client, fsKeysStorage, tracesStorage } = require('../../index.js');
describe('Client', () => {
describe('instantiating', () => {
it('should throw with no options provided', () => assert.throws(() => new Client()));
it('should throw with no url provided', () => assert.throws(() => new Client({})));
it('should throw with no partnerId provided', () => assert.throws(() => new Client({ url: 'https://myebics.com' })));
it('should throw with no userId provided', () => assert.throws(() => new Client({ url: 'https://myebics.com', partnerId: 'partnerId' })));
it('should throw with no hostId provided', () => assert.throws(() => new Client({ url: 'https://myebics.com', partnerId: 'partnerId', userId: 'userId' })));
it('should throw with no passphrase provided', () => assert.throws(() => new Client({
url: 'https://myebics.com', partnerId: 'partnerId', userId: 'userId', hostId: 'hostId',
})));
it('should throw with no keyStorage provided', () => assert.throws(() => new Client({
url: 'https://myebics.com', partnerId: 'partnerId', userId: 'userId', hostId: 'hostId', passphrase: 'test',
})));
it('should create an isntance without tracesStorage', () => assert.doesNotThrow(() => new Client({
url: 'https://myebics.com', partnerId: 'partnerId', userId: 'userId', hostId: 'hostId', passphrase: 'test', keyStorage: fsKeysStorage('./test.key'),
})));
it('should create an isntance with tracesStorage', () => assert.doesNotThrow(() => new Client({
url: 'https://myebics.com', partnerId: 'partnerId', userId: 'userId', hostId: 'hostId', passphrase: 'test', keyStorage: fsKeysStorage('./test.key'), tracesStorage: tracesStorage('./'),
})));
});
});

41
test/unit/middlewares.js Normal file
View File

@@ -0,0 +1,41 @@
'use strict';
/* eslint-env node, mocha */
const { assert } = require('chai');
const { resolve } = require('path');
const response = require('../../lib/middleware/response');
const serializer = require('../../lib/middleware/serializer');
const signer = require('../../lib/middleware/signer');
const ebics = require('../../');
const client = new ebics.Client({
url: 'https://iso20022test.credit-suisse.com/ebicsweb/ebicsweb',
partnerId: 'CRS04381',
userId: 'CRS04381',
hostId: 'CRSISOTB',
passphrase: 'test',
keyStorage: ebics.fsKeysStorage(resolve(__dirname, '../support/TEST_KEYS.key')),
});
describe('Middlewares', () => {
describe('Response Middleware', () => {
it('should not throw with supported protocol version', () => assert.doesNotThrow(() => response.version('H004')));
it('should throw with no unsupported protocol version', () => assert.throws(() => response.version('H003')));
});
describe('Signer Middleware', () => {
it('should not throw with supported protocol version', () => assert.doesNotThrow(() => signer.version('H004')));
it('should throw with no unsupported protocol version', () => assert.throws(() => signer.version('H003')));
});
describe('Serializer Middleware', () => {
it('should not throw with supported protocol version and ini operation', () => assert.doesNotThrow(() => serializer.use(ebics.Orders.INI, client)));
it('should not throw with supported protocol version and download operation', () => assert.doesNotThrow(() => serializer.use(ebics.Orders.STA('2018-01-01', '2018-02-01'), client)));
it('should not throw with supported protocol version and upload operation', () => assert.doesNotThrow(() => serializer.use(ebics.Orders.AZV('<xml />'), client)));
it('should throw with no supported protocol version and ', () => assert.throws(() => serializer.use({ version: 'H004', operation: 'unspported' }, client)));
it('should throw with no unuspported protocol version', () => assert.throws(() => serializer.use({ version: 'H003' }, client)));
});
});

View File

@@ -2,44 +2,110 @@
/* eslint-env node, mocha */
const { readFileSync } = require('fs');
const { join, resolve } = require('path');
const { assert } = require('chai');
const H004Response = require('../../lib/orders/H004/response');
const ebics = require('../../');
const client = new ebics.Client({
url: 'https://iso20022test.credit-suisse.com/ebicsweb/ebicsweb',
partnerId: 'CRS04381',
userId: 'CRS04381',
hostId: 'CRSISOTB',
passphrase: 'test',
keyStorage: ebics.fsKeysStorage(resolve(__dirname, '../support/TEST_KEYS.key')),
});
const buildResponse = (xmlPath) => {
const response = H004Response('<xml/>', {});
const xml = readFileSync(xmlPath, { encoding: 'utf8' });
response.orderData = () => xml;
return response;
};
const fixtures = {
HPB: async () => H004Response(readFileSync(join(__dirname, '../fixtures/HPB_response.xml'), { encoding: 'utf8' }), await client.keys()),
HPB_DATA: () => buildResponse(join(__dirname, '../fixtures/HPB_response_data.xml')),
INI: () => H004Response(readFileSync(join(__dirname, '../fixtures/INI_reposne.xml'), { encoding: 'utf8' }), client.keys()),
STA_1: () => H004Response(readFileSync(join(__dirname, '../fixtures/STA_response_part1.xml'), { encoding: 'utf8' }), client.keys()),
STA_2: () => H004Response(readFileSync(join(__dirname, '../fixtures/STA_response_part2.xml'), { encoding: 'utf8' }), client.keys()),
x002mod: 'AJWVHQIfP0H1fr5Y7IjSlDmFksqQ+0E+CjzbEeE6r444LCuSXwbGKF6DJqguyX1qGYxjHRvVtdkNa+GNAtlZnmuPeLHPBUOs5Zx9J5JP4JZOcKd/wnRDIasTkg3NrtZ22tjOrWx26VuR6h7dUH2oJRnFDHmbXoCDMxkqJUNr/TM89p5slJ9Oj5+NAaOzm+7AlwbJ95EI/xc2jEfhp+GdF9CYdS/m2AZaAt79y6QDtBSDdAs0OHTgsOIjbjZkptBF/Gkip2sOordjsChRNLHLDcAOWbsg1NVMuhXs1b6+bCVLXQcGhFydYhqvrXB7pFS0++hlyzqGhbZK5cwEe/v8EJk=',
e002mod: 'AJWVHQIfP0H1fr5Y7IjSlDmFksqQ+0E+CjzbEeE6r444LCuSXwbGKF6DJqguyX1qGYxjHRvVtdkNa+GNAtlZnmuPeLHPBUOs5Zx9J5JP4JZOcKd/wnRDIasTkg3NrtZ22tjOrWx26VuR6h7dUH2oJRnFDHmbXoCDMxkqJUNr/TM89p5slJ9Oj5+NAaOzm+7AlwbJ95EI/xc2jEfhp+GdF9CYdS/m2AZaAt79y6QDtBSDdAs0OHTgsOIjbjZkptBF/Gkip2sOordjsChRNLHLDcAOWbsg1NVMuhXs1b6+bCVLXQcGhFydYhqvrXB7pFS0++hlyzqGhbZK5cwEe/v8EJk=',
};
describe('H004 response parsing', () => {
it('parses bank keys', () => {
const response = H004Response('<xml/>', {});
const x002mod = 'ntbX6WFjAJP5RyH4ogDG/26wZGzEJXsTudyvcgXmUdk1AExCNqArXDiSlGXpVNq4BKddUMFUmVOyvkdNckPRV2mk3uHNCE5T3tFKQI3FlwHSJHvPSpb9gtHnsK03jByMigWjhTKvsjIdfLVay5m5Bctxq9+5JMHwlNk7MlVXBQcqaFiHFFS1lPfA3Wk1bptPeeGyYcP0+U798oQWnCABKwS8hmYcp5xBtozGoRj9L/NDE68pdP8o/wTKNwT4Jo5nQKYfDsgO4R+z9vVv37Htp6bWhK8Jw3tpkcd3JnkYWx+Ylg0XBpg8LfjFhY2Jc7FqLlx0Bn0Y3PRLI1apxgC85w==';
const e002mod = '4eOGrzcJHVzbEgZTmyPYUIq9kFoua8Ure1Mvyq6XlawFgCWskfu/xSKNLIMJ7H675wl/5y0Oy16P/b6pJEhWrzOw8omW46PBDTaXw9BDYBTuBblluz1yUnzpgfblP8gkRmxAo+QMIskmwdSzuZMiJcLNSzu/bkmLHK2RdrVYMAZLlB6QXTykdenPZtNmc2z4VU6TRmGljAwg2VUNF6iQoucbzDUuca+yUo3fiXZp69nfXv81X2ND+p1ir6zQpx7tbOdfauw0sEKI/Z/lC+E4fMrMlh/ZvOxSYUMA55J4liC3aUV3mTR3dPJHWu1aD1a7EfJnNw0eHLwlB+36qfgGuw==';
response.orderData = () => `<?xml version="1.0" encoding="UTF-8"?>
<HPBResponseOrderData xmlns="urn:org:ebics:H004" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<AuthenticationPubKeyInfo>
<PubKeyValue>
<ds:RSAKeyValue>
<ds:Modulus>${x002mod}</ds:Modulus>
<ds:Exponent>AQAB</ds:Exponent>
</ds:RSAKeyValue>
<TimeStamp>2015-02-25T08:01:13.061Z</TimeStamp>
</PubKeyValue>
<AuthenticationVersion>X002</AuthenticationVersion>
</AuthenticationPubKeyInfo>
<EncryptionPubKeyInfo>
<PubKeyValue>
<ds:RSAKeyValue>
<ds:Modulus>${e002mod}</ds:Modulus>
<ds:Exponent>AQAB</ds:Exponent>
</ds:RSAKeyValue>
<TimeStamp>2015-02-25T08:01:12.344Z</TimeStamp>
</PubKeyValue>
<EncryptionVersion>E002</EncryptionVersion>
</EncryptionPubKeyInfo>
<HostID>SBKPR01</HostID>
</HPBResponseOrderData>`;
const response = fixtures.HPB_DATA();
const bankKeys = response.bankKeys();
assert.equal(bankKeys.bankX002.mod.toString('base64'), x002mod);
assert.equal(bankKeys.bankE002.mod.toString('base64'), e002mod);
assert.equal(bankKeys.bankX002.mod.toString('base64'), fixtures.x002mod);
assert.equal(bankKeys.bankE002.mod.toString('base64'), fixtures.e002mod);
});
it('detects unsegmented response', () => {
const response = fixtures.HPB_DATA();
assert.equal(response.isSegmented(), false);
assert.equal(response.isLastSegment(), false);
});
it('detects segmented response', () => {
const responsePart1 = fixtures.STA_1();
const responsePart2 = fixtures.STA_2();
assert.equal(responsePart1.isSegmented(), true);
assert.equal(responsePart1.isLastSegment(), false);
assert.equal(responsePart2.isSegmented(), true);
assert.equal(responsePart2.isLastSegment(), true);
});
it('parses OrderID', () => {
const response = fixtures.INI();
assert.equal(response.orderId(), 'B004');
});
it('parses BuissnessCode', () => {
const response = fixtures.INI();
const code = response.businessCode();
assert.equal(code, '000000');
assert.equal(response.businessSymbol(code), 'EBICS_OK');
assert.equal(response.businessMeaning(code), 'No technical errors occurred during processing of the EBICS request');
assert.equal(response.businessShortText(code), 'OK');
});
it('parses TechnicalCode', () => {
const response = fixtures.INI();
const code = response.technicalCode();
assert.equal(code, '000000');
assert.equal(response.technicalSymbol(code), '[EBICS_OK] OK');
assert.equal(response.technicalMeaning(code), 'No technical errors occurred during processing of the EBICS request');
assert.equal(response.technicalShortText(code), 'OK');
});
it('parses TransactionID', () => {
const response = fixtures.STA_1();
const code = response.transactionId();
assert.equal(code, 'ECD6F062AAEDFA77250526A68CBEC549');
});
it('parses TransactionKey', async () => {
const response = await fixtures.HPB();
const code = response.transactionKey().toString('base64');
assert.equal(code, '2OTepxiy49uayuzZlYFf8Q==');
});
it('parses OrderData', async () => {
const response = await fixtures.HPB();
const orderBuffer = response.orderData();
assert.deepEqual(orderBuffer, readFileSync(join(__dirname, '../fixtures/HPB_response_data.xml')));
});
it('generates XML', async () => {
const response = await fixtures.HPB();
const xmlString = response.toXML().replace('\\n', '\n');
assert.deepEqual(xmlString, readFileSync(join(__dirname, '../fixtures/HPB_response.xml'), { encoding: 'utf8' }));
});
});