mirror of
https://github.com/node-ebics/node-ebics-client.git
synced 2025-08-14 11:45:35 +00:00
Compare commits
248 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
4a09c8e260 | ||
|
3e4ea41090 | ||
|
8dd84444ff | ||
|
e810ce241f | ||
|
b2ae16b933 | ||
|
ac1b554144 | ||
|
bf64593440 | ||
|
138a2a2e6e | ||
|
aa86eaaffe | ||
|
6cb025f441 | ||
|
c1b87a9e32 | ||
|
412c0146db | ||
|
d96b5e650b | ||
|
1fbe17846d | ||
|
a07822e953 | ||
|
c1022e5ca8 | ||
|
ccaa3f14c9 | ||
|
388156a2e4 | ||
|
231830addc | ||
|
475fc58289 | ||
|
ba997d312b | ||
|
bc4b33f7e4 | ||
|
b1abf16864 | ||
|
fd7bdfe55d | ||
|
e41c0bf74d | ||
|
36b8d2999c | ||
|
510654f52e | ||
|
e251cc0e5b | ||
|
8da104515c | ||
|
f3bd654739 | ||
|
b6b27516d5 | ||
|
a03ec2283f | ||
|
66bf57f0dc | ||
|
3a8dc1da0b | ||
|
a3ce00eb3e | ||
|
e1ded83ea9 | ||
|
0eccce4754 | ||
|
7520a56be8 | ||
|
fe0f585b27 | ||
|
d0c6d76431 | ||
|
936e103c3f | ||
|
9ee2be97c4 | ||
|
f9fb6d3dc9 | ||
|
2d580c0d44 | ||
|
5c8139e1bc | ||
|
cecaa782c9 | ||
|
3eb997e3df | ||
|
2b35ed072a | ||
|
9ef50081ca | ||
|
d192e61d29 | ||
|
0e56947b07 | ||
|
e6420244dc | ||
|
c8220f6d45 | ||
|
f6dfc73ff2 | ||
|
6921f8d503 | ||
|
043caedc94 | ||
|
13f6d03cb2 | ||
|
546d371193 | ||
|
374560b14a | ||
|
500737dbc7 | ||
|
57a15f0722 | ||
|
bff972f354 | ||
|
de92265c95 | ||
|
61581d1af7 | ||
|
8af3cb50c5 | ||
|
a628e00b9b | ||
|
b8ec1e228e | ||
|
f027bc4048 | ||
|
a998538316 | ||
|
b44ff0f44c | ||
|
2ba095fbdd | ||
|
c28a6f7f09 | ||
|
0585ecd396 | ||
|
21a46832fc | ||
|
d5a24f9537 | ||
|
a9bbdd95c6 | ||
|
acd5a1897c | ||
|
bd11a410f1 | ||
|
4e5d8c2ea5 | ||
|
f913f95b64 | ||
|
f232b81fc3 | ||
|
3a18b213d5 | ||
|
7053a03286 | ||
|
be76a52ae5 | ||
|
99f0bd9622 | ||
|
e57316c6cb | ||
|
4b0bf0eba6 | ||
|
e060863356 | ||
|
fb464078dc | ||
|
3d4c94dff8 | ||
|
e98a1f8cc3 | ||
|
c5e59414f3 | ||
|
5e73d3ce5e | ||
|
c7e739f767 | ||
|
478571e447 | ||
|
f6dfdf4c40 | ||
|
fcbf4ca165 | ||
|
6187902ae5 | ||
|
65658ab131 | ||
|
d38460011c | ||
|
b9058fac93 | ||
|
c3d3decd6a | ||
|
a5b65f815e | ||
|
5f57a072ea | ||
|
f95ecc60b8 | ||
|
3873ff49d1 | ||
|
9725380edd | ||
|
f2a3d6f067 | ||
|
6d882f56fe | ||
|
88ba543784 | ||
|
f8c9cc7ba8 | ||
|
0c08d534ff | ||
|
ad7d55ce7c | ||
|
c15e19d22f | ||
|
d2473bb81d | ||
|
4e6383e23c | ||
|
a4a64709f0 | ||
|
7533a861e5 | ||
|
e56e7f224b | ||
|
6d73ef77d4 | ||
|
a10a3a8d63 | ||
|
67d74cfa00 | ||
|
ddd0933c0b | ||
|
ea52c71fb2 | ||
|
ddcd31a5c0 | ||
|
95403cbe6f | ||
|
0b9d93f745 | ||
|
6ecb256483 | ||
|
d482b1dde1 | ||
|
ecf51680c5 | ||
|
9a748fa2bc | ||
|
7355096dfd | ||
|
25eedd5071 | ||
|
4182e7956a | ||
|
fee2aa4681 | ||
|
1f34dcbfb6 | ||
|
3a64d95eb5 | ||
|
926d1bca18 | ||
|
6d601f4186 | ||
|
2d05bf88f9 | ||
|
10e0d602bd | ||
|
eea0a49130 | ||
|
3e95478b3b | ||
|
4496cbf560 | ||
|
0efc46b014 | ||
|
eafe2f9f55 | ||
|
24afdeb257 | ||
|
34051f0a9f | ||
|
14779088f1 | ||
|
aad0bd97c8 | ||
|
429e807994 | ||
|
bb8d1cfaa0 | ||
|
cda36bfcb3 | ||
|
d21d89fb36 | ||
|
df9c330411 | ||
|
2a17ff6056 | ||
|
33ac6ac60f | ||
|
e9f7c11bbb | ||
|
9aabe933e9 | ||
|
dc5f52198b | ||
|
bb5e551057 | ||
|
0a3a4631df | ||
|
3ffa323264 | ||
|
e56dc082d0 | ||
|
0c01420c1e | ||
|
0964992164 | ||
|
5c419630c1 | ||
|
594f2a2623 | ||
|
fa557f5e9b | ||
|
cf16abc843 | ||
|
c60fed4d58 | ||
|
9aa2ab7380 | ||
|
fe2ad67139 | ||
|
104ec67f8c | ||
|
e8a80932e1 | ||
|
ce6cd02e58 | ||
|
836ec0ebf3 | ||
|
59a281c895 | ||
|
61ada747f3 | ||
|
f15e09840a | ||
|
422821fbbd | ||
|
e40f79cee6 | ||
|
837fdaa08c | ||
|
361acf89d0 | ||
|
4149c01695 | ||
|
1c1f112ff5 | ||
|
1320f6f21d | ||
|
0049fffc00 | ||
|
2c9040904a | ||
|
0f6dcf9eb2 | ||
|
ca31edf245 | ||
|
4464349d0f | ||
|
15546df9ea | ||
|
40467a2c5e | ||
|
eb9fbf5834 | ||
|
166c61aec4 | ||
|
5a63e19aab | ||
|
9e6c318372 | ||
|
ce6e58b3f3 | ||
|
7dad7c8787 | ||
|
79f17e1404 | ||
|
3ef32c8ce5 | ||
|
aa761cf7ad | ||
|
5ff3147124 | ||
|
01d4634d86 | ||
|
89904afa63 | ||
|
4907524259 | ||
|
c9f52d3bd9 | ||
|
f5b05ae491 | ||
|
9f88b048d7 | ||
|
d06e92c51c | ||
|
cb2062ae2f | ||
|
07a48e9cc5 | ||
|
800002701d | ||
|
5f0b6cd374 | ||
|
c571ef181b | ||
|
7b0015b2b3 | ||
|
968b582493 | ||
|
1f857a7f85 | ||
|
e2af5c6ea8 | ||
|
548c17a868 | ||
|
5d4e9f8309 | ||
|
044bbba9e3 | ||
|
ab2853956c | ||
|
b259ac76d6 | ||
|
9660242234 | ||
|
9cfed8ec81 | ||
|
c0ec4b8fb7 | ||
|
8e9e0df276 | ||
|
945499290a | ||
|
187636019c | ||
|
d5d80ee1b8 | ||
|
10111878fa | ||
|
ff9a3a16b4 | ||
|
90f51544b7 | ||
|
8492d94054 | ||
|
f207254238 | ||
|
0b79929e1c | ||
|
140c2ccd69 | ||
|
7979999466 | ||
|
5ace213723 | ||
|
7e6e2ff142 | ||
|
162c16362d | ||
|
e12f1f7ec1 | ||
|
babcf76b61 | ||
|
1ba6828ada | ||
|
f47c4d7885 | ||
|
2916b02cf0 |
@@ -10,6 +10,9 @@ charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.xml]
|
||||
insert_final_newline = false
|
||||
|
||||
[*.json]
|
||||
indent_size = 2
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
node_modules/
|
||||
examples/
|
||||
build/
|
||||
static/
|
||||
config/
|
||||
|
34
.eslintrc
34
.eslintrc
@@ -1,34 +1,4 @@
|
||||
{
|
||||
"extends": "airbnb",
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 8,
|
||||
"sourceType": "script",
|
||||
"ecmaFeatures": {
|
||||
"modules": false
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"max-len": 0,
|
||||
"linebreak-style": 0,
|
||||
"no-plusplus": [
|
||||
2,
|
||||
{
|
||||
"allowForLoopAfterthoughts": true
|
||||
}
|
||||
],
|
||||
"no-continue": 0,
|
||||
"indent": [2, "tab"],
|
||||
"no-tabs": 0,
|
||||
"strict": [2, "safe"],
|
||||
"curly": [2, "multi", "consistent"],
|
||||
"import/no-extraneous-dependencies": 0,
|
||||
"import/no-unresolved": 0,
|
||||
"no-underscore-dangle": 0,
|
||||
"no-param-reassign": 0,
|
||||
"generator-star-spacing": 0,
|
||||
"jsx-a11y/href-no-hash": "off"
|
||||
}
|
||||
"extends": "ecollect-base",
|
||||
"root": true
|
||||
}
|
||||
|
23
.github/workflows/CI.yml
vendored
Normal file
23
.github/workflows/CI.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node: [ 18, 20, 22 ]
|
||||
name: Node.js ${{ matrix.node }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
- run: npm ci
|
||||
- run: npm test
|
31
.gitignore
vendored
31
.gitignore
vendored
@@ -1,14 +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
|
||||
*.key
|
||||
*.html
|
||||
|
||||
# Tests temporary
|
||||
.test_tmp
|
||||
|
8
.travis.yml
Normal file
8
.travis.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "16" # maintance lts
|
||||
- "17"
|
||||
- "18" # active lts
|
||||
- "19"
|
||||
- "20" # current
|
||||
after_success: npm run coverage
|
198
CHANGELOG.md
Normal file
198
CHANGELOG.md
Normal file
@@ -0,0 +1,198 @@
|
||||
### Changelog
|
||||
|
||||
#### [v4.2.0]
|
||||
|
||||
- feat: update dependencies [`a03ec22`](https://github.com/node-ebics/node-ebics-client/commit/a03ec2283fdd3dcf750c5ed448f0195d92c5c9f0)
|
||||
- chore: Update dev dependency libxmljs [`3a8dc1d`](https://github.com/node-ebics/node-ebics-client/commit/3a8dc1da0bac20a6f25a687da0a783f3b52d5163)
|
||||
- feat: replace <request> with <rock-req> [`b6b2751`](https://github.com/node-ebics/node-ebics-client/commit/b6b27516d5854b38dcdbe56f23967001f844e631)
|
||||
|
||||
#### [v4.0.0](https://github.com/node-ebics/node-ebics-client/compare/v3.0.0...v0.4.0)
|
||||
|
||||
- Add CI [`#75`](https://github.com/node-ebics/node-ebics-client/pull/75)
|
||||
|
||||
- feat: update dependencies [`a03ec22`](https://github.com/node-ebics/node-ebics-client/commit/a03ec2283fdd3dcf750c5ed448f0195d92c5c9f0)
|
||||
- chore: Update dev dependency libxmljs [`3a8dc1d`](https://github.com/node-ebics/node-ebics-client/commit/3a8dc1da0bac20a6f25a687da0a783f3b52d5163)
|
||||
- feat: replace <request> with <rock-req> [`b6b2751`](https://github.com/node-ebics/node-ebics-client/commit/b6b27516d5854b38dcdbe56f23967001f844e631)
|
||||
|
||||
### [v3.0.0](https://github.com/node-ebics/node-ebics-client/compare/v0.2.1...v3.0.0)
|
||||
|
||||
> 4 August 2022
|
||||
|
||||
- Update LICENSE [`7520a56`](https://github.com/node-ebics/node-ebics-client/commit/7520a56be8ba446d3466c6dc9202b1d65ea3396f)
|
||||
- changelog [`fe0f585`](https://github.com/node-ebics/node-ebics-client/commit/fe0f585b277c390415841a343aa86d4533997057)
|
||||
- chore: update license in package.json, bump version [`b46b214`](https://github.com/node-ebics/node-ebics-client/commit/b46b214e57cf1b4e30455da306b26b3a06dc8a5f)
|
||||
|
||||
#### [v0.2.1](https://github.com/node-ebics/node-ebics-client/compare/v0.2.0...v0.2.1)
|
||||
|
||||
> 30 March 2021
|
||||
|
||||
- bump version [`d0c6d76`](https://github.com/node-ebics/node-ebics-client/commit/d0c6d764318470ef66da9be79d8716c17392f16b)
|
||||
- fix: crypto check [`936e103`](https://github.com/node-ebics/node-ebics-client/commit/936e103c3f36acb697404b4bca4cf2607f3c79e5)
|
||||
|
||||
#### [v0.2.0](https://github.com/node-ebics/node-ebics-client/compare/v0.1.7...v0.2.0)
|
||||
|
||||
> 30 March 2021
|
||||
|
||||
- chore(deps): bump y18n from 4.0.0 to 4.0.1 [`#56`](https://github.com/node-ebics/node-ebics-client/pull/56)
|
||||
- Add additional bank configuration items [`#53`](https://github.com/node-ebics/node-ebics-client/pull/53)
|
||||
- chore(deps): bump xmldom from 0.3.0 to 0.5.0 [`#46`](https://github.com/node-ebics/node-ebics-client/pull/46)
|
||||
- Cryto.js: Nasty workaround for incorrect signature (257 vs 256) and h… [`#50`](https://github.com/node-ebics/node-ebics-client/pull/50)
|
||||
- Examples: Improve config implementation for multibank [`#51`](https://github.com/node-ebics/node-ebics-client/pull/51)
|
||||
- README.md: Add J.P. Morgan to tested banks [`#55`](https://github.com/node-ebics/node-ebics-client/pull/55)
|
||||
- Add support for Bank GPB AO (Gazprombank Russia) [`#49`](https://github.com/node-ebics/node-ebics-client/pull/49)
|
||||
- Add sample code for zipped CAMT statements [`#48`](https://github.com/node-ebics/node-ebics-client/pull/48)
|
||||
|
||||
- chore: changelog [`9ee2be9`](https://github.com/node-ebics/node-ebics-client/commit/9ee2be97c4e7f0921477e3c92c2252c19fb85a7e)
|
||||
- chore: cleanup & bump [`f9fb6d3`](https://github.com/node-ebics/node-ebics-client/commit/f9fb6d3dc94c27a0c983205ce0ef00e4a18f95ff)
|
||||
- merge [`2d580c0`](https://github.com/node-ebics/node-ebics-client/commit/2d580c0d443b0ec0d103a94b64c803bfa1dd6b0b)
|
||||
|
||||
#### [v0.1.7](https://github.com/node-ebics/node-ebics-client/compare/v0.1.6...v0.1.7)
|
||||
|
||||
> 5 February 2021
|
||||
|
||||
- fix high severity vulnerabilities [`#44`](https://github.com/node-ebics/node-ebics-client/pull/44)
|
||||
- chore(deps): bump lodash from 4.17.15 to 4.17.19 [`#39`](https://github.com/node-ebics/node-ebics-client/pull/39)
|
||||
|
||||
- chore: fix dev dependencies voulnarbilities [`d5a24f9`](https://github.com/node-ebics/node-ebics-client/commit/d5a24f9537f676ded8d1996928ed7e76b7b9ba3f)
|
||||
- changelog [`a998538`](https://github.com/node-ebics/node-ebics-client/commit/a998538316c963896c0e7ca76002513f9ea4a01a)
|
||||
- chore: changelog [`a9bbdd9`](https://github.com/node-ebics/node-ebics-client/commit/a9bbdd95c6ce0fdb9cac5452af6fedb4f04b10cb)
|
||||
|
||||
#### [v0.1.6](https://github.com/node-ebics/node-ebics-client/compare/v0.1.4...v0.1.6)
|
||||
|
||||
> 9 May 2020
|
||||
|
||||
- chore(deps): bump acorn from 7.1.0 to 7.1.1 [`#34`](https://github.com/node-ebics/node-ebics-client/pull/34)
|
||||
- feat: Wait until the keys are generated [`#33`](https://github.com/node-ebics/node-ebics-client/pull/33)
|
||||
|
||||
- chore: update deps [`bd11a41`](https://github.com/node-ebics/node-ebics-client/commit/bd11a410f1d2444cdfdfba965df7be37cedcc14a)
|
||||
- chore: update deps [`7053a03`](https://github.com/node-ebics/node-ebics-client/commit/7053a03286c700106bb1988fce72338f51ca9a96)
|
||||
- changelog [`c5e5941`](https://github.com/node-ebics/node-ebics-client/commit/c5e59414f35a9634e12a6b74163f1b7fa6403de5)
|
||||
|
||||
#### [v0.1.4](https://github.com/node-ebics/node-ebics-client/compare/v0.1.3...v0.1.4)
|
||||
|
||||
> 18 December 2019
|
||||
|
||||
- examples: Externalize configuration values and allow for multiple env… [`#28`](https://github.com/node-ebics/node-ebics-client/pull/28)
|
||||
- Add XG1 order type and example [`#29`](https://github.com/node-ebics/node-ebics-client/pull/29)
|
||||
- README.md: Add Bank GPB International S.A. to supported bank list [`#27`](https://github.com/node-ebics/node-ebics-client/pull/27)
|
||||
|
||||
- feat: generalize examples [`f6dfdf4`](https://github.com/node-ebics/node-ebics-client/commit/f6dfdf4c40621d9d6d9bcd64b8698d614307ea61)
|
||||
- examples: Externalize configuration values and allow for multiple environments [`c3d3dec`](https://github.com/node-ebics/node-ebics-client/commit/c3d3decd6a17f733b41ea9f24ed5df8b0b7364f6)
|
||||
- lock [`c7e739f`](https://github.com/node-ebics/node-ebics-client/commit/c7e739f7670856cff5af8fc93a341baf98e01546)
|
||||
|
||||
#### [v0.1.3](https://github.com/node-ebics/node-ebics-client/compare/v0.1.2...v0.1.3)
|
||||
|
||||
> 26 November 2019
|
||||
|
||||
- * Add DKI, C52, C53 order types. [`#26`](https://github.com/node-ebics/node-ebics-client/pull/26)
|
||||
- feat: Add English template & flexible generation [`#24`](https://github.com/node-ebics/node-ebics-client/pull/24)
|
||||
- chore: Various fixes for spelling [`#23`](https://github.com/node-ebics/node-ebics-client/pull/23)
|
||||
|
||||
- test: add additional tests [`6d73ef7`](https://github.com/node-ebics/node-ebics-client/commit/6d73ef77d4454ff966b733f995b64d6dfd7c18b2)
|
||||
- test: add more tests [`67d74cf`](https://github.com/node-ebics/node-ebics-client/commit/67d74cfa0060d97c948bb747885eaba26294663b)
|
||||
- Bank Letter: Add English template & flexible generation [`95403cb`](https://github.com/node-ebics/node-ebics-client/commit/95403cbe6f90c81a696bb589533d713a4ba04873)
|
||||
|
||||
#### [v0.1.2](https://github.com/node-ebics/node-ebics-client/compare/v0.1.1...v0.1.2)
|
||||
|
||||
> 7 November 2019
|
||||
|
||||
- chore: add changelog configoration [`#22`](https://github.com/node-ebics/node-ebics-client/pull/22)
|
||||
- Closes #17 and #13 [`#21`](https://github.com/node-ebics/node-ebics-client/pull/21)
|
||||
- Drop moment dependency [`#20`](https://github.com/node-ebics/node-ebics-client/pull/20)
|
||||
|
||||
- feat: add nyc and cleanup .gitignore [`3e95478`](https://github.com/node-ebics/node-ebics-client/commit/3e95478b3be719c86f32c7df10c42e46b7518669)
|
||||
- feat: drop bn.js [`eea0a49`](https://github.com/node-ebics/node-ebics-client/commit/eea0a49130e30c123b110120c69d7b7c19fd12ba)
|
||||
- add changelog configoration [`1f34dcb`](https://github.com/node-ebics/node-ebics-client/commit/1f34dcbfb6e0febbb93d5356fa36ac57d697a990)
|
||||
|
||||
#### [v0.1.1](https://github.com/node-ebics/node-ebics-client/compare/v0.1.0...v0.1.1)
|
||||
|
||||
> 7 November 2019
|
||||
|
||||
- chore: update license [`9aabe93`](https://github.com/node-ebics/node-ebics-client/commit/9aabe933e91b506ea38820b952ce8e5e58b4c2ff)
|
||||
|
||||
#### [v0.1.0](https://github.com/node-ebics/node-ebics-client/compare/v0.0.36...v0.1.0)
|
||||
|
||||
> 5 November 2019
|
||||
|
||||
- Feat: handle unsual exponent migrate to node-forge [`#16`](https://github.com/node-ebics/node-ebics-client/pull/16)
|
||||
- Add order generation tests and fix linting [`#15`](https://github.com/node-ebics/node-ebics-client/pull/15)
|
||||
- test script run mocha [`#14`](https://github.com/node-ebics/node-ebics-client/pull/14)
|
||||
- chore: readme maintenance [`#11`](https://github.com/node-ebics/node-ebics-client/pull/11)
|
||||
- Provide examples [`#10`](https://github.com/node-ebics/node-ebics-client/pull/10)
|
||||
- * Add Z53 order type [`#7`](https://github.com/node-ebics/node-ebics-client/pull/7)
|
||||
- remove eCollect from constant and minor verbose error handeling [`#2`](https://github.com/node-ebics/node-ebics-client/pull/2)
|
||||
- add iso pain format XCT order type [`#1`](https://github.com/node-ebics/node-ebics-client/pull/1)
|
||||
- remove eCollect from constant and minor verbose error handaling [`#4`](https://github.com/node-ebics/node-ebics-client/pull/4)
|
||||
- add iso pain format XCT order type [`#5`](https://github.com/node-ebics/node-ebics-client/pull/5)
|
||||
- Fix parsing of the bank keys in the HPB response [`#3`](https://github.com/node-ebics/node-ebics-client/pull/3)
|
||||
|
||||
- feat: prepare order generation tests [`e40f79c`](https://github.com/node-ebics/node-ebics-client/commit/e40f79cee68a194272c93f07e763175b213a77a1)
|
||||
- Major changes. Separating responsibilities. Orders builder, serializer. [`ff9a3a1`](https://github.com/node-ebics/node-ebics-client/commit/ff9a3a16b47d0a25674134c875bfd651995837e4)
|
||||
- code optimization [`1876360`](https://github.com/node-ebics/node-ebics-client/commit/187636019c290d757aca77d4c14fb4f2519acd38)
|
||||
|
||||
#### [v0.0.36](https://github.com/node-ebics/node-ebics-client/compare/v0.0.35...v0.0.36)
|
||||
|
||||
> 7 November 2019
|
||||
|
||||
- various modular fixes [`8492d94`](https://github.com/node-ebics/node-ebics-client/commit/8492d940542f61b17aa3a2da7de23f6539ffaad5)
|
||||
|
||||
#### [v0.0.35](https://github.com/node-ebics/node-ebics-client/compare/v0.0.8...v0.0.35)
|
||||
|
||||
> 7 November 2019
|
||||
|
||||
#### [v0.0.8](https://github.com/node-ebics/node-ebics-client/compare/v0.0.7...v0.0.8)
|
||||
|
||||
> 7 November 2019
|
||||
|
||||
- chore: readme maintenance [`#11`](https://github.com/node-ebics/node-ebics-client/pull/11)
|
||||
- Provide examples [`#10`](https://github.com/node-ebics/node-ebics-client/pull/10)
|
||||
|
||||
- initialize.js [`7dad7c8`](https://github.com/node-ebics/node-ebics-client/commit/7dad7c878722be94e03808cef3af38d34019c623)
|
||||
- examples/bankLetter.js [`ce6e58b`](https://github.com/node-ebics/node-ebics-client/commit/ce6e58b3f33017967e5b26fe15a2c435012b8af6)
|
||||
- examples/send-hbt-order.js [`166c61a`](https://github.com/node-ebics/node-ebics-client/commit/166c61aec4a247d923de82278271ec02cbef815f)
|
||||
|
||||
#### [v0.0.7](https://github.com/node-ebics/node-ebics-client/compare/v0.0.6...v0.0.7)
|
||||
|
||||
> 7 November 2019
|
||||
|
||||
- * Add Z53 order type [`#7`](https://github.com/node-ebics/node-ebics-client/pull/7)
|
||||
- remove eCollect from constant and minor verbose error handeling [`#2`](https://github.com/node-ebics/node-ebics-client/pull/2)
|
||||
- add iso pain format XCT order type [`#1`](https://github.com/node-ebics/node-ebics-client/pull/1)
|
||||
|
||||
- add new order type XZ53 and removed repeated dateRange to consts [`5ff3147`](https://github.com/node-ebics/node-ebics-client/commit/5ff314712443c4c8465f46292b010cfedfed8c2e)
|
||||
- move dateRange from constants to utils [`aa761cf`](https://github.com/node-ebics/node-ebics-client/commit/aa761cf7ad87a271d6e6d9eed40e04eb4376f6c5)
|
||||
- bump version [`79f17e1`](https://github.com/node-ebics/node-ebics-client/commit/79f17e14045d121c9505eb3118967f5f88ae79e2)
|
||||
|
||||
#### [v0.0.6](https://github.com/node-ebics/node-ebics-client/compare/v0.0.5...v0.0.6)
|
||||
|
||||
> 7 November 2019
|
||||
|
||||
- remove eCollect from constant and minor verbose error handaling [`#4`](https://github.com/node-ebics/node-ebics-client/pull/4)
|
||||
- add iso pain format XCT order type [`#5`](https://github.com/node-ebics/node-ebics-client/pull/5)
|
||||
|
||||
- remove eCollect from constant and minor verbose error handeling [`cb2062a`](https://github.com/node-ebics/node-ebics-client/commit/cb2062ae2fbd8e8881de26561efddad1f272e065)
|
||||
- bump [`c9f52d3`](https://github.com/node-ebics/node-ebics-client/commit/c9f52d3bd99b9f8761652365b217d9580fa34632)
|
||||
|
||||
#### [v0.0.5](https://github.com/node-ebics/node-ebics-client/compare/v0.0.4...v0.0.5)
|
||||
|
||||
> 7 November 2019
|
||||
|
||||
- Fix parsing of the bank keys in the HPB response [`#3`](https://github.com/node-ebics/node-ebics-client/pull/3)
|
||||
|
||||
- tc for bank keys parsing error [`c571ef1`](https://github.com/node-ebics/node-ebics-client/commit/c571ef181bca2e0cbec70bc6df53c706acd6c829)
|
||||
- #2 corrected bank keys parsing [`5f0b6cd`](https://github.com/node-ebics/node-ebics-client/commit/5f0b6cd3747c4613920d2f71f3c04ce13225d397)
|
||||
|
||||
#### [v0.0.4](https://github.com/node-ebics/node-ebics-client/compare/v0.0.3...v0.0.4)
|
||||
|
||||
> 3 September 2018
|
||||
|
||||
- Major changes. Separating responsibilities. Orders builder, serializer. [`ff9a3a1`](https://github.com/node-ebics/node-ebics-client/commit/ff9a3a16b47d0a25674134c875bfd651995837e4)
|
||||
- code optimization [`1876360`](https://github.com/node-ebics/node-ebics-client/commit/187636019c290d757aca77d4c14fb4f2519acd38)
|
||||
- various modular fixes [`8492d94`](https://github.com/node-ebics/node-ebics-client/commit/8492d940542f61b17aa3a2da7de23f6539ffaad5)
|
||||
|
||||
#### v0.0.3
|
||||
|
||||
> 7 November 2019
|
||||
|
||||
- initial commit [`1f947ff`](https://github.com/node-ebics/node-ebics-client/commit/1f947ff1480c522f89fa1f547581b55e2378d920)
|
||||
- Initial commit [`cd37de3`](https://github.com/node-ebics/node-ebics-client/commit/cd37de3895e32a61798c79ce3a6447e2f269019d)
|
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 eCollect
|
||||
Copyright (c) 2022 Dimitar Nanov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
69
README.md
69
README.md
@@ -1,20 +1,69 @@
|
||||
# node-ebics-client v0.0.3
|
||||
---
|
||||
<p align="center">
|
||||
<img src="assets/logo.png" width="300px" height="auto"/>
|
||||
</p>
|
||||
<h1 align="center">node-ebics-client</h1>
|
||||
|
||||
Pure node.js ( >=8 ) implementation of the [EBICS](https://en.wikipedia.org/wiki/Electronic_Banking_Internet_Communication_Standard) (Electronic Banking Internet Communication).
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/node-ebics/node-ebics-client" title="Build Status"><img src="https://travis-ci.org/node-ebics/node-ebics-client.svg?branch=master" alt="Build Status" /></a>
|
||||
<a href="https://www.npmjs.com/package/ebics-client" title="Build Status">
|
||||
<img alt="ebics-client" src="https://img.shields.io/npm/v/ebics-client">
|
||||
</a>
|
||||
<a href="https://snyk.io/test/github/ecollect/node-ebics-client" title="Known Vulnerabilities">
|
||||
<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>
|
||||
|
||||
The client is aimed to be 100% ISO 20022 complient, and supports complete initilizations process ( INI, HIA, HPB orders ) and HTML letter generation.
|
||||
Pure Node.js (>= 16) implementation of [EBICS](https://en.wikipedia.org/wiki/Electronic_Banking_Internet_Communication_Standard) (Electronic Banking Internet Communication).
|
||||
|
||||
The client is aimed to be 100% [ISO 20022](https://www.iso20022.org) compliant, and supports the complete initializations process (INI, HIA, HPB orders) and HTML letter generation.
|
||||
|
||||
## Usage
|
||||
|
||||
For examples on how to use this library, take a look at the [examples](https://github.com/node-ebics/node-ebics-client/tree/master/examples).
|
||||
|
||||
### A note on recent Node.js versions
|
||||
|
||||
The latest Node.js versions don't support `RSA_PKCS1_PADDING` for private decryption for security reasons, throwing an error like _TypeError: RSA_PKCS1_PADDING is no longer supported for private decryption, this can be reverted with --security-revert=CVE-2023-46809_.
|
||||
|
||||
EBICS requires this mode, so in order for this library to work, add the following parameter when starting Node.js: `--security-revert=CVE-2023-46809`
|
||||
|
||||
### Initialization
|
||||
|
||||
1. Create a configuration (see [example configs](https://github.com/node-ebics/node-ebics-client/tree/master/examples/config)) with the EBICS credentials you received from your bank and name it in this schema: `config.<environment>.<bank>[.<entity>].json` (the entity is optional).
|
||||
|
||||
- The fields `url`, `partnerId`, `userId`, `hostId` are provided by your bank.
|
||||
- The `passphrase` is used to encrypt the keys file, which will be stored at the `storageLocation`.
|
||||
- The `bankName` and `bankShortName` are used internally for creating files and identifying the bank to you.
|
||||
- The `languageCode` is used when creating the Initialization Letter and can be either `de`, `en`, or `fr`.
|
||||
- You can chose any environment, bank and, optionally, entity name. Entities are useful if you have multiple EBICS users for the same bank account.
|
||||
|
||||
2. Run `node examples/initialize.js <environment> <bank> [entity]` to generate your key pair and perform the INI and HIA orders (ie. send the public keys to your bank)
|
||||
The generated keys are stored in the file specified in your config and encrypted with the specified passphrase.
|
||||
3. Run `node examples/bankLetter.js <environment> <bank> [entity]` to generate the Initialization Letter
|
||||
4. Print the letter, sign it and send it to your bank. Wait for them to activate your EBICS account.
|
||||
5. Download the bank keys by running `node examples/save-bank-keys.js <environment> <bank> [entity]`
|
||||
|
||||
If all these steps were executed successfully, you can now do all things EBICS, like fetching bank statements by running `node examples/send-sta-order.js <environment> <bank> [entity]`, or actually use this library in your custom banking applications.
|
||||
|
||||
## Supported Banks
|
||||
The client is tested and verified to work with the following banks:
|
||||
* Credit Suisse
|
||||
* Zürcher Kantonalbank
|
||||
* Raiffeisenbank
|
||||
|
||||
The client is currently tested and verified to work with the following banks:
|
||||
|
||||
- [Credit Suisse (Schweiz) AG](https://www.credit-suisse.com/ch/en.html)
|
||||
- [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)
|
||||
- [Bank GPB AO](https://gazprombank.ru/)
|
||||
- [J.P. Morgan](https://www.jpmorgan.com/)
|
||||
|
||||
## Inspiration
|
||||
|
||||
A lot of the concepts in this library are inspired from the [EPICS](https://github.com/railslove/epics) library.
|
||||
The basic concept of this library was inspired by the [EPICS](https://github.com/railslove/epics) library from the Railslove Team.
|
||||
|
||||
## Copyright
|
||||
Copyright (c) 2017 eCollect.
|
||||
|
||||
Copyright: Dimitar Nanov, 2019-2022.
|
||||
Licensed under the [MIT](LICENSE) license.
|
||||
|
BIN
assets/logo.png
Normal file
BIN
assets/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.0 KiB |
25
changelog-template.hbs
Normal file
25
changelog-template.hbs
Normal 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}}
|
25
examples/bankLetter.js
Executable file
25
examples/bankLetter.js
Executable file
@@ -0,0 +1,25 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const ebics = require('../index');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
|
||||
const config = require('./loadConfig')();
|
||||
const client = require('./getClient')(config);
|
||||
const bankName = client.bankName;
|
||||
const template = fs.readFileSync("./templates/ini_"+client.languageCode+".hbs", { encoding: 'utf8'});
|
||||
const bankLetterFile = path.join("./", "bankLetter_"+client.bankShortName+"_"+client.languageCode+".html");
|
||||
|
||||
const letter = new ebics.BankLetter({ client, bankName, template });
|
||||
|
||||
letter.serialize(bankLetterFile)
|
||||
.then(() => {
|
||||
console.log('Send your bank the letter (%s)', bankLetterFile);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
12
examples/config/config.json
Normal file
12
examples/config/config.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"url": "https://ebics-test.server",
|
||||
"partnerId": "EBICS ParnerID Test",
|
||||
"userId": "MyUserIdTest",
|
||||
"hostId": "MyHostIdTest",
|
||||
"passphrase": "MyPasswordTest",
|
||||
"keyStoragePath": "./keys-test",
|
||||
"bankName":"Test Bank Full Name",
|
||||
"bankShortName":"TESTBANKSHORT",
|
||||
"languageCode":"en",
|
||||
"storageLocation":"\\\\myserver\\Share\\Folder\\BankName\\Test\\"
|
||||
}
|
12
examples/config/config.production.testbank.json
Normal file
12
examples/config/config.production.testbank.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"url": "https://ebics.server",
|
||||
"partnerId": "EBICS ParnerID Production",
|
||||
"userId": "MyUserIdProduction",
|
||||
"hostId": "MyHostIdProduction",
|
||||
"passphrase": "MyPasswordProduction",
|
||||
"keyStoragePath": "./keys-prod",
|
||||
"bankName":"Production Bank Full Name",
|
||||
"bankShortName":"PRODBANKSHORT",
|
||||
"languageCode":"en",
|
||||
"storageLocation":"\\\\myserver\\Share\\Folder\\BankName\\Production\\"
|
||||
}
|
12
examples/config/config.production.testbank.testentity.json
Normal file
12
examples/config/config.production.testbank.testentity.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"url": "https://ebics.server",
|
||||
"partnerId": "EBICS ParnerID Production",
|
||||
"userId": "MyUserIdProduction",
|
||||
"hostId": "MyHostIdProduction",
|
||||
"passphrase": "MyPasswordProduction",
|
||||
"keyStoragePath": "./keys-prod",
|
||||
"bankName":"Production Bank Full Name",
|
||||
"bankShortName":"PRODBANKSHORT",
|
||||
"languageCode":"en",
|
||||
"storageLocation":"\\\\myserver\\Share\\Folder\\BankName\\Production\\"
|
||||
}
|
23
examples/getClient.js
Normal file
23
examples/getClient.js
Normal file
@@ -0,0 +1,23 @@
|
||||
'use strict';
|
||||
|
||||
const { Client, fsKeysStorage } = require('../index');
|
||||
|
||||
const loadConfig = require('./loadConfig');
|
||||
|
||||
module.exports = ({
|
||||
url,
|
||||
partnerId,
|
||||
userId,
|
||||
hostId,
|
||||
passphrase,
|
||||
iv,
|
||||
keyStoragePath,
|
||||
} = loadConfig()) => new Client({
|
||||
url,
|
||||
partnerId,
|
||||
userId,
|
||||
hostId,
|
||||
passphrase,
|
||||
iv,
|
||||
keyStorage: fsKeysStorage(keyStoragePath),
|
||||
});
|
27
examples/initialize.js
Executable file
27
examples/initialize.js
Executable file
@@ -0,0 +1,27 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
|
||||
const ebics = require('../index');
|
||||
|
||||
const client = require('./getClient')();
|
||||
const { Orders } = require('../index');
|
||||
|
||||
// New keys will be generated and saved in ./keys-test
|
||||
client.send(Orders.INI)
|
||||
.then((resp) => {
|
||||
console.log('Response for INI order %j', resp);
|
||||
return client.send(ebics.Orders.HIA);
|
||||
})
|
||||
.then((resp) => {
|
||||
console.log('Response for HIA order %j', resp);
|
||||
if (resp.technicalCode !== '000000')
|
||||
throw new Error('Something might went wrong');
|
||||
|
||||
console.log('Public keys should be sent to bank now. See examples/bankLetter.js');
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
46
examples/loadConfig.js
Normal file
46
examples/loadConfig.js
Normal file
@@ -0,0 +1,46 @@
|
||||
'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 getBankIdentifier = () => {
|
||||
const [,,,parArg] = process.argv;
|
||||
return parArg || "testbank";
|
||||
}
|
||||
|
||||
const getEntityIdentifier = () => {
|
||||
const [,,,,parArg] = process.argv;
|
||||
return parArg || ""
|
||||
}
|
||||
|
||||
const loadConfig = (configDirectory = path.join(__dirname, './config'), env = getDefaultEnv(), bank = getBankIdentifier(), entity = getEntityIdentifier()) => {
|
||||
entity ? console.log(`Loading config from ${configDirectory} with env set to ${env}, bank set to ${bank} and entity set to ${entity}.`) : console.log(`Loading config from ${configDirectory} with env set to ${env} and bank set to ${bank}.`);
|
||||
|
||||
global.entity = entity;
|
||||
const baseConfigFile = path.join(configDirectory, 'config.json');
|
||||
const envConfigFile = env ? entity ? path.join(configDirectory, `config.${env}.${bank}.${entity}.json`) : path.join(configDirectory, `config.${env}.${bank}.json`) : null;
|
||||
|
||||
return {
|
||||
...safeLoadJson(baseConfigFile),
|
||||
...safeLoadJson(envConfigFile),
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = loadConfig;
|
22
examples/save-bank-keys.js
Normal file
22
examples/save-bank-keys.js
Normal file
@@ -0,0 +1,22 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const client = require('./getClient')();
|
||||
const { Orders } = require('../index');
|
||||
|
||||
// Client keys must be already generated and send by letter.
|
||||
// The bank should have enabled the user
|
||||
client.send(Orders.HPB)
|
||||
.then((resp) => {
|
||||
console.log('Response for HPB order %j', resp);
|
||||
if (resp.technicalCode !== '000000')
|
||||
throw new Error('Something went wrong');
|
||||
|
||||
console.log('Received bank keys: %j', resp.bankKeys);
|
||||
return client.setBankKeys(resp.bankKeys);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
28
examples/send-c52-order-zipped.js
Normal file
28
examples/send-c52-order-zipped.js
Normal file
@@ -0,0 +1,28 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
const client = require('./getClient')();
|
||||
const { Orders } = require('../index');
|
||||
|
||||
// The bank keys must have been already saved
|
||||
client.send(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);
|
||||
let distPath = "CAMT052.zip";
|
||||
const dstZip = fs.createWriteStream(distPath);
|
||||
dstZip.write(data);
|
||||
dstZip.end();
|
||||
})
|
||||
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
22
examples/send-c52-order.js
Normal file
22
examples/send-c52-order.js
Normal file
@@ -0,0 +1,22 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const client = require('./getClient')();
|
||||
const { Orders } = require('../index');
|
||||
|
||||
// The bank keys must have been already saved
|
||||
client.send(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);
|
||||
});
|
28
examples/send-c53-order-zipped.js
Normal file
28
examples/send-c53-order-zipped.js
Normal file
@@ -0,0 +1,28 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
const client = require('./getClient')();
|
||||
const { Orders } = require('../index');
|
||||
|
||||
// The bank keys must have been already saved
|
||||
client.send(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);
|
||||
let distPath = "CAMT053.zip";
|
||||
const dstZip = fs.createWriteStream(distPath);
|
||||
dstZip.write(data);
|
||||
dstZip.end();
|
||||
})
|
||||
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
22
examples/send-c53-order.js
Normal file
22
examples/send-c53-order.js
Normal file
@@ -0,0 +1,22 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const client = require('./getClient')();
|
||||
const { Orders } = require('../index');
|
||||
|
||||
// The bank keys must have been already saved
|
||||
client.send(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);
|
||||
});
|
22
examples/send-dki-order.js
Normal file
22
examples/send-dki-order.js
Normal file
@@ -0,0 +1,22 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const client = require('./getClient')();
|
||||
const { Orders } = require('../index');
|
||||
|
||||
// The bank keys must have been already saved
|
||||
client.send(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);
|
||||
});
|
28
examples/send-g02-order-zipped.js
Normal file
28
examples/send-g02-order-zipped.js
Normal file
@@ -0,0 +1,28 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
const client = require('./getClient')();
|
||||
const { Orders } = require('../index');
|
||||
|
||||
// The bank keys must have been already saved
|
||||
client.send(Orders.G02(null, null)) // startDate 'YYYY-MM-DD', endDate 'YYYY-MM-DD'
|
||||
.then((resp) => {
|
||||
console.log('Response for G02 order %j', resp);
|
||||
if (resp.technicalCode !== '000000')
|
||||
throw new Error('Something went wrong');
|
||||
|
||||
// Parsing and processing the G02 Pain.002.001.06 file should happen somewhere here, ideally after saving it to disk
|
||||
const data = Buffer.from(resp.orderData);
|
||||
let distPath = "G02.zip";
|
||||
const dstZip = fs.createWriteStream(distPath);
|
||||
dstZip.write(data);
|
||||
dstZip.end();
|
||||
})
|
||||
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
20
examples/send-g1r-order.js
Normal file
20
examples/send-g1r-order.js
Normal file
@@ -0,0 +1,20 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
const client = require('./getClient')();
|
||||
const { Orders } = require('../index');
|
||||
|
||||
// The bank keys must have been already saved
|
||||
const paymentFile = fs.readFileSync('RUB_PAYMENT.xml').toString();
|
||||
|
||||
client.send(Orders.G1R(paymentFile))
|
||||
.then((resp) => {
|
||||
console.log('Response for G1R order %j', resp);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
20
examples/send-g1v-order.js
Normal file
20
examples/send-g1v-order.js
Normal file
@@ -0,0 +1,20 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
const client = require('./getClient')();
|
||||
const { Orders } = require('../index');
|
||||
|
||||
// The bank keys must have been already saved
|
||||
const paymentFile = fs.readFileSync('FCY_PAYMENT.xml').toString();
|
||||
|
||||
client.send(Orders.G1V(paymentFile))
|
||||
.then((resp) => {
|
||||
console.log('Response for G1V order %j', resp);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
28
examples/send-g52-order-zipped.js
Normal file
28
examples/send-g52-order-zipped.js
Normal file
@@ -0,0 +1,28 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
const client = require('./getClient')();
|
||||
const { Orders } = require('../index');
|
||||
|
||||
// The bank keys must have been already saved
|
||||
client.send(Orders.G52(null, null)) // startDate 'YYYY-MM-DD', endDate 'YYYY-MM-DD'
|
||||
.then((resp) => {
|
||||
console.log('Response for G52 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);
|
||||
let distPath = "CAMT052-G52.zip";
|
||||
const dstZip = fs.createWriteStream(distPath);
|
||||
dstZip.write(data);
|
||||
dstZip.end();
|
||||
})
|
||||
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
28
examples/send-g53-order-zipped.js
Normal file
28
examples/send-g53-order-zipped.js
Normal file
@@ -0,0 +1,28 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
const client = require('./getClient')();
|
||||
const { Orders } = require('../index');
|
||||
|
||||
// The bank keys must have been already saved
|
||||
client.send(Orders.G53(null, null)) // startDate 'YYYY-MM-DD', endDate 'YYYY-MM-DD'
|
||||
.then((resp) => {
|
||||
console.log('Response for G53 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);
|
||||
let distPath = "CAMT053-G53.zip";
|
||||
const dstZip = fs.createWriteStream(distPath);
|
||||
dstZip.write(data);
|
||||
dstZip.end();
|
||||
})
|
||||
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
21
examples/send-hkd-order.js
Normal file
21
examples/send-hkd-order.js
Normal file
@@ -0,0 +1,21 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const client = require('./getClient')();
|
||||
const { Orders } = require('../index');
|
||||
|
||||
// The bank keys must have been already saved
|
||||
client.send(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);
|
||||
});
|
21
examples/send-htd-order.js
Normal file
21
examples/send-htd-order.js
Normal file
@@ -0,0 +1,21 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const client = require('./getClient')();
|
||||
const { Orders } = require('../index');
|
||||
|
||||
// The bank keys must have been already saved
|
||||
client.send(Orders.HTD)
|
||||
.then((resp) => {
|
||||
console.log('Response for HTD 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);
|
||||
});
|
22
examples/send-sta-order.js
Normal file
22
examples/send-sta-order.js
Normal file
@@ -0,0 +1,22 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const client = require('./getClient')();
|
||||
const { Orders } = require('../index');
|
||||
|
||||
// The bank keys must have been already saved
|
||||
client.send(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);
|
||||
});
|
23
examples/send-vmk-order.js
Normal file
23
examples/send-vmk-order.js
Normal file
@@ -0,0 +1,23 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const client = require('./getClient')();
|
||||
const { Orders } = require('../index');
|
||||
|
||||
|
||||
// The bank keys must have been already saved
|
||||
client.send(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);
|
||||
});
|
21
examples/send-xg1-order.js
Normal file
21
examples/send-xg1-order.js
Normal file
@@ -0,0 +1,21 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const ebics = require('../index');
|
||||
const fs = require('fs');
|
||||
|
||||
const client = require('./getClient')();
|
||||
const { Orders } = require('../index');
|
||||
|
||||
// The bank keys must have been already saved
|
||||
const paymentFile = fs.readFileSync('mytestfile.xml').toString();
|
||||
|
||||
client.send(Orders.XG1(paymentFile))
|
||||
.then((resp) => {
|
||||
console.log('Response for XG1 order %j', resp);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
13
index.js
13
index.js
@@ -1,4 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
const Client = require('./lib/Client');
|
||||
module.exports = Client;
|
||||
const Orders = require('./lib/predefinedOrders');
|
||||
const fsKeysStorage = require('./lib/storages/fsKeysStorage');
|
||||
const tracesStorage = require('./lib/storages/tracesStorage');
|
||||
const BankLetter = require('./lib/BankLetter');
|
||||
|
||||
module.exports = {
|
||||
Client,
|
||||
Orders,
|
||||
BankLetter,
|
||||
fsKeysStorage,
|
||||
tracesStorage,
|
||||
};
|
||||
|
@@ -2,65 +2,66 @@
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
const moment = require('moment');
|
||||
const handlebars = require('handlebars');
|
||||
const BN = require("bn.js");
|
||||
const Crypto = require('./crypto/Crypto');
|
||||
const { date } = require('./utils.js');
|
||||
|
||||
const registerHelpers = () => {
|
||||
handlebars.registerHelper('today', () => date.toISODate(Date.now(), false));
|
||||
|
||||
handlebars.registerHelper('now', () => date.toISOTime(Date.now(), false));
|
||||
|
||||
handlebars.registerHelper('keyExponentBits', k => Buffer.byteLength(k.e()) * 8);
|
||||
|
||||
handlebars.registerHelper('keyModulusBits', k => k.size());
|
||||
|
||||
handlebars.registerHelper('keyExponent', k => k.e('hex'));
|
||||
|
||||
handlebars.registerHelper('keyModulus', k => k.n('hex').toUpperCase().match(/.{1,2}/g).join(' '));
|
||||
|
||||
handlebars.registerHelper('sha256', (k) => {
|
||||
const digest = Buffer.from(Crypto.digestPublicKey(k), 'base64').toString('HEX');
|
||||
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, bankName) {
|
||||
this.client = client;
|
||||
this.bankName = bankName;
|
||||
this.pathToTemplate = './app/ebics/ini.hbs';
|
||||
};
|
||||
constructor({
|
||||
client,
|
||||
bankName,
|
||||
template,
|
||||
}) {
|
||||
this.client = client;
|
||||
this.bankName = bankName;
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
_registerHelpers() {
|
||||
handlebars.registerHelper("today", () => {
|
||||
return moment().format('DD.MM.YYYY');
|
||||
});
|
||||
async generate() {
|
||||
registerHelpers();
|
||||
|
||||
handlebars.registerHelper("now", () => {
|
||||
return moment().format('HH:mm:ss');
|
||||
});
|
||||
|
||||
handlebars.registerHelper("keyExponentBits", (k) => {
|
||||
return Buffer.byteLength(new BN(k.key.keyPair.e).toBuffer()) * 8;
|
||||
});
|
||||
|
||||
handlebars.registerHelper("keyModulusBits", (k) => {
|
||||
return k.key.getKeySize();
|
||||
// return Buffer.byteLength(new BN(k.key.keyPair.e).toBuffer()) * 8;
|
||||
});
|
||||
|
||||
handlebars.registerHelper("keyExponent", (k) => {
|
||||
return k.e();
|
||||
});
|
||||
|
||||
handlebars.registerHelper("keyModulus", (k) => {
|
||||
return k.n().toUpperCase().match(/.{1,2}/g).join(' ');
|
||||
});
|
||||
|
||||
handlebars.registerHelper("sha256", (k) => {
|
||||
const digest = Buffer(k.publicDigest(), 'base64').toString('HEX');
|
||||
|
||||
return digest.toUpperCase().match(/.{1,2}/g).join(' ');
|
||||
});
|
||||
};
|
||||
|
||||
generate() {
|
||||
this._registerHelpers();
|
||||
|
||||
const str = fs.readFileSync(this.pathToTemplate).toString();
|
||||
const templ = handlebars.compile(str);
|
||||
const templ = handlebars.compile(this.template);
|
||||
const keys = await this.client.keys();
|
||||
|
||||
const data = {
|
||||
bankName : this.bankName,
|
||||
userId : this.client.userId,
|
||||
bankName: this.bankName,
|
||||
userId: this.client.userId,
|
||||
partnerId: this.client.partnerId,
|
||||
A006 : this.client.a(),
|
||||
X002 : this.client.x(),
|
||||
E002 : this.client.e(),
|
||||
A006: keys.a(),
|
||||
X002: keys.x(),
|
||||
E002: keys.e(),
|
||||
};
|
||||
|
||||
return templ(data);
|
||||
}
|
||||
}
|
||||
|
||||
async serialize(path) {
|
||||
const letter = await this.generate();
|
||||
await writeFile(path, letter);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
416
lib/Client.js
416
lib/Client.js
@@ -1,233 +1,281 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require("fs");
|
||||
const crypto = require("crypto");
|
||||
const $request = require("request");
|
||||
const rock = require('rock-req');
|
||||
|
||||
const BN = require('bn.js');
|
||||
const xpath = require("xpath");
|
||||
const NodeRSA = require("node-rsa");
|
||||
const constants = require('./consts');
|
||||
const Keys = require('./keymanagers/Keys');
|
||||
const defaultKeyEncryptor = require('./keymanagers/defaultKeyEncryptor');
|
||||
|
||||
const signer = require('./middleware/signer');
|
||||
const serializer = require('./middleware/serializer');
|
||||
const response = require('./middleware/response');
|
||||
|
||||
const Key = require('./Key');
|
||||
const XMLSign = require('./middleware/XMLSign');
|
||||
const ParseResponse = require('./middleware/ParseResponse');
|
||||
const BankLetter = require('./BankLetter');
|
||||
const EBICSINI = require('./orders/INI');
|
||||
const EBICSHIA = require('./orders/HIA');
|
||||
const EBICSHPB = require('./orders/HPB');
|
||||
const EBICSHKD = require('./orders/HKD');
|
||||
const EBICSHAA = require('./orders/HAA');
|
||||
const EBICSHAC = require('./orders/HAC');
|
||||
const EBICSHTD = require('./orders/HTD');
|
||||
const EBICSC52 = require('./orders/C52');
|
||||
const stringifyKeys = (keys) => {
|
||||
Object.keys(keys).map((key) => {
|
||||
keys[key] = keys[key] === null ? null : keys[key].toPem();
|
||||
return key;
|
||||
});
|
||||
|
||||
const utils = {
|
||||
exponent: {
|
||||
// str = 65537 => AQAB
|
||||
toBase64(str) {
|
||||
return new BN(str).toBuffer().toString('base64');
|
||||
},
|
||||
// str = AQAB => 65537
|
||||
fromBase64(str) {
|
||||
return new BN(Buffer.from(str, 'base64'), 2).toNumber();
|
||||
}
|
||||
}
|
||||
}
|
||||
return JSON.stringify(keys);
|
||||
};
|
||||
|
||||
/**
|
||||
* Keys persistent object
|
||||
* @typedef {Object} KeysObject
|
||||
* @property {string} A006 - PEM representation of the A006 private key
|
||||
* @property {string} E002 - PEM representation of the E002 private key
|
||||
* @property {string} X002 - PEM representation of the X002 private key
|
||||
* @property {string} bankX002 - PEM representation of the bankX002 public key
|
||||
* @property {string} bankE002 - PEM representation of the bankE002 public key
|
||||
*/
|
||||
|
||||
/**
|
||||
* Key storage implementation
|
||||
* @typedef {Object} KeyStorage
|
||||
* @property {(data: KeysObject):Promise<void>} write - writes the keys to storage
|
||||
* @property {():Promise<KeysObject>} read - reads the keys from storage
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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|Buffer} passphrase - passphrase or key for keys encryption
|
||||
* @property {string|Buffer} iv - Initialization Vector for keys encryption
|
||||
* @property {KeyStorage} keyStorage - keyStorage implementation
|
||||
* @property {object} [tracesStorage] - traces (logs) storage implementation
|
||||
* @property {string} bankName - Full name of the bank to be used in the bank INI letters.
|
||||
* @property {string} bankShortName - Short name of the bank to be used in folders, filenames etc.
|
||||
* @property {string} languageCode - Language code to be used in the bank INI letters ("de", "en" and "fr" are currently supported).
|
||||
* @property {string} storageLocation - Location where to store the files that are downloaded. This can be a network share for example.
|
||||
*/
|
||||
module.exports = class Client {
|
||||
constructor(keysContent, passphrase, url, hostId, userId, partnerId) {
|
||||
this.keysContent = keysContent;
|
||||
this.passphrase = passphrase;
|
||||
this.url = url;
|
||||
this.hostId = hostId;
|
||||
this.userId = userId;
|
||||
this.partnerId = partnerId;
|
||||
this.encryptAlgorithm = 'aes-256-cbc';
|
||||
this.keys = keysContent ? this.extractKeys() : {};
|
||||
};
|
||||
/**
|
||||
*Creates an instance of Client.
|
||||
* @param {EbicClientOptions} clientOptions
|
||||
*/
|
||||
constructor({
|
||||
url,
|
||||
partnerId,
|
||||
userId,
|
||||
hostId,
|
||||
passphrase,
|
||||
iv,
|
||||
keyStorage,
|
||||
tracesStorage,
|
||||
bankName,
|
||||
bankShortName,
|
||||
languageCode,
|
||||
storageLocation,
|
||||
}) {
|
||||
if (!url) throw new Error('EBICS URL is required');
|
||||
if (!partnerId) throw new Error('partnerId is required');
|
||||
if (!userId) throw new Error('userId is required');
|
||||
if (!hostId) throw new Error('hostId is required');
|
||||
if (!passphrase) throw new Error('passphrase is required');
|
||||
|
||||
a() {
|
||||
return this.keys["A006"];
|
||||
};
|
||||
if (
|
||||
!keyStorage
|
||||
|| typeof keyStorage.read !== 'function'
|
||||
|| typeof keyStorage.write !== 'function'
|
||||
)
|
||||
throw new Error('keyStorage implementation missing or wrong');
|
||||
|
||||
e() {
|
||||
return this.keys["E002"];
|
||||
};
|
||||
|
||||
x() {
|
||||
return this.keys["X002"];
|
||||
this.url = url;
|
||||
this.partnerId = partnerId;
|
||||
this.userId = userId;
|
||||
this.hostId = hostId;
|
||||
this.keyStorage = keyStorage;
|
||||
this.keyEncryptor = defaultKeyEncryptor({ passphrase, iv });
|
||||
this.tracesStorage = tracesStorage || null;
|
||||
this.bankName = bankName || 'Dummy Bank Full Name';
|
||||
this.bankShortName = bankShortName || 'BANKSHORTCODE';
|
||||
this.languageCode = languageCode || 'en';
|
||||
this.storageLocation = storageLocation || null;
|
||||
}
|
||||
|
||||
bankX() {
|
||||
return this.keys[`${this.hostId}.X002`];
|
||||
async send(order) {
|
||||
const isInObject = 'operation' in order;
|
||||
|
||||
if (!isInObject) throw new Error('Operation for the order needed');
|
||||
|
||||
if (order.operation.toUpperCase() === constants.orderOperations.ini)
|
||||
return this.initialization(order);
|
||||
|
||||
const keys = await this.keys();
|
||||
if (keys === null)
|
||||
throw new Error(
|
||||
'No keys provided. Can not send the order or any other order for that matter.',
|
||||
);
|
||||
|
||||
if (order.operation.toUpperCase() === constants.orderOperations.upload)
|
||||
return this.upload(order);
|
||||
if (
|
||||
order.operation.toUpperCase() === constants.orderOperations.download
|
||||
)
|
||||
return this.download(order);
|
||||
|
||||
throw new Error('Wrong order operation provided');
|
||||
}
|
||||
|
||||
bankE() {
|
||||
return this.keys[`${this.hostId}.E002`];
|
||||
}
|
||||
async initialization(order) {
|
||||
const keys = await this.keys();
|
||||
if (keys === null) await this._generateKeys();
|
||||
|
||||
encrypt(data) {
|
||||
const cipher = crypto.createCipher(this.encryptAlgorithm, this.passphrase);
|
||||
const encrypted = cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
|
||||
if (this.tracesStorage) this.tracesStorage.new().ofType('ORDER.INI');
|
||||
const res = await this.ebicsRequest(order);
|
||||
const xml = res.orderData();
|
||||
|
||||
return Buffer.from(encrypted).toString('base64');
|
||||
};
|
||||
const returnedTechnicalCode = res.technicalCode();
|
||||
const returnedBusinessCode = res.businessCode();
|
||||
|
||||
decrypt(data) {
|
||||
data = (new Buffer(data, 'base64')).toString();
|
||||
return {
|
||||
orderData: xml.length ? xml.toString() : xml,
|
||||
orderId: res.orderId(),
|
||||
|
||||
const decipher = crypto.createDecipher(this.encryptAlgorithm, this.passphrase);
|
||||
const decrypted = decipher.update(data, 'hex', 'utf8') + decipher.final('utf8');
|
||||
technicalCode: returnedTechnicalCode,
|
||||
technicalCodeSymbol: res.technicalSymbol(),
|
||||
technicalCodeShortText: res.technicalShortText(
|
||||
returnedTechnicalCode,
|
||||
),
|
||||
technicalCodeMeaning: res.technicalMeaning(returnedTechnicalCode),
|
||||
|
||||
return decrypted;
|
||||
};
|
||||
businessCode: returnedBusinessCode,
|
||||
businessCodeSymbol: res.businessSymbol(returnedBusinessCode),
|
||||
businessCodeShortText: res.businessShortText(returnedBusinessCode),
|
||||
businessCodeMeaning: res.businessMeaning(returnedBusinessCode),
|
||||
|
||||
static setup(passphrase, url, hostId, userId, partnerId, keysize = 2048) {
|
||||
const client = new Client(null, passphrase, url, hostId, userId, partnerId);
|
||||
|
||||
for (let key in {A006: '', X002: '', E002: ''}) {
|
||||
client.keys[key] = new Key(new NodeRSA({ b: keysize }));
|
||||
}
|
||||
|
||||
return client;
|
||||
};
|
||||
|
||||
saveIniLetter(bankName, path) {
|
||||
const letter = new BankLetter(this, bankName);
|
||||
|
||||
try {
|
||||
fs.writeFileSync(path, letter.generate());
|
||||
console.log("Data written to file");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
saveKeys(path) {
|
||||
const data = {};
|
||||
|
||||
for (let key in this.keys) {
|
||||
data[key] = this.encrypt(this.keys[key].toPem());
|
||||
bankKeys: res.bankKeys(),
|
||||
};
|
||||
|
||||
try {
|
||||
fs.writeFileSync(path, JSON.stringify(data));
|
||||
console.log("Data written to file");
|
||||
} catch(error) {
|
||||
console.log(error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
extractKeys() {
|
||||
const keys = {};
|
||||
const jsonData = JSON.parse(this.keysContent);
|
||||
|
||||
for (let key in jsonData) {
|
||||
keys[key] = new Key(this.decrypt(jsonData[key]));
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
async download(order) {
|
||||
const res = await this.ebicsRequest(order.toXML());
|
||||
|
||||
const ttt = res.toXML(); // keep this for debugging purposes
|
||||
if (this.tracesStorage)
|
||||
this.tracesStorage.new().ofType('ORDER.DOWNLOAD');
|
||||
const res = await this.ebicsRequest(order);
|
||||
|
||||
order.transactionId = res.transactionId();
|
||||
|
||||
if (res.isSegmented() && res.isLastSegment()) {
|
||||
const receipt = await this.ebicsRequest(order.toReceiptXML());
|
||||
if (this.tracesStorage)
|
||||
this.tracesStorage.connect().ofType('RECEIPT.ORDER.DOWNLOAD');
|
||||
|
||||
const receiptXML = order.toReceiptXML(); // keep this for debugging purposes
|
||||
const rX = receipt.toXML(); // keep this for debugging purposes
|
||||
await this.ebicsRequest(order);
|
||||
}
|
||||
|
||||
return res.orderData();
|
||||
};
|
||||
const returnedTechnicalCode = res.technicalCode();
|
||||
const returnedBusinessCode = res.businessCode();
|
||||
|
||||
async downloadAndUnzip(order) {
|
||||
return {
|
||||
orderData: res.orderData(),
|
||||
orderId: res.orderId(),
|
||||
|
||||
technicalCode: returnedTechnicalCode,
|
||||
technicalCodeSymbol: res.technicalSymbol(),
|
||||
technicalCodeShortText: res.technicalShortText(
|
||||
returnedTechnicalCode,
|
||||
),
|
||||
technicalCodeMeaning: res.technicalMeaning(returnedTechnicalCode),
|
||||
|
||||
businessCode: returnedBusinessCode,
|
||||
businessCodeSymbol: res.businessSymbol(returnedBusinessCode),
|
||||
businessCodeShortText: res.businessShortText(returnedBusinessCode),
|
||||
businessCodeMeaning: res.businessMeaning(returnedBusinessCode),
|
||||
};
|
||||
}
|
||||
|
||||
async upload(order) {
|
||||
if (this.tracesStorage) this.tracesStorage.new().ofType('ORDER.UPLOAD');
|
||||
let res = await this.ebicsRequest(order);
|
||||
const transactionId = res.transactionId();
|
||||
const orderId = res.orderId();
|
||||
|
||||
order.transactionId = transactionId;
|
||||
|
||||
if (this.tracesStorage)
|
||||
this.tracesStorage.connect().ofType('TRANSFER.ORDER.UPLOAD');
|
||||
res = await this.ebicsRequest(order);
|
||||
|
||||
return [transactionId, orderId];
|
||||
}
|
||||
|
||||
ebicsRequest(order) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const bbb = XMLSign.go(this, order);
|
||||
$request.post({
|
||||
url : this.url,
|
||||
body : bbb,
|
||||
headers: { 'Content-Type': 'text/xml' }
|
||||
}, (err, res, data) => {
|
||||
const b = data; // keep this for debugging purposes
|
||||
const r = ParseResponse.go(this, data); // keep this for debugging purposes
|
||||
const rXML = r.toXML(); // keep this for debugging purposes
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const { version } = order;
|
||||
const keys = await this.keys();
|
||||
const r = signer
|
||||
.version(version)
|
||||
.sign((await serializer.use(order, this)).toXML(), keys.x());
|
||||
|
||||
return err ? reject(err): resolve(ParseResponse.go(this, data));
|
||||
if (this.tracesStorage)
|
||||
this.tracesStorage
|
||||
.label(`REQUEST.${order.orderDetails.OrderType}`)
|
||||
.data(r)
|
||||
.persist();
|
||||
|
||||
rock({
|
||||
method: 'POST',
|
||||
url: this.url,
|
||||
body: r,
|
||||
headers: { 'content-type': 'text/xml;charset=UTF-8' },
|
||||
},
|
||||
(err, res, data) => {
|
||||
if (err) reject(err);
|
||||
|
||||
const ebicsResponse = response.version(version)(data.toString('utf-8'), keys);
|
||||
|
||||
if (this.tracesStorage)
|
||||
this.tracesStorage
|
||||
.label(`RESPONSE.${order.orderDetails.OrderType}`)
|
||||
.connect()
|
||||
.data(ebicsResponse.toXML())
|
||||
.persist();
|
||||
|
||||
resolve(ebicsResponse);
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
async INI() {
|
||||
return this.ebicsRequest((new EBICSINI(this)).toXML());
|
||||
};
|
||||
async signOrder(order) {
|
||||
const { version } = order;
|
||||
const keys = await this.keys();
|
||||
return signer
|
||||
.version(version)
|
||||
.sign((await serializer.use(order, this)).toXML(), keys.x());
|
||||
}
|
||||
|
||||
async HIA() {
|
||||
return this.ebicsRequest((new EBICSHIA(this)).toXML());
|
||||
};
|
||||
|
||||
async HPB() {
|
||||
const data = await this.download(new EBICSHPB(this));
|
||||
|
||||
const doc = new DOMParser().parseFromString(data, 'text/xml');
|
||||
const sel = xpath.useNamespaces({'xmlns': "urn:org:ebics:H004"});
|
||||
const keyNodes = sel("//xmlns:PubKeyValue", doc);
|
||||
// console.log(keyNodes);
|
||||
|
||||
function xmlLastChild (node) {
|
||||
let y = node.lastChild;
|
||||
|
||||
while (y.nodeType != 1) y = y.previousSibling;
|
||||
|
||||
return y;
|
||||
};
|
||||
|
||||
for (let i = 0; i < keyNodes.length; i++) {
|
||||
const type = xmlLastChild(keyNodes[i].parentNode).textContent;
|
||||
const modulus = xpath.select("//*[local-name(.)='Modulus']", keyNodes[i])[0].textContent;
|
||||
const exponent = xpath.select("//*[local-name(.)='Exponent']", keyNodes[i])[0].textContent;
|
||||
|
||||
const mod = new BN(Buffer.from(modulus, 'base64'), 2).toBuffer();
|
||||
const exp = utils.exponent.fromBase64(exponent);
|
||||
|
||||
const bank = new NodeRSA();
|
||||
|
||||
bank.importKey({ n: mod, e: exp }, 'components-public');
|
||||
|
||||
this.keys[`${this.hostId}.${type}`] = new Key(bank);
|
||||
async keys() {
|
||||
try {
|
||||
const keysString = await this._readKeys();
|
||||
return new Keys(JSON.parse(this.keyEncryptor.decrypt(keysString)));
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return [this.bankX(), this.bankE()];
|
||||
};
|
||||
async _generateKeys() {
|
||||
const keysObject = Keys.generate();
|
||||
|
||||
HKD() {
|
||||
return this.download(new EBICSHKD(this));
|
||||
};
|
||||
await this._writeKeys(keysObject);
|
||||
}
|
||||
|
||||
HAA() {
|
||||
return this.download(new EBICSHAA(this));
|
||||
};
|
||||
async setBankKeys(bankKeys) {
|
||||
const keysObject = await this.keys();
|
||||
|
||||
HTD() {
|
||||
return this.download(new EBICSHTD(this));
|
||||
};
|
||||
keysObject.setBankKeys(bankKeys);
|
||||
await this._writeKeys(keysObject);
|
||||
}
|
||||
|
||||
HAC(from = null, to = null) {
|
||||
return this.download(new EBICSHAC(this, from, to));
|
||||
};
|
||||
_readKeys() {
|
||||
return this.keyStorage.read();
|
||||
}
|
||||
|
||||
C52(from, to) {
|
||||
return this.downloadAndUnzip(new EBICSC52(this, from, to));
|
||||
_writeKeys(keysObject) {
|
||||
return this.keyStorage.write(
|
||||
this.keyEncryptor.encrypt(stringifyKeys(keysObject.keys)),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
38
lib/Key.js
38
lib/Key.js
@@ -1,38 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const crypto = require('crypto');
|
||||
|
||||
const NodeRSA = require("node-rsa");
|
||||
const BN = require('bn.js');
|
||||
|
||||
module.exports = class Key {
|
||||
constructor(encodedKey, passphrase = null) {
|
||||
if (encodedKey instanceof NodeRSA) {
|
||||
this.key = encodedKey
|
||||
} else {
|
||||
this.key = new NodeRSA(encodedKey);
|
||||
}
|
||||
};
|
||||
|
||||
publicDigest() {
|
||||
const str = [this.e().replace(/^(0+)/g, ''), this.n().replace(/^(0+)/g, '')].map((x) => x.toLowerCase()).join(' ');
|
||||
|
||||
return crypto.createHash('sha256').update(str).digest('base64').trim();
|
||||
};
|
||||
|
||||
publicEncrypt(str) {
|
||||
return this.key.encrypt(str);
|
||||
}
|
||||
|
||||
n() {
|
||||
return this.key.exportKey("components-public").n.toString("hex", 1);
|
||||
};
|
||||
|
||||
e() {
|
||||
return new BN(this.key.exportKey("components-public").e).toBuffer().toString('hex');
|
||||
};
|
||||
|
||||
toPem() {
|
||||
return this.key.isPrivate() ? this.key.exportKey("pkcs1-private-pem") : this.key.exportKey("pkcs8-public-pem");
|
||||
}
|
||||
};
|
@@ -1,57 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const zlib = require('zlib');
|
||||
const crypto = require("crypto");
|
||||
|
||||
const DOMParser = require("xmldom").DOMParser;
|
||||
const XMLSerializer = require("xmldom").XMLSerializer;
|
||||
const xpath = require("xpath");
|
||||
|
||||
module.exports = class Response {
|
||||
constructor(client, data) {
|
||||
this.client = client;
|
||||
this.doc = new DOMParser().parseFromString(data, 'text/xml');
|
||||
};
|
||||
|
||||
isSegmented() {
|
||||
const select = xpath.useNamespaces({'xmlns': "urn:org:ebics:H004"});
|
||||
const node = select("//xmlns:header/xmlns:mutable/xmlns:SegmentNumber", this.doc);
|
||||
|
||||
return node.length ? true: false;
|
||||
}
|
||||
|
||||
isLastSegment() {
|
||||
const select = xpath.useNamespaces({'xmlns': "urn:org:ebics:H004"});
|
||||
const node = select("//xmlns:header/xmlns:mutable/*[@lastSegment='true']", this.doc);
|
||||
|
||||
return node.length ? true: false;
|
||||
}
|
||||
|
||||
orderData() {
|
||||
const orderData = this.doc.getElementsByTagNameNS("urn:org:ebics:H004", "OrderData")[0].textContent;
|
||||
const decipher = crypto.createDecipheriv('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);
|
||||
const data = Buffer.from(decipher.update(orderData, 'base64', 'binary') + decipher.final('binary'), 'binary');
|
||||
|
||||
return zlib.inflateSync(data).toString();
|
||||
}
|
||||
|
||||
transactionKey() {
|
||||
const keyNodeText = this.doc.getElementsByTagNameNS("urn:org:ebics:H004", "TransactionKey")[0].textContent;
|
||||
const tkEncrypted = Buffer.from(keyNodeText, 'base64');
|
||||
|
||||
this.client.e().key.setOptions({encryptionScheme: 'pkcs1'});
|
||||
|
||||
return this.client.e().key.decrypt(tkEncrypted);
|
||||
}
|
||||
|
||||
transactionId() {
|
||||
const select = xpath.useNamespaces({'xmlns': "urn:org:ebics:H004"});
|
||||
const node = select("//xmlns:header/xmlns:static/xmlns:TransactionID", this.doc);
|
||||
|
||||
return node.length ? node[0].textContent : '';
|
||||
}
|
||||
|
||||
toXML() {
|
||||
return new XMLSerializer().serializeToString(this.doc);
|
||||
}
|
||||
};
|
103
lib/Signer.js
103
lib/Signer.js
@@ -1,103 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const crypto = require("crypto");
|
||||
|
||||
const DOMParser = require("xmldom").DOMParser;
|
||||
const XMLSerializer = require("xmldom").XMLSerializer;
|
||||
const select = require("xpath.js");
|
||||
const c14n = require('xml-crypto/lib/c14n-canonicalization').C14nCanonicalization;
|
||||
|
||||
|
||||
module.exports = class Signer {
|
||||
/**
|
||||
* Contructor.
|
||||
*
|
||||
* @param {Client} client
|
||||
* @param {String} data
|
||||
*/
|
||||
constructor(client, data) {
|
||||
/**
|
||||
* The main client
|
||||
*
|
||||
* @type {Signer}
|
||||
*/
|
||||
this.client = client;
|
||||
|
||||
/**
|
||||
* Request data - generated xml
|
||||
*
|
||||
* @type {...}
|
||||
*/
|
||||
this.doc = new DOMParser().parseFromString(data, 'text/xml');
|
||||
}
|
||||
|
||||
_junk() {
|
||||
this.digest();
|
||||
this.sign();
|
||||
// console.log(this.toXML());
|
||||
/* const headerSet = select(this.doc, "//*[@authenticate='true']").map(x => {
|
||||
// x.setAttribute('xmlns:ds', 'http://www.w3.org/2000/09/xmldsig#');
|
||||
return new c14n().process(x);
|
||||
}).join();
|
||||
const can = headerSet.replace('xmlns="urn:org:ebics:H004"', 'xmlns="urn:org:ebics:H004" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"');
|
||||
|
||||
const hash = crypto.createHash('sha256');
|
||||
hash.update(can);
|
||||
const digester = hash.digest('base64').trim();
|
||||
if ( this.doc.getElementsByTagName("ds:DigestValue")[0] )
|
||||
this.doc.getElementsByTagName("ds:DigestValue")[0].textContent = digester; */
|
||||
|
||||
/* const nodeSet = select(this.doc, "//ds:SignedInfo");
|
||||
const canonicalized = nodeSet.map(x => {
|
||||
const g = x.toString();
|
||||
const res = new c14n().process(x);
|
||||
return res;
|
||||
}).join();
|
||||
|
||||
const canonicalizedString = canonicalized.replace('xmlns:ds="http://www.w3.org/2000/09/xmldsig#"', 'xmlns="urn:org:ebics:H004" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"');
|
||||
|
||||
// const SIGN = crypto.createSign('RSA-SHA256');
|
||||
// SIGN.update(canonicalizedString);
|
||||
// const key = SIGN.sign(this.client.x().key.exportKey("pkcs1-private-pem"), 'base64');
|
||||
const f = this.client.x().key.sign(canonicalizedString, 'base64');
|
||||
if ( this.doc.getElementsByTagName("ds:SignatureValue")[0] ) {
|
||||
this.doc.getElementsByTagName("ds:SignatureValue")[0].textContent = f;
|
||||
} */
|
||||
}
|
||||
|
||||
digest() {
|
||||
// get the xml node, where the digested value is supposed to be
|
||||
const nodeDigestValue = this.doc.getElementsByTagName("ds:DigestValue")[0];
|
||||
|
||||
const nodes = select(this.doc, "//*[@authenticate='true']");
|
||||
|
||||
// canonicalize the node that has authenticate='true' attribute
|
||||
const contentToDigest = select(this.doc, "//*[@authenticate='true']")
|
||||
.map(x => {
|
||||
const aaaa = x.toString();
|
||||
return 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.createHash('sha256').update(fixedContent).digest('base64').trim();
|
||||
}
|
||||
};
|
||||
|
||||
sign() {
|
||||
const nodeSignatureValue = this.doc.getElementsByTagName("ds:SignatureValue")[0];
|
||||
|
||||
if (nodeSignatureValue) {
|
||||
const contentToSign = (new c14n().process(select(this.doc, "//ds:SignedInfo")[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 = this.client.x().key.sign(contentToSign, 'base64');
|
||||
}
|
||||
}
|
||||
|
||||
toXML() {
|
||||
return new XMLSerializer().serializeToString(this.doc);
|
||||
}
|
||||
|
||||
};
|
@@ -1,12 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
const packageJson = require('../package.json');
|
||||
const { version } = require('../package.json');
|
||||
|
||||
const name = 'eCollect Node Ebics Client';
|
||||
const version = packageJson.version;
|
||||
const name = 'Node Ebics Client';
|
||||
const orderOperations = {
|
||||
ini: 'INI',
|
||||
upload: 'UPLOAD',
|
||||
download: 'DOWNLOAD',
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
name,
|
||||
version,
|
||||
productString: `${name} ${version}`,
|
||||
};
|
||||
name,
|
||||
version,
|
||||
orderOperations,
|
||||
productString: `${name} ${version}`,
|
||||
};
|
||||
|
66
lib/crypto/BigNumber.js
Normal file
66
lib/crypto/BigNumber.js
Normal 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;
|
104
lib/crypto/Crypto.js
Normal file
104
lib/crypto/Crypto.js
Normal file
@@ -0,0 +1,104 @@
|
||||
'use strict';
|
||||
|
||||
const crypto = require('crypto');
|
||||
const NodeRSA = require('node-rsa');
|
||||
|
||||
const BigNumber = require('./BigNumber.js');
|
||||
const mgf1 = require('./MGF1');
|
||||
|
||||
const modPow = (base, power, mod) => {
|
||||
let result = new BigNumber(1);
|
||||
|
||||
while (power > 0) {
|
||||
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);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const emsaPSS = (msg, salt) => {
|
||||
const eightNullBytes = Buffer.from('\x00'.repeat(8));
|
||||
const digestedMsg = crypto.createHash('sha256').update(msg).digest();
|
||||
const mTickHash = crypto.createHash('sha256').update(Buffer.concat([eightNullBytes, digestedMsg, salt]), 'binary').digest();
|
||||
|
||||
const ps = Buffer.from('\x00'.repeat(190));
|
||||
const db = Buffer.concat([ps, Buffer.from('\x01'), salt]);
|
||||
|
||||
const dbMask = mgf1.generate(mTickHash, db.length);
|
||||
const maskedDb = mgf1.xor(db, dbMask);
|
||||
|
||||
let maskedDbMsb = mgf1.rjust(new BigNumber(maskedDb.slice(0, 1)).toString(2), 8, '0');
|
||||
|
||||
|
||||
maskedDbMsb = `0${maskedDbMsb.substr(1)}`;
|
||||
// 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')]);
|
||||
};
|
||||
|
||||
|
||||
module.exports = class Crypto {
|
||||
static digestPublicKey(key) {
|
||||
const str = [key.e('hex').replace(/^(0+)/g, ''), key.n('hex').replace(/^(0+)/g, '')].map(x => x.toLowerCase()).join(' ');
|
||||
|
||||
return crypto.createHash('sha256').update(str).digest('base64').trim();
|
||||
}
|
||||
|
||||
static publicEncrypt(key, data) {
|
||||
return crypto.publicEncrypt({
|
||||
key: key.toPem(),
|
||||
padding: crypto.constants.RSA_PKCS1_PADDING,
|
||||
}, data);
|
||||
}
|
||||
|
||||
static privateDecrypt(key, data) {
|
||||
const keyRSA = new NodeRSA(
|
||||
key.toPem(),
|
||||
'pkcs1-private-pem', {
|
||||
encryptionScheme: 'pkcs1',
|
||||
environment: 'browser', // would use the crypto module by default, which blocks pkcs1
|
||||
},
|
||||
);
|
||||
return keyRSA.decrypt(data);
|
||||
}
|
||||
|
||||
static privateSign(key, data, outputEncoding = 'base64') {
|
||||
const signer = crypto.createSign('SHA256');
|
||||
|
||||
return signer.update(data).sign(key.toPem(), outputEncoding);
|
||||
}
|
||||
|
||||
static sign(key, msg, salt = crypto.randomBytes(32)) {
|
||||
const base = new BigNumber(emsaPSS(msg, salt));
|
||||
const power = new BigNumber(key.d());
|
||||
const mod = new BigNumber(key.n());
|
||||
const buffer = modPow(base, power, mod).toBEBuffer();
|
||||
|
||||
if (buffer.byteLength === 257 && buffer[0] === 0x00)
|
||||
return buffer.slice(1).toString('base64');
|
||||
|
||||
return buffer.toString('base64');
|
||||
}
|
||||
|
||||
static pad(d) {
|
||||
const dLen = d.length;
|
||||
const len = 16 * (Math.trunc(dLen / 16) + 1);
|
||||
|
||||
return Buffer.concat([d, Buffer.from(Buffer.from([0]).toString().repeat(len - dLen - 1)), Buffer.from([len - dLen])]);
|
||||
}
|
||||
|
||||
static digestWithHash(data, algorith = 'sha256') {
|
||||
return crypto.createHash(algorith).update(data).digest();
|
||||
}
|
||||
|
||||
static nonce(outputEncoding = 'hex') {
|
||||
return crypto.randomBytes(16).toString(outputEncoding);
|
||||
}
|
||||
|
||||
static timestamp() {
|
||||
return new Date().toISOString();
|
||||
}
|
||||
};
|
48
lib/crypto/MGF1.js
Normal file
48
lib/crypto/MGF1.js
Normal file
@@ -0,0 +1,48 @@
|
||||
'use strict';
|
||||
|
||||
const crypto = require('crypto');
|
||||
|
||||
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.substr(0, 1);
|
||||
if (string.length < width)
|
||||
return padding.repeat(width - string.length) + string;
|
||||
return string;
|
||||
};
|
||||
const xor = (a, b) => {
|
||||
if (a.length !== b.length)
|
||||
throw new Error('Different length for a and b');
|
||||
|
||||
for (let i = 0; i < a.length; i++)
|
||||
a[i] ^= b[i]; // eslint-disable-line no-bitwise
|
||||
|
||||
return a;
|
||||
};
|
||||
const i2osp = (x, len) => {
|
||||
if (x >= 256 ** len)
|
||||
throw new Error('Integer too large');
|
||||
|
||||
return Buffer.from(rjust(new BigNumber(x).toBEBuffer(4).toString().replace(/\x00/gi, ''), len, '\x00')); // eslint-disable-line no-control-regex
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
generate(seed, masklen) {
|
||||
if (masklen > 4294967296 * MFG_LEN)
|
||||
throw new Error('Mask too long');
|
||||
|
||||
|
||||
const b = [];
|
||||
|
||||
for (let i = 0; i < divceil(masklen, MFG_LEN); i++)
|
||||
b[i] = crypto.createHash('sha256').update(Buffer.concat([seed, i2osp(i, 4)])).digest();
|
||||
|
||||
|
||||
return (Buffer.concat(b)).slice(0, masklen);
|
||||
},
|
||||
xor,
|
||||
rjust,
|
||||
};
|
66
lib/crypto/encryptDecrypt.js
Normal file
66
lib/crypto/encryptDecrypt.js
Normal file
@@ -0,0 +1,66 @@
|
||||
'use strict';
|
||||
|
||||
const crypto = require('crypto');
|
||||
|
||||
const createKeyAndIv = (passphrase) => {
|
||||
// this generates a 256-bit key and a 128-bit iv for aes-256-cbc
|
||||
// just like nodejs's deprecated/removed crypto.createCipher would
|
||||
const a = crypto.createHash('md5').update(passphrase).digest();
|
||||
const b = crypto
|
||||
.createHash('md5')
|
||||
.update(Buffer.concat([a, Buffer.from(passphrase)]))
|
||||
.digest();
|
||||
const c = crypto
|
||||
.createHash('md5')
|
||||
.update(Buffer.concat([b, Buffer.from(passphrase)]))
|
||||
.digest();
|
||||
const bytes = Buffer.concat([a, b, c]);
|
||||
const key = bytes.subarray(0, 32);
|
||||
const iv = bytes.subarray(32, 48);
|
||||
return { key, iv };
|
||||
};
|
||||
|
||||
const encrypt = (data, algorithm, passphrase, iv) => {
|
||||
let cipher;
|
||||
if (iv) {
|
||||
cipher = crypto.createCipheriv(algorithm, passphrase, iv);
|
||||
} else {
|
||||
console.warn(
|
||||
'[Deprecation notice] No IV provided, falling back to legacy key derivation.\n'
|
||||
+ 'This will be removed in a future major release. You should encrypt your keys with a proper key and IV.',
|
||||
);
|
||||
if (crypto.createCipher) {
|
||||
// nodejs < 22
|
||||
cipher = crypto.createCipher(algorithm, passphrase);
|
||||
} else {
|
||||
const { key, iv: generatedIv } = createKeyAndIv(passphrase);
|
||||
cipher = crypto.createCipheriv(algorithm, key, generatedIv);
|
||||
}
|
||||
}
|
||||
const encrypted = cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
|
||||
return Buffer.from(encrypted).toString('base64');
|
||||
};
|
||||
|
||||
const decrypt = (data, algorithm, passphrase, iv) => {
|
||||
data = Buffer.from(data, 'base64').toString();
|
||||
let decipher;
|
||||
if (iv) {
|
||||
decipher = crypto.createDecipheriv(algorithm, passphrase, iv);
|
||||
} else {
|
||||
console.warn(
|
||||
'[Deprecation notice] No IV provided, falling back to legacy key derivation.\n'
|
||||
+ 'This will be removed in a future major release. You should re-encrypt your keys with a proper key and IV.',
|
||||
);
|
||||
if (crypto.createDecipher) {
|
||||
// nodejs < 22
|
||||
decipher = crypto.createDecipher(algorithm, passphrase);
|
||||
} else {
|
||||
const { key, iv: generatedIv } = createKeyAndIv(passphrase);
|
||||
decipher = crypto.createDecipheriv(algorithm, key, generatedIv);
|
||||
}
|
||||
}
|
||||
const decrypted = decipher.update(data, 'hex', 'utf8') + decipher.final('utf8');
|
||||
return decrypted;
|
||||
};
|
||||
|
||||
module.exports = { encrypt, decrypt };
|
138
lib/keymanagers/Key.js
Normal file
138
lib/keymanagers/Key.js
Normal file
@@ -0,0 +1,138 @@
|
||||
'use strict';
|
||||
|
||||
const {
|
||||
pki: {
|
||||
rsa,
|
||||
publicKeyToPem,
|
||||
privateKeyToPem,
|
||||
publicKeyFromPem,
|
||||
privateKeyFromPem,
|
||||
},
|
||||
jsbn: {
|
||||
BigInteger,
|
||||
},
|
||||
} = require('node-forge');
|
||||
|
||||
const getKeyType = (str) => {
|
||||
const matches = str.match(/(PRIVATE|PUBLIC) KEY/);
|
||||
if (!matches)
|
||||
return null;
|
||||
return matches[1].toLowerCase();
|
||||
};
|
||||
|
||||
const keyFromPem = (pem) => {
|
||||
const type = getKeyType(pem);
|
||||
const isPublic = type === 'public';
|
||||
const key = isPublic ? publicKeyFromPem(pem) : privateKeyFromPem(pem);
|
||||
|
||||
return {
|
||||
isPublic,
|
||||
key,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a public key from modulus and exponent
|
||||
* @param {Buffer} mod - the modulus
|
||||
* @param {Buffer} exp - the exponent
|
||||
*/
|
||||
const keyFromModAndExp = (mod, exp) => {
|
||||
const bnMod = new BigInteger(mod.toString('hex'), 16);
|
||||
const bnExp = new BigInteger(exp.toString('hex'), 16);
|
||||
|
||||
return {
|
||||
key: rsa.setPublicKey(bnMod, bnExp),
|
||||
isPublic: true,
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = class Key {
|
||||
constructor({
|
||||
pem = null, mod = null, exp = null, size = 2048,
|
||||
} = {}) {
|
||||
// generate new private key
|
||||
if (!pem && !mod && !exp) {
|
||||
const keyPair = rsa.generateKeyPair(size);
|
||||
|
||||
this.keyIsPublic = false;
|
||||
this.privateKey = keyPair.privateKey;
|
||||
this.publicKey = keyPair.publicKey;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// new key from pem string
|
||||
if (pem) {
|
||||
const { key, isPublic } = keyFromPem(pem);
|
||||
|
||||
this.keyIsPublic = isPublic;
|
||||
this.privateKey = isPublic ? null : key;
|
||||
this.publicKey = isPublic ? key : null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// new key from mod and exp
|
||||
if (mod && exp) {
|
||||
const { key, isPublic } = keyFromModAndExp(mod, exp);
|
||||
|
||||
this.keyIsPublic = isPublic;
|
||||
this.privateKey = isPublic ? null : key;
|
||||
this.publicKey = isPublic ? key : null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// not good
|
||||
throw new Error(`Can not create key without ${!mod ? 'modulus' : 'exponent'}.`);
|
||||
}
|
||||
|
||||
static generate(size = 2048) {
|
||||
return new Key({ size });
|
||||
}
|
||||
|
||||
static importKey({ mod, exp }) {
|
||||
return new Key({ mod, exp });
|
||||
}
|
||||
|
||||
n(to = 'buff') {
|
||||
const key = this.keyIsPublic ? this.publicKey : this.privateKey;
|
||||
const keyN = Buffer.from(key.n.toByteArray());
|
||||
|
||||
return to === 'hex' ? keyN.toString('hex', 1) : keyN;
|
||||
}
|
||||
|
||||
e(to = 'buff') {
|
||||
const key = this.keyIsPublic ? this.publicKey : this.privateKey;
|
||||
const eKey = Buffer.from(key.e.toByteArray());
|
||||
|
||||
return to === 'hex' ? eKey.toString('hex') : eKey;
|
||||
}
|
||||
|
||||
d() {
|
||||
if (this.keyIsPublic)
|
||||
throw new Error('Can not get d component out of public key.');
|
||||
|
||||
return Buffer.from(this.privateKey.d.toByteArray());
|
||||
}
|
||||
|
||||
isPrivate() {
|
||||
return !this.keyIsPublic;
|
||||
}
|
||||
|
||||
isPublic() {
|
||||
return this.keyIsPublic;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
size() {
|
||||
const keyN = this.n('hex');
|
||||
const bn = new BigInteger(keyN, 16);
|
||||
|
||||
return bn.bitLength();
|
||||
}
|
||||
|
||||
toPem() {
|
||||
return this.keyIsPublic ? publicKeyToPem(this.publicKey) : privateKeyToPem(this.privateKey);
|
||||
}
|
||||
};
|
63
lib/keymanagers/Keys.js
Normal file
63
lib/keymanagers/Keys.js
Normal file
@@ -0,0 +1,63 @@
|
||||
'use strict';
|
||||
|
||||
const Key = require('./Key');
|
||||
|
||||
const keyOrNull = (key) => {
|
||||
if (key instanceof Key)
|
||||
return key;
|
||||
|
||||
return key ? new Key({ pem: key }) : null;
|
||||
};
|
||||
|
||||
module.exports = class Keys {
|
||||
constructor({
|
||||
A006,
|
||||
E002,
|
||||
X002,
|
||||
bankX002,
|
||||
bankE002,
|
||||
}) {
|
||||
this.keys = {
|
||||
A006: keyOrNull(A006),
|
||||
E002: keyOrNull(E002),
|
||||
X002: keyOrNull(X002),
|
||||
bankX002: keyOrNull(bankX002),
|
||||
bankE002: keyOrNull(bankE002),
|
||||
};
|
||||
}
|
||||
|
||||
static generate() {
|
||||
const keys = {};
|
||||
|
||||
Object.keys({ A006: '', X002: '', E002: '' }).forEach((key) => {
|
||||
keys[key] = Key.generate(); // Key().generate();
|
||||
});
|
||||
|
||||
return new Keys(keys);
|
||||
}
|
||||
|
||||
setBankKeys(bankKeys) {
|
||||
this.keys.bankX002 = new Key(bankKeys.bankX002); // Key().importKey(bankKeys.bankX002);
|
||||
this.keys.bankE002 = new Key(bankKeys.bankE002); // Key().importKey(bankKeys.bankE002);
|
||||
}
|
||||
|
||||
a() {
|
||||
return this.keys.A006;
|
||||
}
|
||||
|
||||
e() {
|
||||
return this.keys.E002;
|
||||
}
|
||||
|
||||
x() {
|
||||
return this.keys.X002;
|
||||
}
|
||||
|
||||
bankX() {
|
||||
return this.keys.bankX002;
|
||||
}
|
||||
|
||||
bankE() {
|
||||
return this.keys.bankE002;
|
||||
}
|
||||
};
|
52
lib/keymanagers/KeysManager.js
Normal file
52
lib/keymanagers/KeysManager.js
Normal file
@@ -0,0 +1,52 @@
|
||||
'use strict';
|
||||
|
||||
const { encrypt, decrypt } = require('../crypto/encryptDecrypt');
|
||||
const Keys = require('./Keys');
|
||||
|
||||
module.exports = (keysStorage, passphrase, algorithm = 'aes-256-cbc') => {
|
||||
const storage = keysStorage;
|
||||
const pass = passphrase;
|
||||
const algo = algorithm;
|
||||
// const createIfNone = createIfNone;
|
||||
|
||||
return {
|
||||
generate(save = true) {
|
||||
const keys = Keys.generate();
|
||||
|
||||
if (save) {
|
||||
this.write(keys);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
return keys;
|
||||
},
|
||||
|
||||
write(keysObject) {
|
||||
keysObject = keysObject.keys;
|
||||
|
||||
Object.keys(keysObject).map((key) => {
|
||||
keysObject[key] = keysObject[key] === null ? null : keysObject[key].toPem();
|
||||
|
||||
return key;
|
||||
});
|
||||
|
||||
storage.write(encrypt(JSON.stringify(keysObject), algo, pass));
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
setBankKeys(bankKeys) {
|
||||
const keys = this.keys();
|
||||
|
||||
keys.setBankKeys(bankKeys);
|
||||
this.write(keys);
|
||||
},
|
||||
|
||||
keys() {
|
||||
const keysString = storage.read();
|
||||
|
||||
return new Keys(JSON.parse(decrypt(keysString, algo, pass)));
|
||||
},
|
||||
};
|
||||
};
|
9
lib/keymanagers/defaultKeyEncryptor.js
Normal file
9
lib/keymanagers/defaultKeyEncryptor.js
Normal file
@@ -0,0 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
const { encrypt, decrypt } = require('../crypto/encryptDecrypt');
|
||||
|
||||
|
||||
module.exports = ({ passphrase, iv, algorithm = 'aes-256-cbc' }) => ({
|
||||
encrypt: data => encrypt(data, algorithm, passphrase, iv),
|
||||
decrypt: data => decrypt(data, algorithm, passphrase),
|
||||
});
|
@@ -1,22 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const Response = require('../Response');
|
||||
|
||||
module.exports = class ParseResponse {
|
||||
constructor(client, data) {
|
||||
this.client = client;
|
||||
this.data = data;
|
||||
};
|
||||
|
||||
static go (client, data) {
|
||||
const parseRensponse = new ParseResponse(client, data);
|
||||
const response = new Response(client, data);
|
||||
|
||||
// TODO:
|
||||
// raise error if any
|
||||
|
||||
this.data = response.doc;
|
||||
|
||||
return response;
|
||||
}
|
||||
};
|
@@ -1,22 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const Signer = require('../Signer');
|
||||
|
||||
module.exports = class XMLSign {
|
||||
constructor(client, data) {
|
||||
this.client = client;
|
||||
this.data = data;
|
||||
};
|
||||
|
||||
static go (client, data) {
|
||||
const xmlSigner = new XMLSign(client, data);
|
||||
const signer = new Signer(client, data);
|
||||
|
||||
signer.digest();
|
||||
signer.sign();
|
||||
|
||||
this.data = signer.toXML();
|
||||
|
||||
return this.data;
|
||||
}
|
||||
};
|
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, client) {
|
||||
const { version } = order;
|
||||
|
||||
if (version.toUpperCase() === 'H004') return H004Serializer.use(order, client);
|
||||
|
||||
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');
|
||||
},
|
||||
};
|
@@ -1,50 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const GenericOrder = require('./GenericOrder');
|
||||
|
||||
module.exports = class C52 extends GenericOrder {
|
||||
constructor (client, from, to) {
|
||||
super(client);
|
||||
this._from = from;
|
||||
this._to = to;
|
||||
|
||||
this._schema.header = {
|
||||
"@" : { authenticate: true },
|
||||
static: {
|
||||
HostID : this.hostId,
|
||||
Nonce : this.nonce(),
|
||||
Timestamp: this.timestamp(),
|
||||
PartnerID: this.partnerId,
|
||||
UserID : this.userId,
|
||||
Product : {
|
||||
"@": { Language: "de" },
|
||||
"#": this.productString,
|
||||
},
|
||||
OrderDetails: {
|
||||
OrderType : "C52",
|
||||
OrderAttribute : "DZHNN",
|
||||
StandardOrderParams: {
|
||||
DateRange: {
|
||||
Start: this._from,
|
||||
End : this._to
|
||||
}
|
||||
},
|
||||
},
|
||||
BankPubKeyDigests: {
|
||||
Authentication: {
|
||||
"@": { Version: "X002", Algorithm: "http://www.w3.org/2001/04/xmlenc#sha256" },
|
||||
"#": this.client.bankX().publicDigest()
|
||||
},
|
||||
Encryption: {
|
||||
"@": { Version: "E002", Algorithm: "http://www.w3.org/2001/04/xmlenc#sha256" },
|
||||
"#": this.client.bankE().publicDigest()
|
||||
}
|
||||
},
|
||||
SecurityMedium: "0000"
|
||||
},
|
||||
mutable: {
|
||||
TransactionPhase: "Initialisation"
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
@@ -1,143 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
// const randHex = require('../../lib/utils').randHex;
|
||||
const crypto = require("crypto");
|
||||
const js2xmlparser = require('js2xmlparser');
|
||||
const consts = require('../consts');
|
||||
|
||||
module.exports = class GenericOrder {
|
||||
constructor(client) {
|
||||
this.client = client;
|
||||
|
||||
this.hostId = client.hostId;
|
||||
this.userId = client.userId;
|
||||
this.partnerId = client.partnerId;
|
||||
|
||||
this.transactionId = '';
|
||||
|
||||
this.xmlOptions = {
|
||||
declaration: {
|
||||
include: true,
|
||||
encoding: "utf-8"
|
||||
},
|
||||
format: {
|
||||
doubleQuotes: true,
|
||||
indent: '',
|
||||
newline: '',
|
||||
// indent: "\t",
|
||||
// newline: "\r\n",
|
||||
pretty: true
|
||||
}
|
||||
};
|
||||
|
||||
this._schema = {
|
||||
"@": {
|
||||
"xmlns:ds": "http://www.w3.org/2000/09/xmldsig#",
|
||||
xmlns: "urn:org:ebics:H004",
|
||||
Version: "H004",
|
||||
Revision: "1"
|
||||
},
|
||||
|
||||
header: {},
|
||||
|
||||
AuthSignature: this.authSignature(),
|
||||
|
||||
body: {}
|
||||
};
|
||||
}
|
||||
|
||||
authSignature() {
|
||||
return {
|
||||
"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": {}
|
||||
};
|
||||
}
|
||||
|
||||
get schema() {
|
||||
return this._schema;
|
||||
}
|
||||
|
||||
get productString() {
|
||||
return consts.productString;
|
||||
}
|
||||
|
||||
nonce() {
|
||||
return crypto.randomBytes(16).toString('hex');
|
||||
}
|
||||
|
||||
timestamp() {
|
||||
return new Date().toISOString();
|
||||
}
|
||||
|
||||
root() {
|
||||
return "ebicsRequest";
|
||||
}
|
||||
|
||||
toReceiptXML() {
|
||||
const xmlObj = {
|
||||
"@": {
|
||||
"xmlns:ds": "http://www.w3.org/2000/09/xmldsig#",
|
||||
xmlns: "urn:org:ebics:H004",
|
||||
Version: "H004",
|
||||
Revision: "1"
|
||||
},
|
||||
|
||||
header: {
|
||||
"@": { authenticate: true },
|
||||
static: {
|
||||
HostID: this.hostId,
|
||||
TransactionID: this.transactionId
|
||||
},
|
||||
mutable: {
|
||||
TransactionPhase: 'Receipt',
|
||||
}
|
||||
},
|
||||
|
||||
AuthSignature: this.authSignature(),
|
||||
|
||||
body: {
|
||||
TransferReceipt: {
|
||||
"@": { authenticate: true },
|
||||
ReceiptCode: 0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return js2xmlparser.parse(this.root(), xmlObj, this.xmlOptions);
|
||||
}
|
||||
|
||||
toXML() {
|
||||
return js2xmlparser.parse(this.root(), this._schema, this.xmlOptions);
|
||||
}
|
||||
};
|
@@ -1,63 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const zlib = require('zlib');
|
||||
const crypto = require("crypto");
|
||||
const js2xmlparser = require('js2xmlparser');
|
||||
|
||||
const GenericOrder = require('./GenericOrder');
|
||||
|
||||
module.exports = class GenericUploadOrder extends GenericOrder {
|
||||
constructor(client, document) {
|
||||
super(client);
|
||||
|
||||
this._document = document;
|
||||
this._key = crypto.randomBytes(16);
|
||||
|
||||
this._schema.body = {
|
||||
DataTransfer: {
|
||||
DataEncryptionInfo: {
|
||||
"@": { authenticate: true },
|
||||
EncryptionPubKeyDigest: {
|
||||
"@": { Version: "E002", Algorithm: "http://www.w3.org/2001/04/xmlenc#sha256" },
|
||||
"#": this.client.bankE().publicDigest()
|
||||
},
|
||||
TransactionKey: Buffer.from(this.client.bankE().publicEncrypt(this._key)).toString('base64'),
|
||||
},
|
||||
SignatureData: {
|
||||
"@": { authenticate: true },
|
||||
"#": this.encryptedOrderSignature()
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
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.createHash('sha256').update(this._document).digest();
|
||||
};
|
||||
|
||||
encryptedOrderSignature() {
|
||||
const dst = zlib.deflateSync(this.orderSignature());
|
||||
const cipher = crypto.createCipheriv('aes-128-cbc', this._key, Buffer.from([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,])).setAutoPadding(false);
|
||||
const encrypted = cipher.update(dst) + cipher.final();
|
||||
|
||||
return Buffer.from(encrypted).toString('base64');
|
||||
};
|
||||
};
|
318
lib/orders/H004/errors.js
Normal file
318
lib/orders/H004/errors.js
Normal file
@@ -0,0 +1,318 @@
|
||||
'use strict';
|
||||
|
||||
const errors = {
|
||||
technical: {
|
||||
'000000': {
|
||||
symbol: 'EBICS_OK',
|
||||
short_text: 'OK',
|
||||
meaning: 'No technical errors occurred during processing of the EBICS request',
|
||||
},
|
||||
'011000': {
|
||||
symbol: 'EBICS_DOWNLOAD_POSTPROCESS_DONE',
|
||||
short_text: 'Positive acknowledgement received',
|
||||
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 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',
|
||||
short_text: 'Segment number not reached',
|
||||
meaning: 'The total number of segments transmitted during transaction initialisation was not reached (i.e. the attribute @lastSegment was set to "true" before the specified segment number was reached)',
|
||||
},
|
||||
'031001': {
|
||||
symbol: 'EBICS_ORDER_PARAMS_IGNORED',
|
||||
short_text: 'Unknown order parameters are ignored',
|
||||
meaning: 'E.g. OrderParams for Upload specified',
|
||||
},
|
||||
'061001': {
|
||||
symbol: 'EBICS_AUTHENTICATION_FAILED',
|
||||
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',
|
||||
meaning: 'The syntax of the received message does not conform with EBICS specifications',
|
||||
},
|
||||
'061099': {
|
||||
symbol: 'EBICS_INTERNAL_ERROR',
|
||||
short_text: 'Internal EBICS error',
|
||||
meaning: 'An internal error occurred during',
|
||||
},
|
||||
'061101': {
|
||||
symbol: 'EBICS_TX_RECOVERY_SYNC',
|
||||
short_text: 'Synchronisation necessary',
|
||||
meaning: "Recovery of the transaction requires synchronisation between the customer system and the bank system Continuation of the transaction using the recovery point from the bank system's EBICS response",
|
||||
},
|
||||
'091002': {
|
||||
symbol: 'EBICS_INVALID_USER_OR_USER_STATE',
|
||||
short_text: 'Subscriber unknown or subscriber state inadmissible',
|
||||
meaning: 'Either the initiating party is not known to the bank system or the subscriber state that is stored in the bank of the initiating party is inadmissible with regard to the order type',
|
||||
},
|
||||
'091003': {
|
||||
symbol: 'EBICS_USER_UNKNOWN',
|
||||
short_text: 'Subscriber unknown',
|
||||
meaning: 'The initiating party is not known to the bank system',
|
||||
},
|
||||
'091004': {
|
||||
symbol: 'EBICS_INVALID_USER_STATE',
|
||||
short_text: 'Subscriber state unknown',
|
||||
meaning: 'The subscriber state of the initiating party that is stored in the bank system is inadmissible with regard to the order type',
|
||||
},
|
||||
'091005': {
|
||||
symbol: 'EBICS_INVALID_ORDER_TYPE',
|
||||
short_text: 'Order type inadmissible',
|
||||
meaning: 'The order type is unknown or not approved for use with EBICS',
|
||||
},
|
||||
'091006': {
|
||||
symbol: 'EBICS_UNSUPPORTED_ORDER_TYPE',
|
||||
short_text: 'Order type not supported',
|
||||
meaning: 'The selected order type is optional with EBICS and is not supported by the financial institution',
|
||||
},
|
||||
'091007': {
|
||||
symbol: 'EBICS_DISTRIBUTED_SIGNATURE_AUTHORISATION_FAILED',
|
||||
short_text: 'Subscriber possesses no authorisation of signature for the referenced order in the VEU administration (Request recent signature folder)',
|
||||
meaning: 'Retrieve recent signature folder with permissible orders of order type HVU (or HVZ, respectively)',
|
||||
},
|
||||
'091008': {
|
||||
symbol: 'EBICS_BANK_PUBKEY_UPDATE_REQUIRED',
|
||||
short_text: 'Bank key invalid',
|
||||
meaning: 'The public bank key that is available to the subscriber is invalid',
|
||||
},
|
||||
'091009': {
|
||||
symbol: 'EBICS_SEGMENT_SIZE_EXCEEDED',
|
||||
short_text: 'Segment size exceeded',
|
||||
meaning: 'The specified size of an upload order data segment (in the case of H003: 1 MB) has been exceeded',
|
||||
},
|
||||
'091010': {
|
||||
symbol: 'EBICS_INVALID_XML',
|
||||
short_text: 'XML invalid according to EBICS XML schema',
|
||||
meaning: 'XML validation with EBICS schema failed or XML not well-formed',
|
||||
},
|
||||
'091011': {
|
||||
symbol: 'EBICS_INVALID_HOST_ID',
|
||||
short_text: "The transmitted HostID is unknown on the bank's side",
|
||||
meaning: "The transmitted HostID is unknown on the bank's side. The use of this code is only provided for the HEV request Check the used HostID and correct it. Consultation with the bank, if necessary",
|
||||
},
|
||||
'091101': {
|
||||
symbol: 'EBICS_TX_UNKNOWN_TXID',
|
||||
short_text: 'Transaction ID invalid',
|
||||
meaning: 'The supplied transaction ID is invalid',
|
||||
},
|
||||
'091102': {
|
||||
symbol: 'EBICS_TX_ABORT',
|
||||
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',
|
||||
short_text: 'Suspected Message replay (wrong time/time zone or nonce error)',
|
||||
meaning: 'A message replay has been identified (Nonce/Timestamp pair doubled) or the difference of clock time between client and server exceeds the (parametrisable) tolerance limit',
|
||||
},
|
||||
'091104': {
|
||||
symbol: 'EBICS_TX_SEGMENT_NUMBER_EXCEEDED',
|
||||
short_text: 'Segment number exceeded',
|
||||
meaning: 'The total segment number from transaction initialisation was exceeded, i.e. the attribute @lastSegment was set to "false" when the last segment was transmitted',
|
||||
},
|
||||
'091112': {
|
||||
symbol: 'EBICS_INVALID_ORDER_PARAMS',
|
||||
short_text: 'Invalid order parameters',
|
||||
meaning: 'The content of OrderParams is invalid, e.g. if starting off behind the end in case of StandardOrderParams, or, in case of HVT, fetchOffset is higher than NumOrderInfos (total number of particular order information of an order)',
|
||||
},
|
||||
'091113': {
|
||||
symbol: 'EBICS_INVALID_REQUEST_CONTENT',
|
||||
short_text: 'Message content semantically not compliant to EBICS',
|
||||
meaning: 'The received message complies syntactically EBICS XML schema, but not semantically to the EBICS guidelines, e.g. IZV upload with UZHNN requires NumSegments = 0',
|
||||
},
|
||||
'091117': {
|
||||
symbol: 'EBICS_MAX_ORDER_DATA_SIZE_EXCEEDED',
|
||||
short_text: 'The bank system does not support the requested order size',
|
||||
meaning: 'Upload or download of an order file of improper size (e.g. for HVT, IZV, STA)',
|
||||
},
|
||||
'091118': {
|
||||
symbol: 'EBICS_MAX_SEGMENTS_EXCEEDED',
|
||||
short_text: 'Submitted number of segments for upload is too high',
|
||||
meaning: 'The bank system does not support the specified total number of segments for upload',
|
||||
},
|
||||
'091119': {
|
||||
symbol: 'EBICS_MAX_TRANSACTIONS_EXCEEDED',
|
||||
short_text: 'Maximum number of parallel transactions per customer is exceeded',
|
||||
meaning: 'The maximum number of parallel EBICS transactions defined in the bank system for the customer has been exceeded',
|
||||
},
|
||||
'091120': {
|
||||
symbol: 'EBICS_PARTNER_ID_MISMATCH',
|
||||
short_text: 'The partner ID (=customer ID) of the ES file is not identical to the partner ID (=customer ID) of the submitter.',
|
||||
meaning: "On verifying the submitted signatures a partner ID was found in the document UserSignatureData that is not identical to the subscriber's partner ID in the request header",
|
||||
},
|
||||
'091121': {
|
||||
symbol: 'EBICS_INCOMPATIBLE_ORDER_ATTRIBUTE',
|
||||
short_text: 'The specified order attribute is not compatible with the order in the bank system',
|
||||
meaning: 'Case 1) File with order attribute "DZHNN" or "OZHNN" submitted with an orderId or Case 2) File with order attribute "UZHNN" submitted without an orderId or with orderID which is already used for "DZHNN" File with order attribute "DZHNN" submitted with an orderId',
|
||||
},
|
||||
},
|
||||
business: {
|
||||
'000000': {
|
||||
symbol: 'EBICS_OK',
|
||||
short_text: 'OK',
|
||||
meaning: 'No technical errors occurred during processing of the EBICS request',
|
||||
},
|
||||
'011301': {
|
||||
symbol: 'EBICS_NO_ONLINE_CHECKS',
|
||||
short_text: 'Optional preliminary verification is not supported by the bank system',
|
||||
},
|
||||
'091001': {
|
||||
symbol: 'EBICS_DOWNLOAD_SIGNED_ONLY',
|
||||
short_text: 'The bank system only supports bank-technically signed download order data for the order in question',
|
||||
},
|
||||
'091002': {
|
||||
symbol: 'EBICS_DOWNLOAD_UNSIGNED_ONLY',
|
||||
short_text: 'The bank system only supports unsigned download order data for the order in question',
|
||||
},
|
||||
'090003': {
|
||||
symbol: 'EBICS_AUTHORISATION_ORDER_TYPE_FAILED',
|
||||
short_text: 'The subscriber is not entitled to submit orders of the selected order type',
|
||||
},
|
||||
'090004': {
|
||||
symbol: 'EBICS_INVALID_ORDER_DATA_FORMAT',
|
||||
short_text: 'The transferred order data does not correspond with the specified format',
|
||||
},
|
||||
'090005': {
|
||||
symbol: 'EBICS_NO_DOWNLOAD_DATA_AVAILABLE',
|
||||
short_text: 'No data are available at present for the selected download order type',
|
||||
},
|
||||
'090006': {
|
||||
symbol: 'EBICS_UNSUPPORTED_REQUEST_FOR_ORDER_INSTANCE',
|
||||
short_text: 'The bank system does not support the selected order request for the concrete business transaction associated with this order',
|
||||
},
|
||||
'091105': {
|
||||
symbol: 'EBICS_RECOVERY_NOT_SUPPORTED',
|
||||
short_text: 'The bank system does not support Recovery',
|
||||
},
|
||||
'091111': {
|
||||
symbol: 'EBICS_INVALID_SIGNATURE_FILE_FORMAT',
|
||||
short_text: 'The submitted ES files do not comply with the defined format The ES file cannot be parsed syntactically (no business-related verification!)',
|
||||
},
|
||||
'091114': {
|
||||
symbol: 'EBICS_ORDERID_UNKNOWN',
|
||||
short_text: 'The submitted order number is unknown',
|
||||
},
|
||||
'091115': {
|
||||
symbol: 'EBICS_ORDERID_ALREADY_EXISTS',
|
||||
short_text: 'The submitted order number is already existent',
|
||||
},
|
||||
'091116': {
|
||||
symbol: 'EBICS_PROCESSING_ERROR',
|
||||
short_text: 'During processing of the EBICS request, other business-related errors have ocurred',
|
||||
},
|
||||
'091201': {
|
||||
symbol: 'EBICS_KEYMGMT_UNSUPPORTED_VERSION_SIGNATURE',
|
||||
short_text: 'The algorithm version of the bank-technical signature key is not supported by the financial institution (order types INI, HCS and PUB)',
|
||||
},
|
||||
'091202': {
|
||||
symbol: 'EBICS_KEYMGMT_UNSUPPORTED_VERSION_AUTHENTICATION',
|
||||
short_text: 'The algorithm version of theauthentication key is notsupported by the financialinstitution (order types HIA,HSA and HCA)',
|
||||
},
|
||||
'091203': {
|
||||
symbol: 'EBICS_KEYMGMT_UNSUPPORTED_VERSION_ENCRYPTION',
|
||||
short_text: 'The algorithm version of the encryption key is not supported by the financial institution (order types HIA, HSA and HCA) This error message is returned particularly when the process ID E001 is used which is invalid from schema version H003 on',
|
||||
},
|
||||
'091204': {
|
||||
symbol: 'EBICS_KEYMGMT_KEYLENGTH_ERROR_SIGNATURE',
|
||||
short_text: 'The key length of the banktechnical signature key is not supported by the financial institution (order types INI and PUB or HCS)',
|
||||
},
|
||||
'091205': {
|
||||
symbol: 'EBICS_KEYMGMT_KEYLENGTH_ERROR_AUTHENTICATION',
|
||||
short_text: 'The key length of the authentication key is not supported by the financial institution (order types HIA, HSA, HCS and HCA)',
|
||||
},
|
||||
'091206': {
|
||||
symbol: 'EBICS_KEYMGMT_KEYLENGTH_ERROR_ENCRYPTION',
|
||||
short_text: 'The key length of the encryption key is not supported by the financial institution (order types HIA, HSA, HCS and HCA)',
|
||||
},
|
||||
'091207': {
|
||||
symbol: 'EBICS_KEYMGMT_NO_X509_SUPPORT',
|
||||
short_text: 'The bank system does not support the evaluation of X.509 data (order types INI, HIA, HSA, PUB, HCA, HCS)',
|
||||
},
|
||||
'091208': {
|
||||
symbol: 'EBICS_X509_CERTIFICATE_EXPIRED',
|
||||
short_text: 'certificate is not valid because it has expired',
|
||||
},
|
||||
'091209': {
|
||||
symbol: 'EBICS_X509_ERTIFICATE_NOT_VALID_YET',
|
||||
short_text: 'certificate is not valid because it is not yet in effect',
|
||||
},
|
||||
'091210': {
|
||||
symbol: 'EBICS_X509_WRONG_KEY_USAGE',
|
||||
short_text: 'When verifying the certificate key usage, it has been detected that the certificate has not been issued for the current use. (only applies when key management order types are used)',
|
||||
},
|
||||
'091211': {
|
||||
symbol: 'EBICS_X509_WRONG_ALGORITHM',
|
||||
short_text: 'When verifying the certificate algorithm, it has been detected that the certificate has not been issued for the current use. (only applies when key management order types are used)',
|
||||
},
|
||||
'091212': {
|
||||
symbol: 'EBICS_X509_INVALID_THUMBPRINT',
|
||||
short_text: 'Reserved for next version',
|
||||
},
|
||||
'091213': {
|
||||
symbol: 'EBICS_X509_CTL_INVALID',
|
||||
short_text: 'When verifying the certificate, it has been detected that the certificate trust list (CTL) is not valid because, for example, it has expired.',
|
||||
},
|
||||
'091214': {
|
||||
symbol: 'EBICS_X509_UNKNOWN_CERTIFICATE_AUTHORITY',
|
||||
short_text: 'The chain cannot be verified due to an unknown certificate authority (CA) If OrderType = INI, PUB or HCS and X509v3 supported: The Reject of the Request is mandatory, if signature class <> "T"',
|
||||
},
|
||||
'091215': {
|
||||
symbol: 'EBICS_X509_INVALID_POLICY',
|
||||
short_text: 'Reserved for next version',
|
||||
},
|
||||
'091216': {
|
||||
symbol: 'EBICS_X509_INVALID_BASIC_CONSTRAINTS',
|
||||
short_text: 'Reserved for next version',
|
||||
},
|
||||
'091217': {
|
||||
symbol: 'EBICS_ONLY_X509_SUPPORT',
|
||||
short_text: 'With respect to certificates, the bank system only supports the evaluation of X.509 data',
|
||||
},
|
||||
'091218': {
|
||||
symbol: 'EBICS_KEYMGMT_DUPLICATE_KEY',
|
||||
short_text: 'During the key management request, it has been detected that the key or certificate sent for authentication or for encryption is the same as the signature key/certificate (INI, HIA, PUB, HCS,..)',
|
||||
},
|
||||
'091219': {
|
||||
symbol: 'EBICS_CERTIFICATES_VALIDATION_ERROR',
|
||||
short_text: 'The server is unable to match the certificate (ES key) with the previously declared information automatically.',
|
||||
},
|
||||
'091301': {
|
||||
symbol: 'EBICS_SIGNATURE_VERIFICATION_FAILED',
|
||||
short_text: 'Verification of the ES has failed In the case of asynchronouslyimplemented orders, the error can occur during preliminary verification.',
|
||||
},
|
||||
'091302': {
|
||||
symbol: 'EBICS_ACCOUNT_AUTHORISATION_FAILED',
|
||||
short_text: 'Preliminary verification of the account authorisation has failed',
|
||||
},
|
||||
'091303': {
|
||||
symbol: 'EBICS_AMOUNT_CHECK_FAILED',
|
||||
short_text: 'Preliminary verification of the account amount limit has failed',
|
||||
},
|
||||
'091304': {
|
||||
symbol: 'EBICS_SIGNER_UNKNOWN',
|
||||
short_text: 'A signatory of the order in question is not a valid subscriber.',
|
||||
},
|
||||
'091305': {
|
||||
symbol: 'EBICS_INVALID_SIGNER_STATE',
|
||||
short_text: 'The state of a signatory in the order in question is not admissible.',
|
||||
},
|
||||
'091306': {
|
||||
symbol: 'EBICS_DUPLICATE_SIGNATURE',
|
||||
short_text: 'The signatory has already signed the order on hand.',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = errors;
|
181
lib/orders/H004/response.js
Normal file
181
lib/orders/H004/response.js
Normal file
@@ -0,0 +1,181 @@
|
||||
'use strict';
|
||||
|
||||
const zlib = require('zlib');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const Crypto = require('../../crypto/Crypto');
|
||||
|
||||
const { DOMParser, XMLSerializer } = require('@xmldom/xmldom');
|
||||
const xpath = require('xpath');
|
||||
const errors = require('./errors');
|
||||
|
||||
const DEFAULT_IV = Buffer.from(Array(16).fill(0, 0, 15));
|
||||
|
||||
const lastChild = (node) => {
|
||||
let y = node.lastChild;
|
||||
|
||||
while (y.nodeType !== 1) y = y.previousSibling;
|
||||
|
||||
return y;
|
||||
};
|
||||
|
||||
module.exports = (xml, keys) => ({
|
||||
keys,
|
||||
doc: new DOMParser().parseFromString(xml, 'text/xml'),
|
||||
|
||||
isSegmented() {
|
||||
const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' });
|
||||
const node = select(
|
||||
'//xmlns:header/xmlns:mutable/xmlns:SegmentNumber',
|
||||
this.doc,
|
||||
);
|
||||
|
||||
return !!node.length;
|
||||
},
|
||||
|
||||
isLastSegment() {
|
||||
const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' });
|
||||
const node = select(
|
||||
"//xmlns:header/xmlns:mutable/*[@lastSegment='true']",
|
||||
this.doc,
|
||||
);
|
||||
|
||||
return !!node.length;
|
||||
},
|
||||
|
||||
orderData() {
|
||||
const orderDataNode = this.doc.getElementsByTagNameNS(
|
||||
'urn:org:ebics:H004',
|
||||
'OrderData',
|
||||
);
|
||||
|
||||
if (!orderDataNode.length) return {};
|
||||
|
||||
const orderData = orderDataNode[0].textContent;
|
||||
const decipher = crypto
|
||||
.createDecipheriv('aes-128-cbc', this.transactionKey(), DEFAULT_IV)
|
||||
.setAutoPadding(false);
|
||||
const data = Buffer.from(
|
||||
decipher.update(orderData, 'base64', 'binary')
|
||||
+ decipher.final('binary'),
|
||||
'binary',
|
||||
);
|
||||
|
||||
return zlib.inflateSync(data);
|
||||
},
|
||||
|
||||
transactionKey() {
|
||||
const keyNodeText = this.doc.getElementsByTagNameNS(
|
||||
'urn:org:ebics:H004',
|
||||
'TransactionKey',
|
||||
)[0].textContent;
|
||||
return Crypto.privateDecrypt(
|
||||
this.keys.e(),
|
||||
Buffer.from(keyNodeText, 'base64'),
|
||||
);
|
||||
},
|
||||
|
||||
transactionId() {
|
||||
const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' });
|
||||
const node = select(
|
||||
'//xmlns:header/xmlns:static/xmlns:TransactionID',
|
||||
this.doc,
|
||||
);
|
||||
|
||||
return node.length ? node[0].textContent : '';
|
||||
},
|
||||
|
||||
orderId() {
|
||||
const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' });
|
||||
const node = select(
|
||||
'.//xmlns:header/xmlns:mutable/xmlns:OrderID',
|
||||
this.doc,
|
||||
);
|
||||
|
||||
return node.length ? node[0].textContent : '';
|
||||
},
|
||||
|
||||
businessCode() {
|
||||
const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' });
|
||||
const node = select('//xmlns:body/xmlns:ReturnCode', this.doc);
|
||||
|
||||
return node.length ? node[0].textContent : '';
|
||||
},
|
||||
|
||||
businessSymbol(code) {
|
||||
return errors.business[code].symbol;
|
||||
},
|
||||
|
||||
businessShortText(code) {
|
||||
return errors.business[code].short_text;
|
||||
},
|
||||
|
||||
businessMeaning(code) {
|
||||
return errors.business[code].meaning;
|
||||
},
|
||||
|
||||
technicalCode() {
|
||||
const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' });
|
||||
const node = select(
|
||||
'//xmlns:header/xmlns:mutable/xmlns:ReturnCode',
|
||||
this.doc,
|
||||
);
|
||||
|
||||
return node.length ? node[0].textContent : '';
|
||||
},
|
||||
|
||||
technicalSymbol() {
|
||||
const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' });
|
||||
const node = select(
|
||||
'//xmlns:header/xmlns:mutable/xmlns:ReportText',
|
||||
this.doc,
|
||||
);
|
||||
|
||||
return node.length ? node[0].textContent : '';
|
||||
},
|
||||
|
||||
technicalShortText(code) {
|
||||
return errors.technical[code].short_text;
|
||||
},
|
||||
|
||||
technicalMeaning(code) {
|
||||
return errors.technical[code].meaning;
|
||||
},
|
||||
|
||||
bankKeys() {
|
||||
const orderData = this.orderData().toString();
|
||||
if (!Object.keys(orderData).length) return {};
|
||||
|
||||
const doc = new DOMParser().parseFromString(orderData, 'text/xml');
|
||||
const select = xpath.useNamespaces({ xmlns: 'urn:org:ebics:H004' });
|
||||
const keyNodes = select('//xmlns:PubKeyValue', doc);
|
||||
const bankKeys = {};
|
||||
|
||||
if (!keyNodes.length) return {};
|
||||
|
||||
for (let i = 0; i < keyNodes.length; i++) {
|
||||
const type = lastChild(keyNodes[i].parentNode).textContent;
|
||||
const modulus = xpath.select(
|
||||
".//*[local-name(.)='Modulus']",
|
||||
keyNodes[i],
|
||||
)[0].textContent;
|
||||
const exponent = xpath.select(
|
||||
".//*[local-name(.)='Exponent']",
|
||||
keyNodes[i],
|
||||
)[0].textContent;
|
||||
|
||||
const mod = Buffer.from(modulus, 'base64');
|
||||
const exp = Buffer.from(exponent, 'base64');
|
||||
bankKeys[`bank${type}`] = {
|
||||
mod,
|
||||
exp,
|
||||
};
|
||||
}
|
||||
|
||||
return bankKeys;
|
||||
},
|
||||
|
||||
toXML() {
|
||||
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 constants = require('../../consts');
|
||||
|
||||
const iniSerializer = require('./serializers/ini');
|
||||
const downloadSerializer = require('./serializers/download');
|
||||
const uploadSerializer = require('./serializers/upload');
|
||||
|
||||
module.exports = {
|
||||
use(order, client) {
|
||||
const operation = order.operation.toUpperCase();
|
||||
|
||||
if (operation === constants.orderOperations.ini) return iniSerializer.use(order, client);
|
||||
if (operation === constants.orderOperations.download) return downloadSerializer.use(order, client);
|
||||
if (operation === constants.orderOperations.upload) return uploadSerializer.use(order, client);
|
||||
|
||||
throw Error('Error from orders/orders.js: Wrong order version/type.');
|
||||
},
|
||||
};
|
66
lib/orders/H004/serializers/download.js
Normal file
66
lib/orders/H004/serializers/download.js
Normal file
@@ -0,0 +1,66 @@
|
||||
'use strict';
|
||||
|
||||
const js2xmlparser = require('js2xmlparser');
|
||||
|
||||
const Crypto = require('../../../crypto/Crypto');
|
||||
const genericSerializer = require('./generic');
|
||||
|
||||
module.exports = {
|
||||
async use(order, client) {
|
||||
const keys = await client.keys();
|
||||
const ebicsAccount = {
|
||||
partnerId: client.partnerId,
|
||||
userId: client.userId,
|
||||
hostId: client.hostId,
|
||||
};
|
||||
const { orderDetails, transactionId } = order;
|
||||
const {
|
||||
rootName, xmlOptions, xmlSchema, receipt, transfer, productString,
|
||||
} = genericSerializer(client.hostId, transactionId);
|
||||
|
||||
this.productString = productString;
|
||||
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: ebicsAccount.hostId,
|
||||
Nonce: Crypto.nonce(),
|
||||
Timestamp: Crypto.timestamp(),
|
||||
PartnerID: ebicsAccount.partnerId,
|
||||
UserID: ebicsAccount.userId,
|
||||
Product: {
|
||||
'@': { Language: 'en' },
|
||||
'#': productString,
|
||||
},
|
||||
OrderDetails: orderDetails,
|
||||
BankPubKeyDigests: {
|
||||
Authentication: {
|
||||
'@': { Version: 'X002', Algorithm: 'http://www.w3.org/2001/04/xmlenc#sha256' },
|
||||
'#': Crypto.digestPublicKey(keys.bankX()),
|
||||
},
|
||||
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);
|
||||
},
|
||||
};
|
134
lib/orders/H004/serializers/generic.js
Normal file
134
lib/orders/H004/serializers/generic.js
Normal file
@@ -0,0 +1,134 @@
|
||||
'use strict';
|
||||
|
||||
const constants = require('../../../consts');
|
||||
|
||||
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 = (hostId, transactionId) => ({
|
||||
// return {
|
||||
productString: constants.productString,
|
||||
rootName,
|
||||
xmlOptions,
|
||||
xmlSchema: {
|
||||
'@': rootAttributes,
|
||||
header,
|
||||
AuthSignature: authSignature,
|
||||
body,
|
||||
},
|
||||
|
||||
receipt() {
|
||||
this.xmlSchema = {
|
||||
'@': rootAttributes,
|
||||
|
||||
header: {
|
||||
'@': { authenticate: true },
|
||||
static: {
|
||||
HostID: 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: hostId,
|
||||
TransactionID: transactionId,
|
||||
},
|
||||
mutable: {
|
||||
TransactionPhase: 'Transfer',
|
||||
SegmentNumber: {
|
||||
'@': { lastSegment: true },
|
||||
'#': 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
AuthSignature: authSignature,
|
||||
|
||||
body: {
|
||||
DataTransfer: {
|
||||
OrderData: encryptedOrderData,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return this;
|
||||
},
|
||||
// };
|
||||
});
|
148
lib/orders/H004/serializers/ini.js
Normal file
148
lib/orders/H004/serializers/ini.js
Normal file
@@ -0,0 +1,148 @@
|
||||
'use strict';
|
||||
|
||||
const zlib = require('zlib');
|
||||
|
||||
const js2xmlparser = require('js2xmlparser');
|
||||
|
||||
const Crypto = require('../../../crypto/Crypto');
|
||||
|
||||
const genericSerializer = require('./generic');
|
||||
|
||||
const keySignature = (ebicsAccount, 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: ebicsAccount.partnerId,
|
||||
UserID: ebicsAccount.userId,
|
||||
};
|
||||
|
||||
return js2xmlparser.parse('SignaturePubKeyOrderData', xmlOrderData, xmlOptions);
|
||||
};
|
||||
const orderData = (ebicsAccount, 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: ebicsAccount.partnerId,
|
||||
UserID: ebicsAccount.userId,
|
||||
};
|
||||
|
||||
return js2xmlparser.parse('HIARequestOrderData', xmlOrderData, xmlOptions);
|
||||
};
|
||||
const commonHeader = (ebicsAccount, orderDetails, productString) => ({
|
||||
'@': { authenticate: true },
|
||||
static: {
|
||||
HostID: ebicsAccount.hostId,
|
||||
Nonce: Crypto.nonce(),
|
||||
Timestamp: Crypto.timestamp(),
|
||||
PartnerID: ebicsAccount.partnerId,
|
||||
UserID: ebicsAccount.userId,
|
||||
Product: {
|
||||
'@': { Language: 'en' },
|
||||
'#': productString,
|
||||
},
|
||||
OrderDetails: orderDetails,
|
||||
SecurityMedium: '0000',
|
||||
},
|
||||
mutable: {},
|
||||
});
|
||||
const process = {
|
||||
INI: {
|
||||
rootName: 'ebicsUnsecuredRequest',
|
||||
header: (ebicsAccount, orderDetails, productString) => {
|
||||
const ch = commonHeader(ebicsAccount, orderDetails, productString);
|
||||
|
||||
delete ch.static.Nonce;
|
||||
delete ch.static.Timestamp;
|
||||
|
||||
return ch;
|
||||
},
|
||||
body: (ebicsAccount, keys, xmlOptions) => ({
|
||||
DataTransfer: {
|
||||
OrderData: Buffer.from(zlib.deflateSync(keySignature(ebicsAccount, keys.a(), xmlOptions))).toString('base64'),
|
||||
},
|
||||
}),
|
||||
},
|
||||
HIA: {
|
||||
rootName: 'ebicsUnsecuredRequest',
|
||||
header: (ebicsAccount, orderDetails, productString) => {
|
||||
const ch = commonHeader(ebicsAccount, orderDetails, productString);
|
||||
|
||||
delete ch.static.Nonce;
|
||||
delete ch.static.Timestamp;
|
||||
|
||||
return ch;
|
||||
},
|
||||
body: (ebicsAccount, keys, xmlOptions) => ({
|
||||
DataTransfer: {
|
||||
OrderData: Buffer.from(zlib.deflateSync(orderData(ebicsAccount, keys, xmlOptions))).toString('base64'),
|
||||
},
|
||||
}),
|
||||
},
|
||||
HPB: {
|
||||
rootName: 'ebicsNoPubKeyDigestsRequest',
|
||||
header: (ebicsAccount, orderDetails, productString) => commonHeader(ebicsAccount, orderDetails, productString),
|
||||
body: () => ({}),
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
async use(order, client) {
|
||||
const keys = await client.keys();
|
||||
const { orderDetails, transactionId } = order;
|
||||
const { xmlOptions, xmlSchema, productString } = genericSerializer(client.host, transactionId);
|
||||
const orderType = orderDetails.OrderType.toUpperCase();
|
||||
const ebicsAccount = {
|
||||
partnerId: client.partnerId,
|
||||
userId: client.userId,
|
||||
hostId: client.hostId,
|
||||
};
|
||||
|
||||
this.rootName = process[orderType].rootName;
|
||||
this.xmlOptions = xmlOptions;
|
||||
this.xmlSchema = xmlSchema;
|
||||
|
||||
this.xmlSchema.header = process[orderType].header(ebicsAccount, orderDetails, productString);
|
||||
this.xmlSchema.body = process[orderType].body(ebicsAccount, keys, this.xmlOptions);
|
||||
|
||||
if (orderType !== 'HPB' && Object.prototype.hasOwnProperty.call(this.xmlSchema, 'AuthSignature'))
|
||||
delete this.xmlSchema.AuthSignature;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
toXML() {
|
||||
return js2xmlparser.parse(this.rootName, this.xmlSchema, this.xmlOptions);
|
||||
},
|
||||
};
|
93
lib/orders/H004/serializers/upload.js
Normal file
93
lib/orders/H004/serializers/upload.js
Normal file
@@ -0,0 +1,93 @@
|
||||
'use strict';
|
||||
|
||||
const zlib = require('zlib');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const js2xmlparser = require('js2xmlparser');
|
||||
|
||||
const Crypto = require('../../../crypto/Crypto');
|
||||
|
||||
const downloadSerializer = require('./download');
|
||||
|
||||
const transKey = crypto.randomBytes(16);
|
||||
|
||||
const signatureValue = (document, key) => {
|
||||
const digested = Crypto.digestWithHash(document.replace(/\n|\r/g, ''));
|
||||
|
||||
return Crypto.sign(key, digested);
|
||||
};
|
||||
const orderSignature = (ebicsAccount, 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: ebicsAccount.partnerId,
|
||||
UserID: ebicsAccount.userId,
|
||||
},
|
||||
};
|
||||
|
||||
return js2xmlparser.parse('UserSignatureData', xmlObj, xmlOptions);
|
||||
};
|
||||
const encryptedOrderSignature = (ebicsAccount, document, transactionKey, key, xmlOptions) => {
|
||||
const dst = zlib.deflateSync(orderSignature(ebicsAccount, document, key, xmlOptions));
|
||||
const cipher = crypto.createCipheriv('aes-128-cbc', transactionKey, Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])).setAutoPadding(false);
|
||||
|
||||
return Buffer.concat([cipher.update(Crypto.pad(dst)), cipher.final()]).toString('base64');
|
||||
};
|
||||
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 = {
|
||||
async use(order, client) {
|
||||
const keys = await client.keys();
|
||||
const ebicsAccount = {
|
||||
partnerId: client.partnerId,
|
||||
userId: client.userId,
|
||||
hostId: client.hostId,
|
||||
};
|
||||
const { transactionId, document } = order;
|
||||
const {
|
||||
rootName, xmlOptions, xmlSchema, transfer,
|
||||
} = await downloadSerializer.use(order, client);
|
||||
|
||||
this.rootName = rootName;
|
||||
this.xmlOptions = xmlOptions;
|
||||
this.xmlSchema = xmlSchema;
|
||||
this.transfer = transfer;
|
||||
|
||||
if (transactionId) return this.transfer(encryptedOrderData(document, transKey));
|
||||
|
||||
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(), transKey).toString('base64'),
|
||||
},
|
||||
SignatureData: {
|
||||
'@': { authenticate: true },
|
||||
'#': encryptedOrderSignature(ebicsAccount, document, transKey, keys.a(), this.xmlOptions),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
toXML() {
|
||||
return js2xmlparser.parse(this.rootName, this.xmlSchema, this.xmlOptions);
|
||||
},
|
||||
};
|
62
lib/orders/H004/signer.js
Normal file
62
lib/orders/H004/signer.js
Normal file
@@ -0,0 +1,62 @@
|
||||
'use strict';
|
||||
|
||||
// const crypto = require('crypto');
|
||||
const Crypto = require('../../crypto/Crypto');
|
||||
|
||||
const { DOMParser, XMLSerializer } = require('@xmldom/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, keyX) {
|
||||
const doc = new DOMParser().parseFromString(data, 'text/xml');
|
||||
|
||||
return toXML(sign(digest(doc), keyX));
|
||||
},
|
||||
};
|
@@ -1,43 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const GenericOrder = require('./GenericOrder');
|
||||
|
||||
module.exports = class HAA extends GenericOrder {
|
||||
constructor (client) {
|
||||
super(client);
|
||||
|
||||
this._schema.header = {
|
||||
"@": { authenticate: true },
|
||||
static: {
|
||||
HostID: this.hostId,
|
||||
Nonce: this.nonce(),
|
||||
Timestamp: this.timestamp(),
|
||||
PartnerID: this.partnerId,
|
||||
UserID: this.userId,
|
||||
Product: {
|
||||
"@": { Language: "de" },
|
||||
"#": this.productString
|
||||
},
|
||||
OrderDetails: {
|
||||
OrderType: "HAA",
|
||||
OrderAttribute: "DZHNN",
|
||||
StandardOrderParams: ""
|
||||
},
|
||||
BankPubKeyDigests: {
|
||||
Authentication: {
|
||||
"@": { Version: "X002", Algorithm: "http://www.w3.org/2001/04/xmlenc#sha256" },
|
||||
"#": this.client.bankX().publicDigest()
|
||||
},
|
||||
Encryption: {
|
||||
"@": { Version: "E002", Algorithm: "http://www.w3.org/2001/04/xmlenc#sha256" },
|
||||
"#": this.client.bankE().publicDigest()
|
||||
}
|
||||
},
|
||||
SecurityMedium: "0000"
|
||||
},
|
||||
mutable: {
|
||||
TransactionPhase: "Initialisation"
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
@@ -1,54 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const GenericOrder = require('./GenericOrder');
|
||||
|
||||
module.exports = class HAC extends GenericOrder {
|
||||
constructor (client, from = null, to = null) {
|
||||
super(client);
|
||||
this._from = from;
|
||||
this._to = to;
|
||||
|
||||
this._schema.header = {
|
||||
"@" : { authenticate: true },
|
||||
static: {
|
||||
HostID : this.hostId,
|
||||
Nonce : this.nonce(),
|
||||
Timestamp: this.timestamp(),
|
||||
PartnerID: this.partnerId,
|
||||
UserID : this.userId,
|
||||
Product : {
|
||||
"@": { Language: "de" },
|
||||
"#": this.productString,
|
||||
},
|
||||
OrderDetails: {
|
||||
OrderType : "HAC",
|
||||
OrderAttribute : "DZHNN",
|
||||
StandardOrderParams: this._hasDateRange() ? {
|
||||
DateRange: {
|
||||
Start: this._from,
|
||||
End : this._to
|
||||
}
|
||||
} : ""
|
||||
},
|
||||
BankPubKeyDigests: {
|
||||
Authentication: {
|
||||
"@": { Version: "X002", Algorithm: "http://www.w3.org/2001/04/xmlenc#sha256" },
|
||||
"#": this.client.bankX().publicDigest()
|
||||
},
|
||||
Encryption: {
|
||||
"@": { Version: "E002", Algorithm: "http://www.w3.org/2001/04/xmlenc#sha256" },
|
||||
"#": this.client.bankE().publicDigest()
|
||||
}
|
||||
},
|
||||
SecurityMedium: "0000"
|
||||
},
|
||||
mutable: {
|
||||
TransactionPhase: "Initialisation"
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
_hasDateRange() {
|
||||
return this._from && this._to;
|
||||
}
|
||||
};
|
@@ -1,85 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const zlib = require('zlib');
|
||||
const js2xmlparser = require('js2xmlparser');
|
||||
|
||||
const GenericOrder = require('./GenericOrder');
|
||||
|
||||
module.exports = class HIA extends GenericOrder {
|
||||
constructor(client) {
|
||||
super(client);
|
||||
|
||||
this._schema = {
|
||||
"@": {
|
||||
"xmlns:ds": "http://www.w3.org/2000/09/xmldsig#",
|
||||
xmlns: "urn:org:ebics:H004",
|
||||
Version: "H004",
|
||||
Revision: "1"
|
||||
},
|
||||
|
||||
header: {
|
||||
"@": { authenticate: true },
|
||||
static: {
|
||||
HostID: this.hostId,
|
||||
PartnerID: this.partnerId,
|
||||
UserID: this.userId,
|
||||
Product: {
|
||||
"@": { Language: "de" },
|
||||
"#": this.productString,
|
||||
},
|
||||
OrderDetails: {
|
||||
OrderType: "HIA",
|
||||
OrderAttribute: "DZNNN"
|
||||
},
|
||||
SecurityMedium: "0000"
|
||||
},
|
||||
mutable: {}
|
||||
},
|
||||
|
||||
body: {
|
||||
DataTransfer: {
|
||||
OrderData: Buffer.from(zlib.deflateSync(this.orderData())).toString('base64')
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
root() {
|
||||
return "ebicsUnsecuredRequest";
|
||||
};
|
||||
|
||||
orderData() {
|
||||
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.client.x().n(), 'HEX').toString('base64'),
|
||||
"ds:Exponent": "AQAB"
|
||||
},
|
||||
},
|
||||
AuthenticationVersion: "X002"
|
||||
},
|
||||
EncryptionPubKeyInfo: {
|
||||
PubKeyValue: {
|
||||
"ds:RSAKeyValue": {
|
||||
"ds:Modulus": Buffer.from(this.client.e().n(), 'HEX').toString('base64'),
|
||||
"ds:Exponent": "AQAB"
|
||||
},
|
||||
},
|
||||
EncryptionVersion: "E002"
|
||||
},
|
||||
PartnerID: this.partnerId,
|
||||
UserID: this.userId
|
||||
};
|
||||
|
||||
return js2xmlparser.parse("HIARequestOrderData", xmlOrderData, this.xmlOptions);
|
||||
};
|
||||
|
||||
toXML() {
|
||||
return js2xmlparser.parse(this.root(), this._schema, this.xmlOptions);
|
||||
};
|
||||
};
|
@@ -1,43 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const GenericOrder = require('./GenericOrder');
|
||||
|
||||
module.exports = class HKD extends GenericOrder {
|
||||
constructor (client) {
|
||||
super(client);
|
||||
|
||||
this._schema.header = {
|
||||
"@": { authenticate: true },
|
||||
static: {
|
||||
HostID: this.hostId,
|
||||
Nonce: this.nonce(),
|
||||
Timestamp: this.timestamp(),
|
||||
PartnerID: this.partnerId,
|
||||
UserID: this.userId,
|
||||
Product: {
|
||||
"@": { Language: "de" },
|
||||
"#": this.productString,
|
||||
},
|
||||
OrderDetails: {
|
||||
OrderType: "HKD",
|
||||
OrderAttribute: "DZHNN",
|
||||
StandardOrderParams: ""
|
||||
},
|
||||
BankPubKeyDigests: {
|
||||
Authentication: {
|
||||
"@": { Version: "X002", Algorithm: "http://www.w3.org/2001/04/xmlenc#sha256" },
|
||||
"#": this.client.bankX().publicDigest()
|
||||
},
|
||||
Encryption: {
|
||||
"@": { Version: "E002", Algorithm: "http://www.w3.org/2001/04/xmlenc#sha256" },
|
||||
"#": this.client.bankE().publicDigest()
|
||||
}
|
||||
},
|
||||
SecurityMedium: "0000"
|
||||
},
|
||||
mutable: {
|
||||
TransactionPhase: "Initialisation"
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
@@ -1,34 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const GenericOrder = require('./GenericOrder');
|
||||
|
||||
module.exports = class HPB extends GenericOrder {
|
||||
constructor (client) {
|
||||
super(client);
|
||||
|
||||
this._schema.header = {
|
||||
"@": { authenticate: true },
|
||||
static: {
|
||||
HostID: this.hostId,
|
||||
Nonce: this.nonce(),
|
||||
Timestamp: this.timestamp(),
|
||||
PartnerID: this.partnerId,
|
||||
UserID: this.userId,
|
||||
Product: {
|
||||
"@": { Language: "de" },
|
||||
"#": this.productString,
|
||||
},
|
||||
OrderDetails: {
|
||||
OrderType: "HPB",
|
||||
OrderAttribute: "DZHNN"
|
||||
},
|
||||
SecurityMedium: "0000"
|
||||
},
|
||||
mutable: {}
|
||||
};
|
||||
};
|
||||
|
||||
root() {
|
||||
return "ebicsNoPubKeyDigestsRequest";
|
||||
};
|
||||
};
|
@@ -1,43 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const GenericOrder = require('./GenericOrder');
|
||||
|
||||
module.exports = class HTD extends GenericOrder {
|
||||
constructor (client) {
|
||||
super(client);
|
||||
|
||||
this._schema.header = {
|
||||
"@": { authenticate: true },
|
||||
static: {
|
||||
HostID: this.hostId,
|
||||
Nonce: this.nonce(),
|
||||
Timestamp: this.timestamp(),
|
||||
PartnerID: this.partnerId,
|
||||
UserID: this.userId,
|
||||
Product: {
|
||||
"@": { Language: "de" },
|
||||
"#": this.productString,
|
||||
},
|
||||
OrderDetails: {
|
||||
OrderType: "HTD",
|
||||
OrderAttribute: "DZHNN",
|
||||
StandardOrderParams: ""
|
||||
},
|
||||
BankPubKeyDigests: {
|
||||
Authentication: {
|
||||
"@": { Version: "X002", Algorithm: "http://www.w3.org/2001/04/xmlenc#sha256" },
|
||||
"#": this.client.bankX().publicDigest()
|
||||
},
|
||||
Encryption: {
|
||||
"@": { Version: "E002", Algorithm: "http://www.w3.org/2001/04/xmlenc#sha256" },
|
||||
"#": this.client.bankE().publicDigest()
|
||||
}
|
||||
},
|
||||
SecurityMedium: "0000"
|
||||
},
|
||||
mutable: {
|
||||
TransactionPhase: "Initialisation"
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
@@ -1,77 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const zlib = require('zlib');
|
||||
const js2xmlparser = require('js2xmlparser');
|
||||
|
||||
const GenericOrder = require('./GenericOrder');
|
||||
|
||||
module.exports = class INI extends GenericOrder {
|
||||
constructor (client) {
|
||||
super(client);
|
||||
|
||||
this._schema = {
|
||||
"@": {
|
||||
"xmlns:ds": "http://www.w3.org/2000/09/xmldsig#",
|
||||
xmlns: "urn:org:ebics:H004",
|
||||
Version: "H004",
|
||||
Revision: "1"
|
||||
},
|
||||
|
||||
header: {
|
||||
"@": { authenticate: true },
|
||||
static: {
|
||||
HostID: this.hostId,
|
||||
PartnerID: this.partnerId,
|
||||
UserID: this.userId,
|
||||
Product: {
|
||||
"@": { Language: "de" },
|
||||
"#": this.productString,
|
||||
},
|
||||
OrderDetails: {
|
||||
OrderType: "INI",
|
||||
OrderAttribute: "DZNNN"
|
||||
},
|
||||
SecurityMedium: "0000"
|
||||
},
|
||||
mutable: {}
|
||||
},
|
||||
|
||||
body: {
|
||||
DataTransfer: {
|
||||
OrderData: Buffer.from(zlib.deflateSync(this.keySignature())).toString('base64')
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
root() {
|
||||
return "ebicsUnsecuredRequest";
|
||||
};
|
||||
|
||||
keySignature() {
|
||||
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.client.a().n(), 'HEX').toString('base64'),
|
||||
"ds:Exponent": "AQAB"
|
||||
},
|
||||
TimeStamp: this.timestamp()
|
||||
},
|
||||
SignatureVersion: "A006"
|
||||
},
|
||||
PartnerID: this.partnerId,
|
||||
UserID: this.userId
|
||||
};
|
||||
|
||||
return js2xmlparser.parse("SignaturePubKeyOrderData", xmlOrderData, this.xmlOptions);
|
||||
};
|
||||
|
||||
toXML() {
|
||||
return js2xmlparser.parse(this.root(), this._schema, this.xmlOptions);
|
||||
}
|
||||
};
|
8
lib/predefinedOrders/AZV.js
Normal file
8
lib/predefinedOrders/AZV.js
Normal file
@@ -0,0 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = document => ({
|
||||
version: 'h004',
|
||||
orderDetails: { OrderType: 'AZV', OrderAttribute: 'OZHNN', StandardOrderParams: {} },
|
||||
operation: 'upload',
|
||||
document,
|
||||
});
|
13
lib/predefinedOrders/C52.js
Normal file
13
lib/predefinedOrders/C52.js
Normal 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',
|
||||
});
|
13
lib/predefinedOrders/C53.js
Normal file
13
lib/predefinedOrders/C53.js
Normal 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',
|
||||
});
|
8
lib/predefinedOrders/CCS.js
Normal file
8
lib/predefinedOrders/CCS.js
Normal file
@@ -0,0 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = document => ({
|
||||
version: 'h004',
|
||||
orderDetails: { OrderType: 'CCS', OrderAttribute: 'OZHNN', StandardOrderParams: {} },
|
||||
operation: 'upload',
|
||||
document,
|
||||
});
|
8
lib/predefinedOrders/CCT.js
Normal file
8
lib/predefinedOrders/CCT.js
Normal file
@@ -0,0 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = document => ({
|
||||
version: 'h004',
|
||||
orderDetails: { OrderType: 'CCT', OrderAttribute: 'OZHNN', StandardOrderParams: {} },
|
||||
operation: 'upload',
|
||||
document,
|
||||
});
|
8
lib/predefinedOrders/CD1.js
Normal file
8
lib/predefinedOrders/CD1.js
Normal file
@@ -0,0 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = document => ({
|
||||
version: 'h004',
|
||||
orderDetails: { OrderType: 'CD1', OrderAttribute: 'OZHNN', StandardOrderParams: {} },
|
||||
operation: 'upload',
|
||||
document,
|
||||
});
|
8
lib/predefinedOrders/CDB.js
Normal file
8
lib/predefinedOrders/CDB.js
Normal file
@@ -0,0 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = document => ({
|
||||
version: 'h004',
|
||||
orderDetails: { OrderType: 'CDB', OrderAttribute: 'OZHNN', StandardOrderParams: {} },
|
||||
operation: 'upload',
|
||||
document,
|
||||
});
|
8
lib/predefinedOrders/CDD.js
Normal file
8
lib/predefinedOrders/CDD.js
Normal file
@@ -0,0 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = document => ({
|
||||
version: 'h004',
|
||||
orderDetails: { OrderType: 'CDD', OrderAttribute: 'OZHNN', StandardOrderParams: {} },
|
||||
operation: 'upload',
|
||||
document,
|
||||
});
|
8
lib/predefinedOrders/CDS.js
Normal file
8
lib/predefinedOrders/CDS.js
Normal file
@@ -0,0 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = document => ({
|
||||
version: 'h004',
|
||||
orderDetails: { OrderType: 'CDS', OrderAttribute: 'OZHNN', StandardOrderParams: {} },
|
||||
operation: 'upload',
|
||||
document,
|
||||
});
|
13
lib/predefinedOrders/DKI.js
Normal file
13
lib/predefinedOrders/DKI.js
Normal 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',
|
||||
});
|
13
lib/predefinedOrders/G02.js
Normal file
13
lib/predefinedOrders/G02.js
Normal file
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
const utils = require('../utils');
|
||||
|
||||
module.exports = (start = null, end = null) => ({
|
||||
version: 'h004',
|
||||
orderDetails: {
|
||||
OrderType: 'G02',
|
||||
OrderAttribute: 'DZHNN',
|
||||
StandardOrderParams: utils.dateRange(start, end),
|
||||
},
|
||||
operation: 'download',
|
||||
});
|
8
lib/predefinedOrders/G1R.js
Normal file
8
lib/predefinedOrders/G1R.js
Normal file
@@ -0,0 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = document => ({
|
||||
version: 'h004',
|
||||
orderDetails: { OrderType: 'G1R', OrderAttribute: 'DZHNN', StandardOrderParams: {} },
|
||||
operation: 'upload',
|
||||
document,
|
||||
});
|
8
lib/predefinedOrders/G1V.js
Normal file
8
lib/predefinedOrders/G1V.js
Normal file
@@ -0,0 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = document => ({
|
||||
version: 'h004',
|
||||
orderDetails: { OrderType: 'G1V', OrderAttribute: 'DZHNN', StandardOrderParams: {} },
|
||||
operation: 'upload',
|
||||
document,
|
||||
});
|
13
lib/predefinedOrders/G52.js
Normal file
13
lib/predefinedOrders/G52.js
Normal file
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
const utils = require('../utils');
|
||||
|
||||
module.exports = (start = null, end = null) => ({
|
||||
version: 'h004',
|
||||
orderDetails: {
|
||||
OrderType: 'G52',
|
||||
OrderAttribute: 'DZHNN',
|
||||
StandardOrderParams: utils.dateRange(start, end),
|
||||
},
|
||||
operation: 'download',
|
||||
});
|
13
lib/predefinedOrders/G53.js
Normal file
13
lib/predefinedOrders/G53.js
Normal file
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
const utils = require('../utils');
|
||||
|
||||
module.exports = (start = null, end = null) => ({
|
||||
version: 'h004',
|
||||
orderDetails: {
|
||||
OrderType: 'G53',
|
||||
OrderAttribute: 'DZHNN',
|
||||
StandardOrderParams: utils.dateRange(start, end),
|
||||
},
|
||||
operation: 'download',
|
||||
});
|
11
lib/predefinedOrders/HAA.js
Normal file
11
lib/predefinedOrders/HAA.js
Normal file
@@ -0,0 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
version: 'h004',
|
||||
orderDetails: {
|
||||
OrderType: 'HAA',
|
||||
OrderAttribute: 'DZHNN',
|
||||
StandardOrderParams: {},
|
||||
},
|
||||
operation: 'download',
|
||||
};
|
13
lib/predefinedOrders/HAC.js
Normal file
13
lib/predefinedOrders/HAC.js
Normal file
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
const utils = require('../utils');
|
||||
|
||||
module.exports = (start = null, end = null) => ({
|
||||
version: 'h004',
|
||||
orderDetails: {
|
||||
OrderType: 'HAC',
|
||||
OrderAttribute: 'DZHNN',
|
||||
StandardOrderParams: utils.dateRange(start, end),
|
||||
},
|
||||
operation: 'download',
|
||||
});
|
7
lib/predefinedOrders/HIA.js
Normal file
7
lib/predefinedOrders/HIA.js
Normal file
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
version: 'h004',
|
||||
orderDetails: { OrderType: 'HIA', OrderAttribute: 'DZNNN' },
|
||||
operation: 'ini',
|
||||
};
|
11
lib/predefinedOrders/HKD.js
Normal file
11
lib/predefinedOrders/HKD.js
Normal file
@@ -0,0 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
version: 'h004',
|
||||
orderDetails: {
|
||||
OrderType: 'HKD',
|
||||
OrderAttribute: 'DZHNN',
|
||||
StandardOrderParams: {},
|
||||
},
|
||||
operation: 'download',
|
||||
};
|
7
lib/predefinedOrders/HPB.js
Normal file
7
lib/predefinedOrders/HPB.js
Normal file
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
version: 'h004',
|
||||
orderDetails: { OrderType: 'HPB', OrderAttribute: 'DZHNN' },
|
||||
operation: 'ini',
|
||||
};
|
11
lib/predefinedOrders/HPD.js
Normal file
11
lib/predefinedOrders/HPD.js
Normal file
@@ -0,0 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
version: 'h004',
|
||||
orderDetails: {
|
||||
OrderType: 'HPD',
|
||||
OrderAttribute: 'DZHNN',
|
||||
StandardOrderParams: {},
|
||||
},
|
||||
operation: 'download',
|
||||
};
|
11
lib/predefinedOrders/HTD.js
Normal file
11
lib/predefinedOrders/HTD.js
Normal file
@@ -0,0 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
version: 'h004',
|
||||
orderDetails: {
|
||||
OrderType: 'HTD',
|
||||
OrderAttribute: 'DZHNN',
|
||||
StandardOrderParams: {},
|
||||
},
|
||||
operation: 'download',
|
||||
};
|
7
lib/predefinedOrders/INI.js
Normal file
7
lib/predefinedOrders/INI.js
Normal file
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
version: 'h004',
|
||||
orderDetails: { OrderType: 'INI', OrderAttribute: 'DZNNN' },
|
||||
operation: 'ini',
|
||||
};
|
13
lib/predefinedOrders/PTK.js
Normal file
13
lib/predefinedOrders/PTK.js
Normal file
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
const utils = require('../utils');
|
||||
|
||||
module.exports = (start = null, end = null) => ({
|
||||
version: 'h004',
|
||||
orderDetails: {
|
||||
OrderType: 'PTK',
|
||||
OrderAttribute: 'DZHNN',
|
||||
StandardOrderParams: utils.dateRange(start, end),
|
||||
},
|
||||
operation: 'download',
|
||||
});
|
13
lib/predefinedOrders/STA.js
Normal file
13
lib/predefinedOrders/STA.js
Normal file
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
const utils = require('../utils');
|
||||
|
||||
module.exports = (start = null, end = null) => ({
|
||||
version: 'h004',
|
||||
orderDetails: {
|
||||
OrderType: 'STA',
|
||||
OrderAttribute: 'DZHNN',
|
||||
StandardOrderParams: utils.dateRange(start, end),
|
||||
},
|
||||
operation: 'download',
|
||||
});
|
13
lib/predefinedOrders/VMK.js
Normal file
13
lib/predefinedOrders/VMK.js
Normal file
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
const utils = require('../utils');
|
||||
|
||||
module.exports = (start = null, end = null) => ({
|
||||
version: 'h004',
|
||||
orderDetails: {
|
||||
OrderType: 'VMK',
|
||||
OrderAttribute: 'DZHNN',
|
||||
StandardOrderParams: utils.dateRange(start, end),
|
||||
},
|
||||
operation: 'download',
|
||||
});
|
8
lib/predefinedOrders/XCT.js
Normal file
8
lib/predefinedOrders/XCT.js
Normal file
@@ -0,0 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = document => ({
|
||||
version: 'h004',
|
||||
orderDetails: { OrderType: 'XCT', OrderAttribute: 'OZHNN', StandardOrderParams: {} },
|
||||
operation: 'upload',
|
||||
document,
|
||||
});
|
8
lib/predefinedOrders/XE3.js
Normal file
8
lib/predefinedOrders/XE3.js
Normal file
@@ -0,0 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = document => ({
|
||||
version: 'h004',
|
||||
orderDetails: { OrderType: 'XE3', OrderAttribute: 'OZHNN', StandardOrderParams: {} },
|
||||
operation: 'upload',
|
||||
document,
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user