@coderoftime/fints 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. package/CHANGELOG.md +152 -0
  2. package/LICENSE +28 -0
  3. package/README.md +246 -2
  4. package/dist/client.d.ts +48 -0
  5. package/dist/client.d.ts.map +1 -0
  6. package/dist/client.js +199 -0
  7. package/dist/client.js.map +1 -0
  8. package/dist/core/account.d.ts +168 -0
  9. package/dist/core/account.d.ts.map +1 -0
  10. package/dist/core/account.js +245 -0
  11. package/dist/core/account.js.map +1 -0
  12. package/dist/core/amount.d.ts +63 -0
  13. package/dist/core/amount.d.ts.map +1 -0
  14. package/dist/core/amount.js +192 -0
  15. package/dist/core/amount.js.map +1 -0
  16. package/dist/core/balance.d.ts +55 -0
  17. package/dist/core/balance.d.ts.map +1 -0
  18. package/dist/core/balance.js +54 -0
  19. package/dist/core/balance.js.map +1 -0
  20. package/dist/core/bank-info.d.ts +49 -0
  21. package/dist/core/bank-info.d.ts.map +1 -0
  22. package/dist/core/bank-info.js +52 -0
  23. package/dist/core/bank-info.js.map +1 -0
  24. package/dist/core/client.d.ts +161 -0
  25. package/dist/core/client.d.ts.map +1 -0
  26. package/dist/core/client.js +2 -0
  27. package/dist/core/client.js.map +1 -0
  28. package/dist/core/config.d.ts +80 -0
  29. package/dist/core/config.d.ts.map +1 -0
  30. package/dist/core/config.js +153 -0
  31. package/dist/core/config.js.map +1 -0
  32. package/dist/core/errors.d.ts +153 -0
  33. package/dist/core/errors.d.ts.map +1 -0
  34. package/dist/core/errors.js +247 -0
  35. package/dist/core/errors.js.map +1 -0
  36. package/dist/core/feedback.d.ts +72 -0
  37. package/dist/core/feedback.d.ts.map +1 -0
  38. package/dist/core/feedback.js +127 -0
  39. package/dist/core/feedback.js.map +1 -0
  40. package/dist/core/transaction.d.ts +103 -0
  41. package/dist/core/transaction.d.ts.map +1 -0
  42. package/dist/core/transaction.js +96 -0
  43. package/dist/core/transaction.js.map +1 -0
  44. package/dist/core/transport.d.ts +64 -0
  45. package/dist/core/transport.d.ts.map +1 -0
  46. package/dist/core/transport.js +149 -0
  47. package/dist/core/transport.js.map +1 -0
  48. package/dist/formats/camt.d.ts +32 -0
  49. package/dist/formats/camt.d.ts.map +1 -0
  50. package/dist/formats/camt.js +242 -0
  51. package/dist/formats/camt.js.map +1 -0
  52. package/dist/formats/mt940.d.ts +54 -0
  53. package/dist/formats/mt940.d.ts.map +1 -0
  54. package/dist/formats/mt940.js +376 -0
  55. package/dist/formats/mt940.js.map +1 -0
  56. package/dist/formats/readers.d.ts +15 -0
  57. package/dist/formats/readers.d.ts.map +1 -0
  58. package/dist/formats/readers.js +42 -0
  59. package/dist/formats/readers.js.map +1 -0
  60. package/dist/formats/record-budget.d.ts +7 -0
  61. package/dist/formats/record-budget.d.ts.map +1 -0
  62. package/dist/formats/record-budget.js +17 -0
  63. package/dist/formats/record-budget.js.map +1 -0
  64. package/dist/formats/sepa-purpose.d.ts +28 -0
  65. package/dist/formats/sepa-purpose.d.ts.map +1 -0
  66. package/dist/formats/sepa-purpose.js +89 -0
  67. package/dist/formats/sepa-purpose.js.map +1 -0
  68. package/dist/index.d.ts +28 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js +27 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/session/app-approval.d.ts +66 -0
  73. package/dist/session/app-approval.d.ts.map +1 -0
  74. package/dist/session/app-approval.js +226 -0
  75. package/dist/session/app-approval.js.map +1 -0
  76. package/dist/session/dialog-runner.d.ts +31 -0
  77. package/dist/session/dialog-runner.d.ts.map +1 -0
  78. package/dist/session/dialog-runner.js +111 -0
  79. package/dist/session/dialog-runner.js.map +1 -0
  80. package/dist/session/login-guard.d.ts +78 -0
  81. package/dist/session/login-guard.d.ts.map +1 -0
  82. package/dist/session/login-guard.js +181 -0
  83. package/dist/session/login-guard.js.map +1 -0
  84. package/dist/session/sepa-accounts.d.ts +40 -0
  85. package/dist/session/sepa-accounts.d.ts.map +1 -0
  86. package/dist/session/sepa-accounts.js +112 -0
  87. package/dist/session/sepa-accounts.js.map +1 -0
  88. package/dist/session/session-setup.d.ts +80 -0
  89. package/dist/session/session-setup.d.ts.map +1 -0
  90. package/dist/session/session-setup.js +182 -0
  91. package/dist/session/session-setup.js.map +1 -0
  92. package/dist/session/session-state.d.ts +50 -0
  93. package/dist/session/session-state.d.ts.map +1 -0
  94. package/dist/session/session-state.js +182 -0
  95. package/dist/session/session-state.js.map +1 -0
  96. package/dist/session/signed-dialog.d.ts +77 -0
  97. package/dist/session/signed-dialog.d.ts.map +1 -0
  98. package/dist/session/signed-dialog.js +170 -0
  99. package/dist/session/signed-dialog.js.map +1 -0
  100. package/dist/session/tan-selection.d.ts +96 -0
  101. package/dist/session/tan-selection.d.ts.map +1 -0
  102. package/dist/session/tan-selection.js +189 -0
  103. package/dist/session/tan-selection.js.map +1 -0
  104. package/dist/session/user-prompts.d.ts +65 -0
  105. package/dist/session/user-prompts.d.ts.map +1 -0
  106. package/dist/session/user-prompts.js +184 -0
  107. package/dist/session/user-prompts.js.map +1 -0
  108. package/dist/tan/challenge.d.ts +135 -0
  109. package/dist/tan/challenge.d.ts.map +1 -0
  110. package/dist/tan/challenge.js +184 -0
  111. package/dist/tan/challenge.js.map +1 -0
  112. package/dist/tan/flicker.d.ts +42 -0
  113. package/dist/tan/flicker.d.ts.map +1 -0
  114. package/dist/tan/flicker.js +296 -0
  115. package/dist/tan/flicker.js.map +1 -0
  116. package/dist/tan/tan-image.d.ts +22 -0
  117. package/dist/tan/tan-image.d.ts.map +1 -0
  118. package/dist/tan/tan-image.js +43 -0
  119. package/dist/tan/tan-image.js.map +1 -0
  120. package/dist/tan/tan-models.d.ts +149 -0
  121. package/dist/tan/tan-models.d.ts.map +1 -0
  122. package/dist/tan/tan-models.js +153 -0
  123. package/dist/tan/tan-models.js.map +1 -0
  124. package/dist/util/async.d.ts +22 -0
  125. package/dist/util/async.d.ts.map +1 -0
  126. package/dist/util/async.js +45 -0
  127. package/dist/util/async.js.map +1 -0
  128. package/dist/util/bytes.d.ts +22 -0
  129. package/dist/util/bytes.d.ts.map +1 -0
  130. package/dist/util/bytes.js +128 -0
  131. package/dist/util/bytes.js.map +1 -0
  132. package/dist/util/call-context.d.ts +12 -0
  133. package/dist/util/call-context.d.ts.map +1 -0
  134. package/dist/util/call-context.js +30 -0
  135. package/dist/util/call-context.js.map +1 -0
  136. package/dist/util/dates.d.ts +55 -0
  137. package/dist/util/dates.d.ts.map +1 -0
  138. package/dist/util/dates.js +189 -0
  139. package/dist/util/dates.js.map +1 -0
  140. package/dist/util/errors.d.ts +17 -0
  141. package/dist/util/errors.d.ts.map +1 -0
  142. package/dist/util/errors.js +24 -0
  143. package/dist/util/errors.js.map +1 -0
  144. package/dist/util/immutable-map.d.ts +16 -0
  145. package/dist/util/immutable-map.d.ts.map +1 -0
  146. package/dist/util/immutable-map.js +38 -0
  147. package/dist/util/immutable-map.js.map +1 -0
  148. package/dist/util/json.d.ts +17 -0
  149. package/dist/util/json.d.ts.map +1 -0
  150. package/dist/util/json.js +62 -0
  151. package/dist/util/json.js.map +1 -0
  152. package/dist/util/text.d.ts +37 -0
  153. package/dist/util/text.d.ts.map +1 -0
  154. package/dist/util/text.js +107 -0
  155. package/dist/util/text.js.map +1 -0
  156. package/dist/util/xml.d.ts +36 -0
  157. package/dist/util/xml.d.ts.map +1 -0
  158. package/dist/util/xml.js +194 -0
  159. package/dist/util/xml.js.map +1 -0
  160. package/dist/v3/account-extension.d.ts +25 -0
  161. package/dist/v3/account-extension.d.ts.map +1 -0
  162. package/dist/v3/account-extension.js +173 -0
  163. package/dist/v3/account-extension.js.map +1 -0
  164. package/dist/v3/bank-connection.d.ts +34 -0
  165. package/dist/v3/bank-connection.d.ts.map +1 -0
  166. package/dist/v3/bank-connection.js +58 -0
  167. package/dist/v3/bank-connection.js.map +1 -0
  168. package/dist/v3/dialog.d.ts +112 -0
  169. package/dist/v3/dialog.d.ts.map +1 -0
  170. package/dist/v3/dialog.js +241 -0
  171. package/dist/v3/dialog.js.map +1 -0
  172. package/dist/v3/message.d.ts +85 -0
  173. package/dist/v3/message.d.ts.map +1 -0
  174. package/dist/v3/message.js +303 -0
  175. package/dist/v3/message.js.map +1 -0
  176. package/dist/v3/parameter-store.d.ts +75 -0
  177. package/dist/v3/parameter-store.d.ts.map +1 -0
  178. package/dist/v3/parameter-store.js +143 -0
  179. package/dist/v3/parameter-store.js.map +1 -0
  180. package/dist/v3/parameters.d.ts +105 -0
  181. package/dist/v3/parameters.d.ts.map +1 -0
  182. package/dist/v3/parameters.js +450 -0
  183. package/dist/v3/parameters.js.map +1 -0
  184. package/dist/v3/protocol.d.ts +61 -0
  185. package/dist/v3/protocol.d.ts.map +1 -0
  186. package/dist/v3/protocol.js +113 -0
  187. package/dist/v3/protocol.js.map +1 -0
  188. package/dist/v3/queries.d.ts +51 -0
  189. package/dist/v3/queries.d.ts.map +1 -0
  190. package/dist/v3/queries.js +120 -0
  191. package/dist/v3/queries.js.map +1 -0
  192. package/dist/v3/segments.d.ts +106 -0
  193. package/dist/v3/segments.d.ts.map +1 -0
  194. package/dist/v3/segments.js +325 -0
  195. package/dist/v3/segments.js.map +1 -0
  196. package/dist/v3/syntax.d.ts +127 -0
  197. package/dist/v3/syntax.d.ts.map +1 -0
  198. package/dist/v3/syntax.js +367 -0
  199. package/dist/v3/syntax.js.map +1 -0
  200. package/package.json +67 -4
  201. package/src/client.ts +252 -0
  202. package/src/core/account.ts +323 -0
  203. package/src/core/amount.ts +211 -0
  204. package/src/core/balance.ts +85 -0
  205. package/src/core/bank-info.ts +66 -0
  206. package/src/core/client.ts +186 -0
  207. package/src/core/config.ts +182 -0
  208. package/src/core/errors.ts +277 -0
  209. package/src/core/feedback.ts +140 -0
  210. package/src/core/transaction.ts +161 -0
  211. package/src/core/transport.ts +189 -0
  212. package/src/formats/camt.ts +266 -0
  213. package/src/formats/mt940.ts +419 -0
  214. package/src/formats/readers.ts +49 -0
  215. package/src/formats/record-budget.ts +18 -0
  216. package/src/formats/sepa-purpose.ts +94 -0
  217. package/src/index.ts +70 -0
  218. package/src/session/app-approval.ts +278 -0
  219. package/src/session/dialog-runner.ts +122 -0
  220. package/src/session/login-guard.ts +221 -0
  221. package/src/session/sepa-accounts.ts +115 -0
  222. package/src/session/session-setup.ts +184 -0
  223. package/src/session/session-state.ts +204 -0
  224. package/src/session/signed-dialog.ts +192 -0
  225. package/src/session/tan-selection.ts +203 -0
  226. package/src/session/user-prompts.ts +193 -0
  227. package/src/tan/challenge.ts +261 -0
  228. package/src/tan/flicker.ts +308 -0
  229. package/src/tan/tan-image.ts +38 -0
  230. package/src/tan/tan-models.ts +252 -0
  231. package/src/util/async.ts +48 -0
  232. package/src/util/bytes.ts +129 -0
  233. package/src/util/call-context.ts +41 -0
  234. package/src/util/dates.ts +210 -0
  235. package/src/util/errors.ts +27 -0
  236. package/src/util/immutable-map.ts +47 -0
  237. package/src/util/json.ts +67 -0
  238. package/src/util/text.ts +112 -0
  239. package/src/util/xml.ts +183 -0
  240. package/src/v3/account-extension.ts +185 -0
  241. package/src/v3/bank-connection.ts +67 -0
  242. package/src/v3/dialog.ts +283 -0
  243. package/src/v3/message.ts +373 -0
  244. package/src/v3/parameter-store.ts +160 -0
  245. package/src/v3/parameters.ts +524 -0
  246. package/src/v3/protocol.ts +148 -0
  247. package/src/v3/queries.ts +190 -0
  248. package/src/v3/segments.ts +374 -0
  249. package/src/v3/syntax.ts +369 -0
@@ -0,0 +1,450 @@
1
+ // Internal to the package, and named after the FinTS specification. Documentation is where the meaning is not evident.
2
+ import { Account } from '../core/account.js';
3
+ import { BankInfo } from '../core/bank-info.js';
4
+ import { FinTsProtocolError } from '../core/errors.js';
5
+ import { TanMethod, tanMediumRequirementOf } from '../tan/tan-models.js';
6
+ import { base64Decode, base64Encode, concatBytes } from '../util/bytes.js';
7
+ import { nonBlank, tryParseInt } from '../util/text.js';
8
+ import { AccountExtension } from './account-extension.js';
9
+ import { parseSegments } from './syntax.js';
10
+ /** Positions of the data elements in the header of the bank parameter data (HIBPA), after the segment header. */
11
+ const Hibpa = {
12
+ version: 1,
13
+ /** Country code, then bank code. */
14
+ bankId: 2,
15
+ bankName: 3,
16
+ languages: 5,
17
+ fintsVersions: 6,
18
+ maxMessageSize: 7,
19
+ minTimeout: 8,
20
+ maxTimeout: 9,
21
+ };
22
+ /**
23
+ * The data element of every parameter segment (`HI…S`) that holds its specific parameters, after the maximum number of
24
+ * orders, the minimum number of signatures and the security class.
25
+ */
26
+ const parameterGroup = 4;
27
+ /** The standard language in the communication access (HIKOM). */
28
+ const hikomStandardLanguage = 2;
29
+ function defined(values) {
30
+ return values.filter((v) => v !== undefined);
31
+ }
32
+ /** `bpd`, or `FinTsProtocolError` if the bank has not sent its parameter data yet. */
33
+ export function requireBankParameters(bpd) {
34
+ if (bpd === undefined)
35
+ throw new FinTsProtocolError('No bank parameter data available');
36
+ return bpd;
37
+ }
38
+ /** FinTS 3.0 bank parameter data (BPD): HIBPA and the parameter segments (`HI…S`), parsed once. */
39
+ export class Bpd3 {
40
+ segments;
41
+ bankInfo;
42
+ /** The two-step TAN methods of HITANS versions 6 and 7, by security function. */
43
+ offeredMethods;
44
+ /** Two-step TAN methods the bank offers and the client can run. */
45
+ tanMethods;
46
+ /** Security functions of the two-step methods the bank offers in a form the client cannot run. */
47
+ unsupportedTanMethods;
48
+ pinTan;
49
+ /** camt formats the bank offers for HKCAZ. */
50
+ camtFormats;
51
+ /** Versions of each parameter segment, by segment type. */
52
+ versions;
53
+ /**
54
+ * The dialog language HKVVB names: the bank's standard language (HIKOM), else the first it supports (HIBPA). Only
55
+ * these may be sent once the parameter data are known; `0`, the default, only before (Formals C.3.1.3).
56
+ */
57
+ dialogLanguage;
58
+ encodedValue;
59
+ constructor(segments, hibpa, fallbackBankCode) {
60
+ this.segments = segments;
61
+ this.bankInfo = new BankInfo({
62
+ bankCode: hibpa.text(Hibpa.bankId, 1) ?? fallbackBankCode,
63
+ name: hibpa.text(Hibpa.bankName),
64
+ bpdVersion: hibpa.integer(Hibpa.version) ?? 0,
65
+ languages: defined(hibpa.texts(Hibpa.languages)),
66
+ supportedVersions: defined(hibpa.texts(Hibpa.fintsVersions)),
67
+ maxMessageSize: hibpa.integer(Hibpa.maxMessageSize),
68
+ minTimeout: hibpa.integer(Hibpa.minTimeout),
69
+ maxTimeout: hibpa.integer(Hibpa.maxTimeout),
70
+ });
71
+ this.offeredMethods = parseTanMethods(segments);
72
+ const offered = [...this.offeredMethods.values()];
73
+ this.tanMethods = Object.freeze(offered.filter((o) => o.runnable).map((o) => o.method));
74
+ this.unsupportedTanMethods = Object.freeze(offered.filter((o) => !o.runnable).map((o) => o.method.securityFunction));
75
+ this.pinTan = PinTanParameters.parse(segments);
76
+ this.camtFormats = segments
77
+ .filter((s) => s.type === 'HICAZS')
78
+ .flatMap((s) => defined(s.texts(parameterGroup)))
79
+ .filter((format) => format.includes('camt'));
80
+ this.versions = versionsByType(segments);
81
+ this.dialogLanguage = dialogLanguageOf(segments, this.bankInfo);
82
+ }
83
+ /** The version of the parameter data, which the client reports back so that the bank sends newer ones only. */
84
+ get version() {
85
+ return this.bankInfo.bpdVersion;
86
+ }
87
+ /** The segments as the saved state keeps them, encoded once. */
88
+ get encoded() {
89
+ return (this.encodedValue ??= encodeSegments(this.segments));
90
+ }
91
+ /** The BPD in `all`, or `undefined` if they contain no HIBPA segment. */
92
+ static fromSegments(all, fallbackBankCode) {
93
+ const segments = all.filter(isParameterSegment);
94
+ const hibpa = segments.find((s) => s.type === 'HIBPA');
95
+ return hibpa === undefined ? undefined : new Bpd3(segments, hibpa, fallbackBankCode);
96
+ }
97
+ /** The parameter segment type of a business transaction: `HKSAL` → `HISALS`. */
98
+ static parameterName(transaction) {
99
+ return `HI${transaction.substring(2)}S`;
100
+ }
101
+ /** The highest version of `transaction` that the bank offers and the client `implemented`. */
102
+ bestVersion(transaction, implemented) {
103
+ let best;
104
+ for (const version of this.versions.get(Bpd3.parameterName(transaction)) ?? []) {
105
+ if (implemented.has(version) && (best === undefined || version > best))
106
+ best = version;
107
+ }
108
+ return best;
109
+ }
110
+ /** The version of the HKTAN segments that go with `method`; `undefined` for a method the bank does not offer. */
111
+ tanVersion(method) {
112
+ return this.offeredMethods.get(method.securityFunction)?.version;
113
+ }
114
+ }
115
+ function dialogLanguageOf(segments, bankInfo) {
116
+ const languages = new Set([1, 2, 3]);
117
+ const standard = segments.find((s) => s.type === 'HIKOM')?.integer(hikomStandardLanguage);
118
+ if (standard !== undefined && languages.has(standard))
119
+ return standard;
120
+ return bankInfo.languages.map((l) => tryParseInt(l)).find((l) => l !== undefined && languages.has(l)) ?? 0;
121
+ }
122
+ function isParameterSegment(s) {
123
+ const type = s.type;
124
+ if (['HIBPA', 'HIKOM', 'HISHV', 'HIKPV'].includes(type))
125
+ return true;
126
+ if (type === 'HIRMS' || type === 'HIRMG')
127
+ return false;
128
+ return type.length >= 5 && (type.startsWith('HI') || type.startsWith('DI')) && type.endsWith('S');
129
+ }
130
+ function versionsByType(segments) {
131
+ const versions = new Map();
132
+ for (const s of segments) {
133
+ let set = versions.get(s.type);
134
+ if (set === undefined)
135
+ versions.set(s.type, (set = new Set()));
136
+ set.add(s.version);
137
+ }
138
+ return versions;
139
+ }
140
+ /** Parses the two-step TAN methods from HITANS versions 6 and 7; for a method offered in several, the highest wins. */
141
+ function parseTanMethods(segments) {
142
+ const byCode = new Map();
143
+ for (const s of segments.filter((s) => s.type === 'HITANS')) {
144
+ for (const offered of parseHitans(s)) {
145
+ const existing = byCode.get(offered.method.securityFunction);
146
+ if (existing === undefined || offered.version > existing.version) {
147
+ byCode.set(offered.method.securityFunction, offered);
148
+ }
149
+ }
150
+ }
151
+ return byCode;
152
+ }
153
+ /** The fields describing one TAN method in HITANS, in order; version 6 ends with `activeMediaCount`. */
154
+ const HitansField = {
155
+ securityFunction: 0,
156
+ processVariant: 1,
157
+ technicalId: 2,
158
+ dkMethod: 3,
159
+ dkVersion: 4,
160
+ name: 5,
161
+ maxTanLength: 6,
162
+ tanFormat: 7,
163
+ returnValueText: 8,
164
+ /** "Maximale Länge des Rückgabewertes": the return value is the challenge. */
165
+ maxChallengeLength: 9,
166
+ multipleTans: 10,
167
+ tanTimeAndDialogRelation: 11,
168
+ orderCancellation: 12,
169
+ smsChargeAccountRequired: 13,
170
+ orderingAccountRequired: 14,
171
+ challengeClassRequired: 15,
172
+ structuredChallenge: 16,
173
+ initializationMode: 17,
174
+ mediumNameRequired: 18,
175
+ hhdUcRequired: 19,
176
+ activeMediaCount: 20,
177
+ maxStatusPolls: 21,
178
+ firstPollDelay: 22,
179
+ pollInterval: 23,
180
+ manualConfirmation: 24,
181
+ automaticPolling: 25,
182
+ };
183
+ function parseHitans(s) {
184
+ const version = s.version;
185
+ if (version !== 6 && version !== 7)
186
+ return [];
187
+ // Version 7 adds the fields for decoupled approval.
188
+ const fieldsPerMethod = version === 6 ? HitansField.activeMediaCount + 1 : HitansField.automaticPolling + 1;
189
+ const all = s.texts(parameterGroup);
190
+ const methods = [];
191
+ // The group starts with three general fields, then lists the methods.
192
+ for (let start = 3; start < all.length; start += fieldsPerMethod) {
193
+ const fields = all.slice(start, start + fieldsPerMethod);
194
+ const field = (f) => fields[f];
195
+ const number = (f) => tryParseInt(field(f));
196
+ const code = field(HitansField.securityFunction);
197
+ if (code === undefined)
198
+ continue;
199
+ // Process variant 1 needs the order hash and another message flow; the client runs variant 2, the one of PSD2
200
+ // strong customer authentication. An SMS charge account or an HHD_UC answer, where required, it cannot send.
201
+ const runnable = number(HitansField.processVariant) !== 1 &&
202
+ field(HitansField.smsChargeAccountRequired) !== '2' &&
203
+ field(HitansField.hhdUcRequired) !== 'J';
204
+ const dkMethod = field(HitansField.dkMethod);
205
+ const decoupledFields = version === 7;
206
+ const method = new TanMethod({
207
+ securityFunction: code,
208
+ technicalId: field(HitansField.technicalId),
209
+ dkMethod,
210
+ dkVersion: field(HitansField.dkVersion),
211
+ name: field(HitansField.name) ?? code,
212
+ maxTanLength: number(HitansField.maxTanLength),
213
+ numericTan: field(HitansField.tanFormat) !== '2',
214
+ returnValueText: field(HitansField.returnValueText),
215
+ maxChallengeLength: number(HitansField.maxChallengeLength),
216
+ structuredChallenge: field(HitansField.structuredChallenge) === 'J',
217
+ mediumRequirement: tanMediumRequirementOf(field(HitansField.mediumNameRequired)),
218
+ activeMediaCount: number(HitansField.activeMediaCount),
219
+ decoupled: decoupledFields && dkMethod !== undefined && dkMethod.toLowerCase().startsWith('decoupled'),
220
+ decoupledMaxPolls: decoupledFields ? number(HitansField.maxStatusPolls) : undefined,
221
+ decoupledFirstPollDelaySeconds: decoupledFields ? number(HitansField.firstPollDelay) : undefined,
222
+ decoupledPollIntervalSeconds: decoupledFields ? number(HitansField.pollInterval) : undefined,
223
+ decoupledManualConfirmation: !decoupledFields || field(HitansField.manualConfirmation) !== 'N',
224
+ decoupledAutomaticPolling: !decoupledFields || field(HitansField.automaticPolling) !== 'N',
225
+ });
226
+ methods.push({ method, runnable, version });
227
+ }
228
+ return methods;
229
+ }
230
+ /**
231
+ * PIN/TAN parameters (HIPINS): the PIN length, which business transactions PIN/TAN allows, and which of them need a
232
+ * TAN.
233
+ */
234
+ export class PinTanParameters {
235
+ tanRequired;
236
+ pinLength;
237
+ constructor(tanRequired,
238
+ /** The shortest and longest PIN the bank takes. */
239
+ pinLength) {
240
+ this.tanRequired = tanRequired;
241
+ this.pinLength = pinLength;
242
+ }
243
+ /** Reads the HIPINS segment of the highest version. */
244
+ static parse(segments) {
245
+ let hipins;
246
+ for (const s of segments.filter((s) => s.type === 'HIPINS')) {
247
+ if (hipins === undefined || s.version > hipins.version)
248
+ hipins = s;
249
+ }
250
+ if (hipins === undefined)
251
+ return new PinTanParameters(new Map(), { min: undefined, max: undefined });
252
+ const fields = hipins.texts(parameterGroup);
253
+ const tanRequired = new Map();
254
+ // Five general fields, the PIN lengths first; then pairs of segment type and TAN flag.
255
+ for (let i = 5; i + 1 < fields.length; i += 2) {
256
+ const type = fields[i];
257
+ if (type !== undefined)
258
+ tanRequired.set(type, fields[i + 1] === 'J');
259
+ }
260
+ return new PinTanParameters(tanRequired, { min: tryParseInt(fields[0]), max: tryParseInt(fields[1]) });
261
+ }
262
+ /** Whether the bank wants a TAN for the business transaction of `segmentType`, such as `HKKAZ`. */
263
+ requiresTan(segmentType) {
264
+ return this.tanRequired.get(segmentType) ?? false;
265
+ }
266
+ /** Whether PIN/TAN allows `segmentType` at all: HIPINS lists it, or lists no business transactions (PIN/TAN B.8.1). */
267
+ allowsWithPinTan(segmentType) {
268
+ return this.tanRequired.size === 0 || this.tanRequired.has(segmentType);
269
+ }
270
+ }
271
+ /** The user ID (Benutzerkennung), the version and the usage ("UPD-Verwendung") of the user parameter data in HIUPA. */
272
+ const hiupaUserId = 1;
273
+ const hiupaVersion = 2;
274
+ const hiupaUsage = 3;
275
+ /** Business transaction codes such as `HKSAL` or `DKPAE`. */
276
+ const transactionCode = /^[A-Z]{4,6}$/;
277
+ /** FinTS 3.0 user parameter data (UPD): HIUPA and the accounts (HIUPD), parsed once. */
278
+ export class Upd3 {
279
+ segments;
280
+ /** The user the bank sent them for; `undefined` where it names none. */
281
+ userId;
282
+ /** The version of the parameter data, which the client reports back so that the bank sends newer ones only. */
283
+ version;
284
+ /**
285
+ * Whether the lists of permitted transactions are complete: the bank permits nothing they leave out ("UPD-Verwendung"
286
+ * 0).
287
+ */
288
+ listsAllTransactions;
289
+ /** The transactions any entry lists as permitted, with or without an account. */
290
+ listedTransactions;
291
+ /** The accounts with the extension each carries, where it does. */
292
+ entries;
293
+ /** The accounts the user may access. */
294
+ accounts;
295
+ encodedValue;
296
+ /** `listsAll` tells whether HIUPA declares the lists of permitted transactions complete ("UPD-Verwendung" 0). */
297
+ constructor(segments, hiupa, listsAll, defaultBankCode, defaultCountry) {
298
+ this.segments = segments;
299
+ const hiupds = segments.filter((s) => s.type === 'HIUPD');
300
+ this.userId = hiupa.text(hiupaUserId)?.trim();
301
+ this.version = hiupa.integer(hiupaVersion) ?? 0;
302
+ this.listsAllTransactions = listsAll;
303
+ this.listedTransactions = new Set(hiupds.flatMap(transactionsOf));
304
+ this.entries = Object.freeze(hiupds.map((s) => entryOf(s, defaultBankCode, defaultCountry, listsAll)).filter((e) => e !== undefined));
305
+ this.accounts = Object.freeze(this.entries.map((e) => e.account));
306
+ }
307
+ /** The segments as the saved state keeps them, encoded once. */
308
+ get encoded() {
309
+ return (this.encodedValue ??= encodeSegments(this.segments));
310
+ }
311
+ /**
312
+ * The balance of `account` the user parameter data carry, where it holds all a balance query would deliver, so that
313
+ * the client asks for none (Formals E.3.1, F.3.2); `undefined` otherwise.
314
+ */
315
+ completeBalance(account) {
316
+ return this.entries.find((e) => e.account.matches(account))?.extension?.completeBalance(account);
317
+ }
318
+ /** The UPD in `all`, or `undefined` if they contain no HIUPA segment. */
319
+ static fromSegments(all, defaultBankCode, defaultCountry) {
320
+ const segments = all.filter((s) => s.type === 'HIUPA' || s.type === 'HIUPD');
321
+ const hiupa = segments.find((s) => s.type === 'HIUPA');
322
+ if (hiupa === undefined)
323
+ return undefined;
324
+ return new Upd3(segments, hiupa, hiupa.text(hiupaUsage) === '0', defaultBankCode, defaultCountry);
325
+ }
326
+ }
327
+ /**
328
+ * The data element where the permitted transactions start, by HIUPD version: version 6 inserts the IBAN, version 5 the
329
+ * account type.
330
+ */
331
+ function allowedFrom(version) {
332
+ return version >= 6 ? 10 : version === 5 ? 9 : 8;
333
+ }
334
+ /** The permitted transactions of the HIUPD `s`. */
335
+ function transactionsOf(s) {
336
+ const codes = [];
337
+ for (let i = allowedFrom(s.version); i < s.length; i++) {
338
+ const code = s.text(i, 0);
339
+ if (code !== undefined && transactionCode.test(code))
340
+ codes.push(code);
341
+ }
342
+ return codes;
343
+ }
344
+ /**
345
+ * The account extension of `s` (version 6, "Erweiterung, kontobezogen"): the JSON object behind the permitted
346
+ * transactions, whose count varies. A bank that leaves its colons unescaped splits it into group elements, which are
347
+ * joined again.
348
+ */
349
+ function extensionOf(s) {
350
+ if (s.version < 6)
351
+ return undefined;
352
+ for (let i = allowedFrom(s.version); i < s.length; i++) {
353
+ const text = s
354
+ .group(i)
355
+ .map((e) => e.text)
356
+ .join(':');
357
+ if (text.trimStart().startsWith('{'))
358
+ return AccountExtension.tryParse(text);
359
+ }
360
+ return undefined;
361
+ }
362
+ function entryOf(s, defaultBankCode, defaultCountry, listsAll) {
363
+ const account = accountOf(s, defaultBankCode, defaultCountry, listsAll);
364
+ if (account === undefined)
365
+ return undefined;
366
+ const extension = extensionOf(s);
367
+ return {
368
+ account: extension === undefined ? account : account.copyWith({ bic: extension.bic, dataStatus: extension.status }),
369
+ extension,
370
+ };
371
+ }
372
+ function accountOf(s, defaultBankCode, defaultCountry, listsAll) {
373
+ const version = s.version;
374
+ // Every version names the account as KTV2, by position: a sub-account or bank code the bank leaves out is empty.
375
+ const [number, subAccount, country, bank] = s.texts(1);
376
+ const iban = version >= 6 ? s.text(2) : undefined;
377
+ if (number === undefined && iban === undefined)
378
+ return undefined;
379
+ // Field positions by HIUPD version: version 6 inserts the IBAN, version 5 the account type.
380
+ const fields = version >= 6
381
+ ? { customer: 3, type: 4, currency: 5, name1: 6, name2: 7, product: 8 }
382
+ : version === 5
383
+ ? { customer: 2, type: 3, currency: 4, name1: 5, name2: 6, product: 7 }
384
+ : { customer: 2, type: undefined, currency: 3, name1: 4, name2: 5, product: 6 };
385
+ return new Account({
386
+ accountNumber: number,
387
+ subAccount,
388
+ countryCode: country ?? defaultCountry,
389
+ bankCode: bank ?? defaultBankCode,
390
+ iban,
391
+ customerId: s.text(fields.customer),
392
+ typeCode: fields.type === undefined ? undefined : s.integer(fields.type),
393
+ currency: s.text(fields.currency),
394
+ ownerName: nonBlank(defined([s.text(fields.name1), s.text(fields.name2)]).join(' ')),
395
+ productName: s.text(fields.product),
396
+ allowedTransactions: transactionsOf(s),
397
+ allowedTransactionsComplete: listsAll,
398
+ });
399
+ }
400
+ /**
401
+ * The version of `transaction` to send, for `account` where it concerns one: the highest the bank offers and the client
402
+ * `implemented`. `undefined` where there is none, or the parameter data do not permit the transaction
403
+ * (`permitsTransaction`).
404
+ */
405
+ export function offeredVersion(bpd, upd, transaction, implemented, options) {
406
+ return permitsTransaction(bpd, upd, transaction, options) ? bpd?.bestVersion(transaction, implemented) : undefined;
407
+ }
408
+ /**
409
+ * Whether the parameter data let the user send `transaction`, for `account` where it concerns one: the bank allows it
410
+ * with PIN/TAN, and the user parameter data permit it (Formals E.1, F.3.4; PIN/TAN B.1, B.8.1).
411
+ *
412
+ * - `account`, which the session has taken as the bank knows it (`SepaAccounts.complete`), permits what it lists, and
413
+ * anything else only where its list is incomplete ("UPD-Verwendung" 1). One only the SEPA account list names lists
414
+ * nothing, and so permits anything; where the lists are complete, the session refuses one the bank names nowhere.
415
+ * - A transaction without account, such as the TAN media list, is permitted where some entry lists it or the lists are
416
+ * incomplete.
417
+ * - One that `requiresEntry`, the SEPA account list, must be listed even where the lists are incomplete (Formals F.3.4),
418
+ * unless they list nothing at all, which tells nothing.
419
+ */
420
+ function permitsTransaction(bpd, upd, transaction, options) {
421
+ if (bpd !== undefined && !bpd.pinTan.allowsWithPinTan(transaction))
422
+ return false;
423
+ if (upd === undefined)
424
+ return true;
425
+ if (options.account !== undefined)
426
+ return allows(options.account, transaction);
427
+ const listed = upd.listedTransactions;
428
+ if (listed.has(transaction))
429
+ return true;
430
+ return !upd.listsAllTransactions && (!(options.requiresEntry ?? false) || listed.size === 0);
431
+ }
432
+ /** Whether the bank lists `transaction`, such as `HKCAZ`, as permitted for `account`. */
433
+ export function lists(account, transaction) {
434
+ return account.allowedTransactions.includes(transaction);
435
+ }
436
+ /**
437
+ * Whether the bank may permit `transaction` on `account`: it lists it, or its list is not complete
438
+ * (`Account.allowedTransactionsComplete`), so that only the bank can tell.
439
+ */
440
+ function allows(account, transaction) {
441
+ return lists(account, transaction) || !account.allowedTransactionsComplete;
442
+ }
443
+ /** Serializes parameter segments for the saved state. */
444
+ function encodeSegments(segments) {
445
+ return base64Encode(concatBytes(segments.map((s) => s.encode())));
446
+ }
447
+ export function decodeSegments(data) {
448
+ return parseSegments(base64Decode(data));
449
+ }
450
+ //# sourceMappingURL=parameters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parameters.js","sourceRoot":"","sources":["../../src/v3/parameters.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import type { MessageLogger } from '../core/client.js';
2
+ import type { FinTsTransport } from '../core/transport.js';
3
+ import type { ParameterStore } from './parameter-store.js';
4
+ import type { SegmentSpec } from './syntax.js';
5
+ /** How a message is signed: the security function of the TAN method and the customer system ID. */
6
+ export interface Signing3 {
7
+ readonly securityFunction: string;
8
+ readonly systemId: string;
9
+ }
10
+ /** Hands out the PIN for each message the protocol signs, and so decides whether one may go out. */
11
+ export interface PinGuard {
12
+ /** The PIN to sign a message with; throws instead where none may go out. */
13
+ readonly pin: string;
14
+ /** Counts a login signed with the PIN, the first message of a dialog, before it goes out. */
15
+ loginSent(): void;
16
+ }
17
+ /**
18
+ * Builds, signs and posts FinTS 3.0 messages (HBCI segment syntax, PIN/TAN security) for the user `parameters.config`
19
+ * names, with the parameter data and IDs `parameters` keeps. Every message signed with the PIN takes it from the
20
+ * `PinGuard` (`post`), which keeps it from going out after a refused login.
21
+ */
22
+ export declare class FinTs3Protocol {
23
+ readonly parameters: ParameterStore;
24
+ private readonly guard;
25
+ private readonly config;
26
+ private readonly connection;
27
+ /** Whether the client is closing, so that only dialog ends go out (`beginClose`). */
28
+ private closing;
29
+ constructor(parameters: ParameterStore, guard: PinGuard, transport?: FinTsTransport, logger?: MessageLogger);
30
+ /** Identification (HKIDN) and processing preparation (HKVVB), which open every dialog. */
31
+ initSegments(systemId: string, anonymous?: boolean): SegmentSpec[];
32
+ /**
33
+ * Sends `segments` as message `number` of the dialog `dialogId` and returns the bank's answer, not yet parsed.
34
+ *
35
+ * With `signing` the message is signed with the PIN, which `PinGuard.pin` hands out, and the `tan`; without, it
36
+ * goes out unsigned, as in an anonymous dialog.
37
+ */
38
+ post(message: {
39
+ dialogId: string;
40
+ number: number;
41
+ segments: readonly SegmentSpec[];
42
+ signing: Signing3 | undefined;
43
+ tan: string | undefined;
44
+ }): Promise<Uint8Array>;
45
+ /**
46
+ * The PIN to sign a login with, the first message of a dialog.
47
+ *
48
+ * Throws instead where the guard holds the PIN back (`PinGuard.pin`), or if the bank parameters rule out the PIN's
49
+ * length: the bank would count such a PIN as a failed attempt. The later messages of a dialog, its end included, take
50
+ * the PIN the bank has accepted, whatever the parameter data it delivered since say.
51
+ */
52
+ private pinForLogin;
53
+ /**
54
+ * Aborts the request on its way, and sends nothing but dialog ends from now on: any other message fails with
55
+ * `FinTsStateError` before it goes out, so that a call under way stops at its next one. The client calls it as soon as
56
+ * it is closed, and `close` once it has ended its dialog.
57
+ */
58
+ beginClose(): void;
59
+ close(): void;
60
+ }
61
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/v3/protocol.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAI3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK/C,mGAAmG;AACnG,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,oGAAoG;AACpG,MAAM,WAAW,QAAQ;IACvB,4EAA4E;IAC5E,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB,6FAA6F;IAC7F,SAAS,IAAI,IAAI,CAAC;CACnB;AAOD;;;;GAIG;AACH,qBAAa,cAAc;IAQvB,QAAQ,CAAC,UAAU,EAAE,cAAc;IACnC,OAAO,CAAC,QAAQ,CAAC,KAAK;IARxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAiB;IAE5C,qFAAqF;IACrF,OAAO,CAAC,OAAO,CAAS;gBAGb,UAAU,EAAE,cAAc,EAClB,KAAK,EAAE,QAAQ,EAChC,SAAS,CAAC,EAAE,cAAc,EAC1B,MAAM,CAAC,EAAE,aAAa;IAMxB,0FAA0F;IAC1F,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,UAAQ,GAAG,WAAW,EAAE;IAmBhE;;;;;OAKG;IACG,IAAI,CAAC,OAAO,EAAE;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;QACjC,OAAO,EAAE,QAAQ,GAAG,SAAS,CAAC;QAC9B,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;KACzB,GAAG,OAAO,CAAC,UAAU,CAAC;IA8BvB;;;;;;OAMG;IACH,OAAO,CAAC,WAAW;IAOnB;;;;OAIG;IACH,UAAU,IAAI,IAAI;IAKlB,KAAK,IAAI,IAAI;CAGd"}
@@ -0,0 +1,113 @@
1
+ // Internal to the package, and named after the FinTS specification. Documentation is where the meaning is not evident.
2
+ import { requirePinLength } from '../core/config.js';
3
+ import { clientClosedError } from '../core/errors.js';
4
+ import { decodeBankText } from '../util/text.js';
5
+ import { BankConnection, checkMessageSize } from './bank-connection.js';
6
+ import { buildMessage, decodeTransport, encodeTransport } from './message.js';
7
+ import { Segments } from './segments.js';
8
+ /** Customer ID the specification reserves for anonymous dialogs. */
9
+ const anonymousCustomerId = '9999999999';
10
+ /** Whether `segments` are those of a dialog end, the one message a closing client still sends. */
11
+ function isDialogEnd(segments) {
12
+ return segments.length === 1 && segments[0].type === 'HKEND';
13
+ }
14
+ /**
15
+ * Builds, signs and posts FinTS 3.0 messages (HBCI segment syntax, PIN/TAN security) for the user `parameters.config`
16
+ * names, with the parameter data and IDs `parameters` keeps. Every message signed with the PIN takes it from the
17
+ * `PinGuard` (`post`), which keeps it from going out after a refused login.
18
+ */
19
+ export class FinTs3Protocol {
20
+ parameters;
21
+ guard;
22
+ config;
23
+ connection;
24
+ /** Whether the client is closing, so that only dialog ends go out (`beginClose`). */
25
+ closing = false;
26
+ constructor(parameters, guard, transport, logger) {
27
+ this.parameters = parameters;
28
+ this.guard = guard;
29
+ this.config = parameters.config;
30
+ this.connection = new BankConnection(this.config.url, transport, logger);
31
+ }
32
+ /** Identification (HKIDN) and processing preparation (HKVVB), which open every dialog. */
33
+ initSegments(systemId, anonymous = false) {
34
+ return [
35
+ Segments.identification({
36
+ countryCode: this.config.countryCode,
37
+ bankCode: this.config.bankCode,
38
+ customerId: anonymous ? anonymousCustomerId : this.config.customerId,
39
+ systemId,
40
+ systemIdRequired: !anonymous,
41
+ }),
42
+ Segments.processingPreparation({
43
+ bpdVersion: this.parameters.reportedBpdVersion,
44
+ updVersion: anonymous ? 0 : this.parameters.reportedUpdVersion,
45
+ language: this.parameters.bankParameters?.dialogLanguage ?? 0,
46
+ productId: this.config.productId,
47
+ productVersion: this.config.productVersion,
48
+ }),
49
+ ];
50
+ }
51
+ /**
52
+ * Sends `segments` as message `number` of the dialog `dialogId` and returns the bank's answer, not yet parsed.
53
+ *
54
+ * With `signing` the message is signed with the PIN, which `PinGuard.pin` hands out, and the `tan`; without, it
55
+ * goes out unsigned, as in an anonymous dialog.
56
+ */
57
+ async post(message) {
58
+ if (this.closing && !isDialogEnd(message.segments))
59
+ throw clientClosedError();
60
+ const signing = message.signing;
61
+ // The first message of a signed dialog logs in: from here on the bank may count the PIN.
62
+ const login = signing !== undefined && message.number === 1;
63
+ const outgoing = buildMessage({
64
+ dialogId: message.dialogId,
65
+ messageNumber: message.number,
66
+ segments: message.segments,
67
+ security: signing === undefined
68
+ ? undefined
69
+ : {
70
+ countryCode: this.config.countryCode,
71
+ bankCode: this.config.bankCode,
72
+ userId: this.config.userId,
73
+ systemId: signing.systemId,
74
+ pin: login ? this.pinForLogin() : this.guard.pin,
75
+ securityFunction: signing.securityFunction,
76
+ },
77
+ tan: message.tan,
78
+ });
79
+ checkMessageSize(outgoing.bytes.length, this.parameters.bankParameters?.bankInfo.maxMessageSize);
80
+ this.connection.log('outgoing', () => outgoing.masked);
81
+ if (login)
82
+ this.guard.loginSent();
83
+ const bytes = decodeTransport(await this.connection.post(encodeTransport(outgoing.bytes), 'text/plain'));
84
+ this.connection.log('incoming', () => decodeBankText(bytes));
85
+ return bytes;
86
+ }
87
+ /**
88
+ * The PIN to sign a login with, the first message of a dialog.
89
+ *
90
+ * Throws instead where the guard holds the PIN back (`PinGuard.pin`), or if the bank parameters rule out the PIN's
91
+ * length: the bank would count such a PIN as a failed attempt. The later messages of a dialog, its end included, take
92
+ * the PIN the bank has accepted, whatever the parameter data it delivered since say.
93
+ */
94
+ pinForLogin() {
95
+ const pin = this.guard.pin;
96
+ const length = this.parameters.bankParameters?.pinTan.pinLength;
97
+ requirePinLength(pin, length?.min, length?.max);
98
+ return pin;
99
+ }
100
+ /**
101
+ * Aborts the request on its way, and sends nothing but dialog ends from now on: any other message fails with
102
+ * `FinTsStateError` before it goes out, so that a call under way stops at its next one. The client calls it as soon as
103
+ * it is closed, and `close` once it has ended its dialog.
104
+ */
105
+ beginClose() {
106
+ this.closing = true;
107
+ this.connection.abortRequests();
108
+ }
109
+ close() {
110
+ this.connection.close();
111
+ }
112
+ }
113
+ //# sourceMappingURL=protocol.js.map