@coderoftime/fints 0.1.0 → 0.3.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.
- package/CHANGELOG.md +519 -1
- package/README.md +138 -40
- package/dist/client.d.ts +49 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +242 -0
- package/dist/client.js.map +1 -0
- package/dist/core/account.d.ts +46 -7
- package/dist/core/account.d.ts.map +1 -1
- package/dist/core/account.js +143 -24
- package/dist/core/account.js.map +1 -1
- package/dist/core/amount.d.ts +15 -4
- package/dist/core/amount.d.ts.map +1 -1
- package/dist/core/amount.js +46 -9
- package/dist/core/amount.js.map +1 -1
- package/dist/core/balance.d.ts +4 -0
- package/dist/core/balance.d.ts.map +1 -1
- package/dist/core/balance.js +11 -5
- package/dist/core/balance.js.map +1 -1
- package/dist/core/bank-info.d.ts +21 -4
- package/dist/core/bank-info.d.ts.map +1 -1
- package/dist/core/bank-info.js +26 -5
- package/dist/core/bank-info.js.map +1 -1
- package/dist/core/client.d.ts +81 -19
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/config.d.ts +40 -20
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +85 -30
- package/dist/core/config.js.map +1 -1
- package/dist/core/errors.d.ts +100 -26
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +136 -53
- package/dist/core/errors.js.map +1 -1
- package/dist/core/feedback.d.ts +11 -1
- package/dist/core/feedback.d.ts.map +1 -1
- package/dist/core/feedback.js +14 -2
- package/dist/core/feedback.js.map +1 -1
- package/dist/core/transaction.d.ts +11 -1
- package/dist/core/transaction.d.ts.map +1 -1
- package/dist/core/transaction.js +21 -4
- package/dist/core/transaction.js.map +1 -1
- package/dist/core/transport.d.ts +48 -6
- package/dist/core/transport.d.ts.map +1 -1
- package/dist/core/transport.js +126 -29
- package/dist/core/transport.js.map +1 -1
- package/dist/formats/camt.d.ts +28 -5
- package/dist/formats/camt.d.ts.map +1 -1
- package/dist/formats/camt.js +132 -50
- package/dist/formats/camt.js.map +1 -1
- package/dist/formats/mt940.d.ts +29 -5
- package/dist/formats/mt940.d.ts.map +1 -1
- package/dist/formats/mt940.js +209 -113
- package/dist/formats/mt940.js.map +1 -1
- package/dist/formats/readers.d.ts +6 -2
- package/dist/formats/readers.d.ts.map +1 -1
- package/dist/formats/readers.js +28 -29
- package/dist/formats/readers.js.map +1 -1
- package/dist/formats/record-budget.d.ts +7 -0
- package/dist/formats/record-budget.d.ts.map +1 -0
- package/dist/formats/record-budget.js +17 -0
- package/dist/formats/record-budget.js.map +1 -0
- package/dist/formats/sepa-purpose.d.ts +9 -0
- package/dist/formats/sepa-purpose.d.ts.map +1 -1
- package/dist/formats/sepa-purpose.js +32 -2
- package/dist/formats/sepa-purpose.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/session/app-approval.d.ts +11 -5
- package/dist/session/app-approval.d.ts.map +1 -1
- package/dist/session/app-approval.js +23 -12
- package/dist/session/app-approval.js.map +1 -1
- package/dist/session/dialog-runner.d.ts +11 -11
- package/dist/session/dialog-runner.d.ts.map +1 -1
- package/dist/session/dialog-runner.js +34 -19
- package/dist/session/dialog-runner.js.map +1 -1
- package/dist/session/login-guard.d.ts +54 -49
- package/dist/session/login-guard.d.ts.map +1 -1
- package/dist/session/login-guard.js +170 -83
- package/dist/session/login-guard.js.map +1 -1
- package/dist/session/sepa-accounts.d.ts +20 -14
- package/dist/session/sepa-accounts.d.ts.map +1 -1
- package/dist/session/sepa-accounts.js +62 -46
- package/dist/session/sepa-accounts.js.map +1 -1
- package/dist/session/session-setup.d.ts +41 -24
- package/dist/session/session-setup.d.ts.map +1 -1
- package/dist/session/session-setup.js +106 -63
- package/dist/session/session-setup.js.map +1 -1
- package/dist/session/session-state.d.ts +10 -6
- package/dist/session/session-state.d.ts.map +1 -1
- package/dist/session/session-state.js +72 -18
- package/dist/session/session-state.js.map +1 -1
- package/dist/session/signed-dialog.d.ts +83 -0
- package/dist/session/signed-dialog.d.ts.map +1 -0
- package/dist/session/signed-dialog.js +185 -0
- package/dist/session/signed-dialog.js.map +1 -0
- package/dist/session/tan-selection.d.ts +26 -18
- package/dist/session/tan-selection.d.ts.map +1 -1
- package/dist/session/tan-selection.js +44 -33
- package/dist/session/tan-selection.js.map +1 -1
- package/dist/session/user-prompts.d.ts +14 -5
- package/dist/session/user-prompts.d.ts.map +1 -1
- package/dist/session/user-prompts.js +53 -18
- package/dist/session/user-prompts.js.map +1 -1
- package/dist/tan/challenge.d.ts +47 -24
- package/dist/tan/challenge.d.ts.map +1 -1
- package/dist/tan/challenge.js +56 -51
- package/dist/tan/challenge.js.map +1 -1
- package/dist/tan/flicker.d.ts +11 -1
- package/dist/tan/flicker.d.ts.map +1 -1
- package/dist/tan/flicker.js +70 -24
- package/dist/tan/flicker.js.map +1 -1
- package/dist/tan/tan-image.d.ts +6 -2
- package/dist/tan/tan-image.d.ts.map +1 -1
- package/dist/tan/tan-image.js +14 -6
- package/dist/tan/tan-image.js.map +1 -1
- package/dist/tan/tan-models.d.ts +14 -2
- package/dist/tan/tan-models.d.ts.map +1 -1
- package/dist/tan/tan-models.js +24 -7
- package/dist/tan/tan-models.js.map +1 -1
- package/dist/util/arguments.d.ts +13 -0
- package/dist/util/arguments.d.ts.map +1 -0
- package/dist/util/arguments.js +40 -0
- package/dist/util/arguments.js.map +1 -0
- package/dist/util/async.d.ts +4 -3
- package/dist/util/async.d.ts.map +1 -1
- package/dist/util/async.js +6 -7
- package/dist/util/async.js.map +1 -1
- package/dist/util/bytes.d.ts +3 -4
- package/dist/util/bytes.d.ts.map +1 -1
- package/dist/util/bytes.js +13 -21
- package/dist/util/bytes.js.map +1 -1
- package/dist/util/call-context.d.ts.map +1 -1
- package/dist/util/call-context.js +3 -2
- package/dist/util/call-context.js.map +1 -1
- package/dist/util/dates.d.ts +6 -20
- package/dist/util/dates.d.ts.map +1 -1
- package/dist/util/dates.js +58 -28
- package/dist/util/dates.js.map +1 -1
- package/dist/util/errors.d.ts +13 -3
- package/dist/util/errors.d.ts.map +1 -1
- package/dist/util/errors.js +19 -6
- package/dist/util/errors.js.map +1 -1
- package/dist/util/immutable-map.d.ts +5 -2
- package/dist/util/immutable-map.d.ts.map +1 -1
- package/dist/util/immutable-map.js +15 -12
- package/dist/util/immutable-map.js.map +1 -1
- package/dist/util/inspect.d.ts +11 -0
- package/dist/util/inspect.d.ts.map +1 -0
- package/dist/util/inspect.js +14 -0
- package/dist/util/inspect.js.map +1 -0
- package/dist/util/json.d.ts +4 -0
- package/dist/util/json.d.ts.map +1 -1
- package/dist/util/json.js +18 -0
- package/dist/util/json.js.map +1 -1
- package/dist/util/text.d.ts +38 -5
- package/dist/util/text.d.ts.map +1 -1
- package/dist/util/text.js +90 -16
- package/dist/util/text.js.map +1 -1
- package/dist/util/xml.d.ts +9 -6
- package/dist/util/xml.d.ts.map +1 -1
- package/dist/util/xml.js +129 -56
- package/dist/util/xml.js.map +1 -1
- package/dist/v3/account-extension.d.ts.map +1 -1
- package/dist/v3/account-extension.js +7 -10
- package/dist/v3/account-extension.js.map +1 -1
- package/dist/v3/bank-connection.d.ts +54 -0
- package/dist/v3/bank-connection.d.ts.map +1 -0
- package/dist/v3/bank-connection.js +118 -0
- package/dist/v3/bank-connection.js.map +1 -0
- package/dist/v3/dialog.d.ts +84 -46
- package/dist/v3/dialog.d.ts.map +1 -1
- package/dist/v3/dialog.js +174 -60
- package/dist/v3/dialog.js.map +1 -1
- package/dist/v3/message.d.ts +32 -11
- package/dist/v3/message.d.ts.map +1 -1
- package/dist/v3/message.js +144 -83
- package/dist/v3/message.js.map +1 -1
- package/dist/v3/parameter-store.d.ts +111 -0
- package/dist/v3/parameter-store.d.ts.map +1 -0
- package/dist/v3/parameter-store.js +197 -0
- package/dist/v3/parameter-store.js.map +1 -0
- package/dist/v3/parameters.d.ts +44 -17
- package/dist/v3/parameters.d.ts.map +1 -1
- package/dist/v3/parameters.js +136 -60
- package/dist/v3/parameters.js.map +1 -1
- package/dist/v3/protocol.d.ts +50 -50
- package/dist/v3/protocol.d.ts.map +1 -1
- package/dist/v3/protocol.js +91 -210
- package/dist/v3/protocol.js.map +1 -1
- package/dist/v3/queries.d.ts +51 -0
- package/dist/v3/queries.d.ts.map +1 -0
- package/dist/v3/queries.js +128 -0
- package/dist/v3/queries.js.map +1 -0
- package/dist/v3/segments.d.ts +43 -19
- package/dist/v3/segments.d.ts.map +1 -1
- package/dist/v3/segments.js +84 -33
- package/dist/v3/segments.js.map +1 -1
- package/dist/v3/syntax.d.ts +68 -13
- package/dist/v3/syntax.d.ts.map +1 -1
- package/dist/v3/syntax.js +183 -102
- package/dist/v3/syntax.js.map +1 -1
- package/package.json +10 -6
- package/src/client.ts +293 -0
- package/src/core/account.ts +153 -24
- package/src/core/amount.ts +45 -10
- package/src/core/balance.ts +12 -5
- package/src/core/bank-info.ts +29 -5
- package/src/core/client.ts +83 -19
- package/src/core/config.ts +95 -35
- package/src/core/errors.ts +148 -54
- package/src/core/feedback.ts +16 -2
- package/src/core/transaction.ts +22 -4
- package/src/core/transport.ts +153 -32
- package/src/formats/camt.ts +153 -45
- package/src/formats/mt940.ts +244 -122
- package/src/formats/readers.ts +28 -31
- package/src/formats/record-budget.ts +18 -0
- package/src/formats/sepa-purpose.ts +29 -2
- package/src/index.ts +4 -2
- package/src/session/app-approval.ts +51 -38
- package/src/session/dialog-runner.ts +61 -31
- package/src/session/login-guard.ts +189 -87
- package/src/session/sepa-accounts.ts +63 -45
- package/src/session/session-setup.ts +105 -68
- package/src/session/session-state.ts +74 -23
- package/src/session/signed-dialog.ts +222 -0
- package/src/session/tan-selection.ts +50 -39
- package/src/session/user-prompts.ts +62 -18
- package/src/tan/challenge.ts +87 -64
- package/src/tan/flicker.ts +72 -23
- package/src/tan/tan-image.ts +15 -6
- package/src/tan/tan-models.ts +26 -7
- package/src/util/arguments.ts +40 -0
- package/src/util/async.ts +10 -9
- package/src/util/bytes.ts +14 -20
- package/src/util/call-context.ts +3 -2
- package/src/util/dates.ts +64 -33
- package/src/util/errors.ts +22 -6
- package/src/util/immutable-map.ts +15 -12
- package/src/util/inspect.ts +14 -0
- package/src/util/json.ts +16 -0
- package/src/util/text.ts +87 -15
- package/src/util/xml.ts +130 -52
- package/src/v3/account-extension.ts +7 -12
- package/src/v3/bank-connection.ts +126 -0
- package/src/v3/dialog.ts +186 -92
- package/src/v3/message.ts +140 -79
- package/src/v3/parameter-store.ts +226 -0
- package/src/v3/parameters.ts +166 -66
- package/src/v3/protocol.ts +103 -253
- package/src/v3/queries.ts +198 -0
- package/src/v3/segments.ts +86 -31
- package/src/v3/syntax.ts +172 -93
- package/dist/session/bank-connection.d.ts +0 -28
- package/dist/session/bank-connection.d.ts.map +0 -1
- package/dist/session/bank-connection.js +0 -48
- package/dist/session/bank-connection.js.map +0 -1
- package/dist/session/parameter-data.d.ts +0 -83
- package/dist/session/parameter-data.d.ts.map +0 -1
- package/dist/session/parameter-data.js +0 -68
- package/dist/session/parameter-data.js.map +0 -1
- package/dist/session/pin-tan-client.d.ts +0 -54
- package/dist/session/pin-tan-client.d.ts.map +0 -1
- package/dist/session/pin-tan-client.js +0 -153
- package/dist/session/pin-tan-client.js.map +0 -1
- package/dist/session/pin-tan-dialog.d.ts +0 -71
- package/dist/session/pin-tan-dialog.d.ts.map +0 -1
- package/dist/session/pin-tan-dialog.js +0 -124
- package/dist/session/pin-tan-dialog.js.map +0 -1
- package/dist/session/protocol.d.ts +0 -209
- package/dist/session/protocol.d.ts.map +0 -1
- package/dist/session/protocol.js +0 -75
- package/dist/session/protocol.js.map +0 -1
- package/dist/session/response-handler.d.ts +0 -48
- package/dist/session/response-handler.d.ts.map +0 -1
- package/dist/session/response-handler.js +0 -121
- package/dist/session/response-handler.js.map +0 -1
- package/dist/v3/client.d.ts +0 -24
- package/dist/v3/client.d.ts.map +0 -1
- package/dist/v3/client.js +0 -16
- package/dist/v3/client.js.map +0 -1
- package/src/session/bank-connection.ts +0 -51
- package/src/session/parameter-data.ts +0 -137
- package/src/session/pin-tan-client.ts +0 -186
- package/src/session/pin-tan-dialog.ts +0 -160
- package/src/session/protocol.ts +0 -311
- package/src/session/response-handler.ts +0 -130
- package/src/v3/client.ts +0 -29
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,519 @@
|
|
|
1
|
+
## 0.3.0
|
|
2
|
+
|
|
3
|
+
An app may notice these changes: arguments and options of another type than declared, such as a number as `bankCode`
|
|
4
|
+
or a `state` that is no string, and a user ID or customer ID of more than 30 characters fail with a `TypeError` before
|
|
5
|
+
the bank is contacted; the client reads its options once; `close` waits up to five seconds for the request on its way,
|
|
6
|
+
so the call it ends fails with `FinTsStateError` where the answer comes in time; a TAN goes out as the user typed it;
|
|
7
|
+
`console.log` shows the models of the package only by what identifies no person, account or TAN, and `toString` of
|
|
8
|
+
`FinTsFeedback` and `BankMessage` leaves out the bank's texts; `feedback` and `source` of an error are getters; and more
|
|
9
|
+
malformed bank data fail with `FinTsProtocolError`. Where these notes compare with the Dart package, they mean its
|
|
10
|
+
source after its release 0.2.0, unless they name 0.2.0, which differs in more ways: it keeps no refused login in the
|
|
11
|
+
saved state.
|
|
12
|
+
|
|
13
|
+
### Breaking
|
|
14
|
+
|
|
15
|
+
- `getTransactions` rejects a `format` other than `'auto'`, `'mt940'` and `'camt'` with a `TypeError`, before it waits
|
|
16
|
+
for other calls or contacts the bank: one such as `'CAMT'` asked for MT940, and `null` meant `'auto'`, as `undefined`
|
|
17
|
+
still does.
|
|
18
|
+
- `getBalance` and `getTransactions` reject anything but an `Account`, such as one written to JSON and read back, with a
|
|
19
|
+
`TypeError` before they wait for other calls or contact the bank. They logged in, fetched the SEPA account list, and
|
|
20
|
+
then failed with an unrelated `TypeError`.
|
|
21
|
+
- `selectTanMethod` rejects a TAN method or medium that is no string, and a missing method, with a `TypeError` before it
|
|
22
|
+
ends the dialog. A number as the method was saved and then dropped at the next login, which asked `tanMethodSelector`
|
|
23
|
+
instead; a medium of another type went out as its text or as a data element group, which the bank refused as a login;
|
|
24
|
+
and a state saved in between could not be restored.
|
|
25
|
+
- `FinTs3Client` throws a `TypeError` for options of another type, before contacting the bank: a missing `tanCallback`
|
|
26
|
+
or one that is no function, another callback that is neither a function nor `undefined` or `null`, a `state` that is
|
|
27
|
+
neither a string nor `undefined` or `null`, such as the parsed JSON a store hands back, and a `transport` without the
|
|
28
|
+
functions `post` and `close`. A callback that was no function failed the call after its messages had gone out,
|
|
29
|
+
`tanCallback` at the first TAN challenge after the PIN-signed login; a `state` that was no string was ignored; and a
|
|
30
|
+
transport without `close` made `close` reject.
|
|
31
|
+
- The client reads its options once, when it is built, as the Dart package does: assigning another `tanCallback`,
|
|
32
|
+
selector, `onBankMessage` or `onWarning` to the options object afterwards no longer changes what the client calls.
|
|
33
|
+
- `Account`, `Amount` and `FinTsConfig` throw a `TypeError` ('Invalid argument (<name>): …', without the value) for an
|
|
34
|
+
argument of another type than declared, as the Dart package's types refuse it: such as a number as `bankCode`,
|
|
35
|
+
`accountNumber`, `iban`, `currency` or `customerId`, a missing `bankCode`, a string as `minorUnits`, `scale` or
|
|
36
|
+
`typeCode`, anything but an array of strings as `allowedTransactions`, anything but a boolean as `allowInsecureUrl`,
|
|
37
|
+
and anything but an `AccountDataStatus` as `dataStatus`. `Amount.parseDecimal` does for a `value` or `currency` that
|
|
38
|
+
is no string. Such an account passed the constructor, threw in `toString`, and failed `getBalance` and
|
|
39
|
+
`getTransactions` only after the login, or matched none of the bank's accounts, so that the query failed with
|
|
40
|
+
`FinTsUnsupportedError` or went out without the bank's IBAN and BIC. A `dataStatus` written to JSON and read back
|
|
41
|
+
failed with an unrelated `TypeError` ('object is not iterable'), and a string counted as an empty status. An amount
|
|
42
|
+
kept a number as its currency, and a string as `minorUnits` threw a `RangeError` that showed it as a valid value.
|
|
43
|
+
- `FinTsConfig` throws a `TypeError` for a `userId` or `customerId` longer than 30 characters, the length FinTS 3.0
|
|
44
|
+
gives them (Formals, data type `id`). The bank refused such a login with a syntax error, which the client counted as
|
|
45
|
+
a refused login, so it sent the PIN no more.
|
|
46
|
+
- A `FinTsConfig` is frozen once its constructor has checked it: assigning to a field throws a `TypeError` in
|
|
47
|
+
strict-mode code and does nothing otherwise, and a subclass cannot add fields.
|
|
48
|
+
- As in the Dart package, `Mt940.parse` and `Mt940.parseTransactions` throw a `TypeError` for a `status` other than
|
|
49
|
+
`'booked'` and `'pending'`, `null` included, which meant `'booked'`, and for a `currency` that is no string;
|
|
50
|
+
`Camt.parse` and `Camt.parseTransactions` for a status other than these, `undefined` and `null`. Such a status became
|
|
51
|
+
the transactions' `status`, and such a currency that of their amounts. `SepaPurpose.parseParts` throws a `TypeError`
|
|
52
|
+
for a string, whose characters it took for parts, and for parts that are no strings.
|
|
53
|
+
- camt documents are read as XML 1.0 has them, failing `getTransactions` with `FinTsProtocolError` and `Camt.parse` with
|
|
54
|
+
`FormatError` for a name that is no XML name, such as `<1x>`, an end tag with another namespace prefix than its start
|
|
55
|
+
tag, a second XML declaration or one inside or after the root element, a processing instruction without a target, and
|
|
56
|
+
an attribute stated twice.
|
|
57
|
+
- camt: a `Dt` that holds a date and time is read like a `DtTm`. One whose time the client cannot read, such as
|
|
58
|
+
`2024-03-15T25:00:00` or `2024-03-15T10:00`, fails `getTransactions` with `FinTsProtocolError` and `Camt.parse` with
|
|
59
|
+
`FormatError` instead of counting on the date written. So do a UTC offset beyond ±14:00, such as `+15:00`, which XML
|
|
60
|
+
Schema does not allow and which the client used to read as an offset, and `24:00:00` with a fraction of a second other
|
|
61
|
+
than zero.
|
|
62
|
+
- `BankInfo.maxMessageSize`, `minTimeout` and `maxTimeout` are `undefined` for a value above 9999, the four digits HIBPA
|
|
63
|
+
allows, as in the Dart package. The client then sends messages of any size and starts a new dialog after 5 idle
|
|
64
|
+
minutes. `TanChallenge.plainMessage` leaves a structured challenge of more than 65,536 characters as the bank sent it,
|
|
65
|
+
as the Dart package does.
|
|
66
|
+
- `close` no longer aborts a request on its way at once: it waits up to five seconds for the answer and only then aborts
|
|
67
|
+
it, and the dialog ends then have five seconds once that request is over, so `close` may take about ten seconds where
|
|
68
|
+
the bank has stopped answering. Where the answer comes in time, the running call fails with `FinTsStateError` instead
|
|
69
|
+
of `FinTsTransportError`, also where that answer completes it, unless the answer brings an error of its own, such as a
|
|
70
|
+
rejected PIN, which it fails with instead; a request aborted after the five seconds still fails it with
|
|
71
|
+
`FinTsTransportError`. A call whose last answer arrives after `close`, within those five seconds, fails with
|
|
72
|
+
`FinTsStateError` instead of returning its result.
|
|
73
|
+
- A TAN goes out as the user typed it, except for full-width characters, which count as their ASCII counterparts, and
|
|
74
|
+
the ideographic space U+3000, which counts as a blank, as in the Dart package. Unicode NFKC changed it before:
|
|
75
|
+
superscript, circled and mathematical digits counted as digits, and characters that ISO 8859-1 holds went out altered,
|
|
76
|
+
such as `²` as `2` or a no-break space inside the TAN as a space, which the bank counts as a failed attempt; `µ`, `½`
|
|
77
|
+
and the like failed with a `TypeError` as not sendable. Other characters outside ISO 8859-1, and digits other than 0
|
|
78
|
+
to 9 for a `numericTan` method, fail the call with a `TypeError` before it is sent.
|
|
79
|
+
- `FinTsFeedback.toString` gives the code only, such as `FinTsFeedback(3072)`, and `BankMessage.toString` gives
|
|
80
|
+
`BankMessage(…)`, as `console.log` showed them already. So `String(f)`, template strings and loggers that call
|
|
81
|
+
`toString` no longer collect the bank's texts and parameters, which with return code 3072 hold the new login data, or
|
|
82
|
+
a message that may address the user by name. To show them to the user, use `code`, `text` and `parameters`, or
|
|
83
|
+
`subject` and `text`. The message of a `FinTsBankError` stays as it was, with the code, text and parameters of each
|
|
84
|
+
error, such as `9010: Konto gesperrt [DE89370400440532013000]`.
|
|
85
|
+
- `FinTsBankError.feedback` and `FormatError.source` are getters instead of own properties of the error, so
|
|
86
|
+
`Object.keys`, object spread and `JSON.stringify` of the error leave them out.
|
|
87
|
+
|
|
88
|
+
### Security
|
|
89
|
+
|
|
90
|
+
- Plain JavaScript can no longer change a `FinTsConfig` once checked, which could send the PIN to an http URL, or login
|
|
91
|
+
data the constructor had not checked, to the bank.
|
|
92
|
+
- `FinTsConfig` refuses an `allowInsecureUrl` that is no boolean, such as the string `'false'` read from an environment
|
|
93
|
+
variable, with a `TypeError`: it allowed plain http to a loopback host, where the PIN passes any proxy the runtime's
|
|
94
|
+
`fetch` takes from the environment.
|
|
95
|
+
- `console.log` and `util.inspect` on Node.js, Deno and Bun show the objects of this package only by what identifies no
|
|
96
|
+
person, account or TAN. An `Account`, `Balance`, `Transaction`, `TanMethod` or `TanMedium` shows as its `toString`, a
|
|
97
|
+
`TanChallenge` by its method, kind and attempt, a `FinTsFeedback` by its code and a `TanAnswer` by its kind.
|
|
98
|
+
`AccountDataStatus`, `BankInfo`, `FinTsConfig`, `FlickerCode` and `TanImage` show codes, versions and sizes only, the
|
|
99
|
+
statements of `Mt940.parse` and `Camt.parse` the last digits of the account and the number of transactions, and a
|
|
100
|
+
`BankMessage` shows as `BankMessage(…)`. Until now they showed every field: the bank's texts, references and
|
|
101
|
+
parameters (with return code 3072 the new login data), TAN media names, the TAN, the challenge data and image, the
|
|
102
|
+
login name and product ID, and a statement's full account. An error shows its message and stack, and a
|
|
103
|
+
`FinTsTransportError` its `statusCode`; the message of a `FinTsBankError` holds the texts and parameters of its
|
|
104
|
+
errors, as before. `JSON.stringify` and the browser console still show every field.
|
|
105
|
+
- Node.js's report of an uncaught error ignores what `console.log` shows of an object. It printed the whole `feedback`
|
|
106
|
+
of a `FinTsBankError`, including the texts, references and parameters of its successes and warnings and, with return
|
|
107
|
+
code 3072, the new login data, as well as the `source` of a `FormatError`. `JSON.stringify` of such an error, and
|
|
108
|
+
loggers that copy an error's fields, got them too. Both are getters now, so an uncaught `FinTsBankError` or
|
|
109
|
+
`FormatError` prints its message and stack only, as in the Dart package, and `JSON.stringify` leaves them out.
|
|
110
|
+
- `TanMedium.toString` leaves out the medium's name, which the user may have chosen after themselves, such as
|
|
111
|
+
`Max’s iPhone`: it gives `TanMedium(M, active)`, or, for a card, the last digits of its number,
|
|
112
|
+
`TanMedium(…2014, active)`, as before for a card without a name.
|
|
113
|
+
- A PIN that begins or ends with U+0085 (NEL) fails with a `TypeError` before it is sent, like one with other blanks at
|
|
114
|
+
either end. It went out with the byte 0x85, which the bank could count as a failed attempt.
|
|
115
|
+
- New login data (3072) next to an error in the answer to the login's TAN or app approval, such as 9941 for a wrong TAN,
|
|
116
|
+
an aborted dialog (9800) or any other error but a rejected PIN, end the old ones as well, as in the Dart package: the
|
|
117
|
+
call fails with `FinTsLoginDataChangedError`, the client ends the dialog where the bank keeps it open, and no later
|
|
118
|
+
call logs in with the old data. Until now the call failed with `FinTsTanError`, `FinTsDialogAbortedError` or
|
|
119
|
+
`FinTsBankError`, and the next call logged in again with the old login data and the PIN, which the bank may count as a
|
|
120
|
+
failed attempt, and asked for another TAN.
|
|
121
|
+
- A refused login, and the count of logins whose answer was lost, are restored from a saved state whose owner names the
|
|
122
|
+
server by something other than a string, such as a number or `null`, as in the Dart package; the rest of such a state
|
|
123
|
+
is dropped, as for another server. Until now the whole state was dropped, and the next call sent the PIN the bank had
|
|
124
|
+
refused.
|
|
125
|
+
- A `state` that is no string, such as the parsed JSON a json column returns, fails the `FinTs3Client` constructor with
|
|
126
|
+
a `TypeError`: the client ignored it, and with it a refused login it held, and sent the PIN again.
|
|
127
|
+
- A refused login stays refused where the `loginGuard` section of a saved state for the same user is damaged, such as a
|
|
128
|
+
return code without its code or `unreadLogins` that is no integer: the client restores a `FinTsLoginRefusedError`
|
|
129
|
+
without return codes and sends the PIN no more until `clearLoginRefusal`. Such damage dropped the refusal, and the
|
|
130
|
+
next call sent the refused PIN again. A state without the section, as fints-ts 0.1 and the Dart package 0.2.0 save
|
|
131
|
+
it, restores as before.
|
|
132
|
+
- `HttpTransport` copies each part of an answer as it arrives, as the Dart package does. An answer within
|
|
133
|
+
`maxResponseBytes` that a server sent in one-byte parts took gigabytes of memory and could end a Node.js process with
|
|
134
|
+
an out-of-memory error, which the app cannot catch. A `fetch` that refills the part it handed out corrupted the
|
|
135
|
+
answer.
|
|
136
|
+
- The documentation of `HttpTransport` and `allowInsecureUrl` warns that plain http to a local server goes wherever the
|
|
137
|
+
global `fetch` sends it, as https does. Whatever replaces `globalThis.fetch`, such as a test's stub, and on Node.js a
|
|
138
|
+
global dispatcher get every message with the PIN. A proxy that the runtime's `fetch` takes from the environment, as
|
|
139
|
+
Node.js does with `NODE_USE_ENV_PROXY=1`, and Deno and Bun do from `HTTP_PROXY`, sees the PIN unencrypted: exempt the
|
|
140
|
+
host with `NO_PROXY` or pass a `fetch` that connects directly. The Dart package connects to the loopback host
|
|
141
|
+
directly, also bypassing a client set with `runWithClient`.
|
|
142
|
+
- The limits on bank data are those of the Dart package. The following fail the call with `FinTsProtocolError`, and
|
|
143
|
+
`Mt940.parse`, `Camt.parse` and `Amount.parseDecimal` with `FormatError`: an answer with more than 1,000,000 data
|
|
144
|
+
elements and segments in its plain or in its encrypted part, or with more than one encrypted part (HNVSD); XML nested
|
|
145
|
+
more than 100 levels deep, an empty element such as `<a/>` included, or with more than 500,000 nodes besides text or
|
|
146
|
+
one per 16 characters, whichever is more; an MT940 field of more than 65,536 characters; and an amount written with
|
|
147
|
+
more than 64 characters. The limits were 200,000 data elements per answer, the encrypted part included, and XML of 256
|
|
148
|
+
levels or 1,000,000 elements and attributes; fields and amounts had none. A hostile answer can now take up to about
|
|
149
|
+
210 MB of memory while it is read, instead of about 25 MB. The 128 MiB a query may hold count each data element its
|
|
150
|
+
pages keep as 512 bytes instead of 256, and no longer count the elements of the encrypted part's envelope, so a query
|
|
151
|
+
of many short elements stops after half as many. The 200,000 statements and transactions per query stay.
|
|
152
|
+
- XML text or an attribute value of megabytes of `&`, or of unknown entities such as `&a;`, fails at its first bad
|
|
153
|
+
reference. The parser first found every reference, which took more than a second and about a gigabyte of memory for
|
|
154
|
+
12 MB, beyond the 210 MB the limits allow.
|
|
155
|
+
- camt: remittance information (`Ustrd`) of more than 65,536 characters, as for an MT940 field, fails
|
|
156
|
+
`getTransactions` with `FinTsProtocolError` and `Camt.parse` with `FormatError`. Megabytes of SEPA keywords took
|
|
157
|
+
about 40 times their size in memory.
|
|
158
|
+
- camt: blanks alone between elements, such as the line breaks of an indented document, are no longer kept as text,
|
|
159
|
+
which halves the memory such a document takes while it is read.
|
|
160
|
+
- MT940: the counterparty's IBAN and BIC come from the subfields `?31` and `?30` only, where the bank states them. A
|
|
161
|
+
payer could write `IBAN+…` and `BIC+…` into the end-to-end reference, and these filled `counterpartyIban` and
|
|
162
|
+
`counterpartyBic` where the subfields stated none. Both values stay readable in `purposeCodes`.
|
|
163
|
+
- In a browser, `HttpTransport` sends no cookies and no referrer with a message, and the browser's cache keeps no copy
|
|
164
|
+
of the exchange (`credentials: 'omit'`, `referrerPolicy: 'no-referrer'`, `cache: 'no-store'`). With the defaults,
|
|
165
|
+
cookies of the page and its URL as referrer went along to a server on the page's own origin.
|
|
166
|
+
- The relay server of the README refuses a body without `Content-Length` or of more than 1 MiB before reading it:
|
|
167
|
+
update relays built from it. The documentation of `FinTsTransport.post` says that the client bounds neither the time
|
|
168
|
+
of the exchange nor the size of the answer, so a transport of the app's own has to, as `HttpTransport` does.
|
|
169
|
+
|
|
170
|
+
### Fixed
|
|
171
|
+
|
|
172
|
+
- `close` ends the dialog of a request it aborts after five seconds, unless that request opened the dialog, whose ID
|
|
173
|
+
only the answer tells: the end goes out after the abort, under the next message number, since the bank may have
|
|
174
|
+
received the aborted message. Until now the abort dropped the dialog without an end, and the bank kept it open until
|
|
175
|
+
its timeout. The answer to that end refuses the login only for a rejected PIN, as at any dialog end, not for an error
|
|
176
|
+
such as a message number the bank did not expect because the aborted message never reached it.
|
|
177
|
+
- `close` gives the dialog ends five seconds once the request on its way, if any, is over: then the client stops
|
|
178
|
+
waiting for them, a transport that takes the abort, as `HttpTransport` does, stops them, and none goes out later. A
|
|
179
|
+
bank that has stopped answering held up `close` for the end of an open dialog until the transport's timeout, 90
|
|
180
|
+
seconds by default.
|
|
181
|
+
- The answer to a request on its way when `close` is called counts as any other, as in the Dart package: the logger gets
|
|
182
|
+
it, and the saved state keeps the bank and user parameter data, the customer system ID, the TAN medium and the SEPA
|
|
183
|
+
account list it brings. `close` aborted it at once, so a client restored from the state repeated the anonymous dialog,
|
|
184
|
+
the synchronization, which has the bank register another customer system ID, the lookup of the TAN media or the SEPA
|
|
185
|
+
account list, and its next login reported user parameter data version 0. The dialog of that request is ended as well,
|
|
186
|
+
also where the request opened it, whose ID only the answer tells, and a login answered so no longer counts as one
|
|
187
|
+
whose answer was lost.
|
|
188
|
+
- A dialog end that `close` keeps from going out, once the time after the request on its way is up, no longer reaches
|
|
189
|
+
the logger as an outgoing message, as in the Dart package: the logger showed a dialog end the bank never received.
|
|
190
|
+
- A TAN medium name the app passes to `selectTanMethod`, also from the saved state, goes out without blanks at either
|
|
191
|
+
end (Formals B.4.1), and one of blanks only as no name, as in the Dart package: a bank that knows the medium without
|
|
192
|
+
them refused the login, and the state kept the refusal. `selectedTanMedium` and the state keep the name as the app
|
|
193
|
+
passed it. A name the bank issued still goes back as the bank sent it, blanks at either end included, and the medium
|
|
194
|
+
in use of a state saved by 0.2.0, which does not tell the two apart, as 0.2.0 sent it.
|
|
195
|
+
- `selectTanMethod(method, null)` leaves the TAN medium to the next login, which looks the media up where the method
|
|
196
|
+
needs one, as without a medium and as in the Dart package. The login went out without a medium, which the bank
|
|
197
|
+
refused, and the client kept the refusal until `clearLoginRefusal`.
|
|
198
|
+
- A `tanMethodSelector` or `tanMediumSelector` that returns `null` picks the first method or medium, as for `undefined`,
|
|
199
|
+
instead of failing the call with a `TypeError`; the selector types allow `null`.
|
|
200
|
+
- `null` for `logger`, `onBankMessage`, `onWarning`, `tanMethodSelector`, `tanMediumSelector` or `state` means none, as
|
|
201
|
+
in the Dart package. `logger: null` failed every call that exchanged messages, and `close`, after their traffic;
|
|
202
|
+
`onBankMessage: null` and `onWarning: null` failed a call whose answer carried a bank message or a warning; and a
|
|
203
|
+
`null` selector failed the call after the PIN-signed synchronization or the lookup of the TAN media.
|
|
204
|
+
- `null` counts as not given for the details of an `Account`, whose `toString` threw for an `accountNumber` of `null`,
|
|
205
|
+
for the `customerId` of `FinTsConfig`, which is then the user ID, where a `TypeError` without the package's message
|
|
206
|
+
was thrown, and for the `currency` of `Mt940.parse`, which gave amounts in the currency `null` instead of the
|
|
207
|
+
`FormatError` 'MT940 statement without currency', as in the Dart package.
|
|
208
|
+
- Where the bank parameter data rule out a login, by the PIN's length or the message's size, the client fetches them
|
|
209
|
+
anew in an anonymous dialog, which carries no PIN, and tries the login once more, which goes out only if the new
|
|
210
|
+
limits allow it; where they rule it out as well, the call fails with the error that names the new limits, as in the
|
|
211
|
+
Dart package. Until now outdated parameter data, as saved ones may be, failed every call that logs in with a
|
|
212
|
+
`TypeError` (`FinTsProtocolError` for the size) until the app dropped `client.state`. It takes only the limits from
|
|
213
|
+
the anonymous answer, and only from parameter data of another version than those kept, the PIN's length only where
|
|
214
|
+
they state it. Those limits serve until the login brings the user's parameter data, which the login asks for by
|
|
215
|
+
reporting version 0, so the login the new limits judge may be up to two bytes shorter than the one the old ones
|
|
216
|
+
stopped. The anonymous parameter data never replace the user's. A bank that does not answer anonymously cannot refresh
|
|
217
|
+
them; the call then fails as before, without sending the PIN.
|
|
218
|
+
- A SEPA account list saved empty, as fints-ts 0.1 and the Dart package 0.2.0 saved it, is ignored on restore, as the
|
|
219
|
+
Dart package does after 0.2.0, so the client asks the bank for it again. Until the bank changed its user parameter
|
|
220
|
+
data, such a state kept the client from asking: `getAccounts` returned the accounts without their BIC, and an account
|
|
221
|
+
the app built from its IBAN went out without one, which a bank may refuse, or failed with `FinTsUnsupportedError`
|
|
222
|
+
where the user parameter data name the account by its number only.
|
|
223
|
+
- `TanChallenge.tanMediumName` is `undefined` for a challenge in the dialog that looks up the TAN media, or where the
|
|
224
|
+
bank echoes it, instead of the placeholder `noref`.
|
|
225
|
+
- The client no longer keeps the result of its last call, such as the transactions, until its next call or `close`.
|
|
226
|
+
- `console.log` and `util.inspect` show an `Amount` as its `toString`, such as `-123.45 EUR`, as the Dart package prints
|
|
227
|
+
it, instead of its fields `minorUnits`, `scale` and `currency`.
|
|
228
|
+
- An answer that is no FinTS message at all, such as the web page of a proxy or a maintenance notice, fails with the
|
|
229
|
+
`FinTsProtocolError` 'Malformed bank data: Not a FinTS message: no message header' instead of 'Malformed bank data:
|
|
230
|
+
Segment without terminator'. A message that starts with its header and is cut short still reports what is wrong with
|
|
231
|
+
it.
|
|
232
|
+
- `HttpTransport` refuses an answer whose `Content-Length` announces more than `maxResponseBytes` at once, without
|
|
233
|
+
reading it, with the same `FinTsTransportError` as for a body over the limit, as the Dart package does. A server that
|
|
234
|
+
announced more and then stalled held the call until the timeout, 90 seconds by default. One that sent the whole answer
|
|
235
|
+
had it read up to the limit before the refusal.
|
|
236
|
+
- `getTransactions` reads statement data that a bank sends as text instead of binary data, as it did for booked camt
|
|
237
|
+
documents: booked and pending MT940 (HIKAZ) and the pending camt document (HICAZ) were dropped without an error. A
|
|
238
|
+
malformed or overlong binary length still fails the call with `FinTsProtocolError`.
|
|
239
|
+
- `TransactionFormat` `auto` takes camt.052 where the bank offers it and MT940 cannot be requested for the account (the
|
|
240
|
+
bank offers no `HKKAZ` version the client implements, or PIN/TAN does not permit it), instead of failing with
|
|
241
|
+
`FinTsUnsupportedError`.
|
|
242
|
+
- A FinTS 3.0 time `240000` is midnight of the next day. So `Balance.bookedAsOfTime`, `Balance.bookingTime` and
|
|
243
|
+
`TanChallenge.validUntil` are set for it instead of `undefined`, and the account extension of the user parameter data
|
|
244
|
+
is read with it instead of being dropped as malformed, BIC, balance and data status included. `bookedAsOf` and
|
|
245
|
+
`bookingDate` stay the stated day.
|
|
246
|
+
- camt: a booking or value date given as `DtTm` without a `T` after the date, such as `2023-12-31`,
|
|
247
|
+
`2024-01-02 10:00:00` or `2024-01-02t10:00:00`, is the date written, as in the Dart package, instead of failing
|
|
248
|
+
`getTransactions` with `FinTsProtocolError`. Whatever follows the date is not read then. A `DtTm` or `Dt` with the
|
|
249
|
+
time `24:00:00` is midnight of the next day, as a FinTS 3.0 time `240000` is. A `Dt` with date and time counts on its
|
|
250
|
+
German day, as a `DtTm` does: `2024-03-15T23:30:00Z` is 16 March.
|
|
251
|
+
- MT940 and camt: `SVWZ+` after `ABWA+` or `ABWE+`, the order some banks write them in, starts the remittance
|
|
252
|
+
information, which went into the ultimate debtor or creditor, leaving the whole text, keywords and all, as the
|
|
253
|
+
purpose. Any other keyword in that text still starts no value, and one that occurs twice still has none.
|
|
254
|
+
- MT940: `getTransactions` joins pages with `@@` where none of them holds a line break. After a first page without `@@`,
|
|
255
|
+
such as `:20:X`, the `@@` of the other pages were read as text, and the query returned no transactions without an
|
|
256
|
+
error.
|
|
257
|
+
- camt: a comment ends only after its `<!--`, so that `<!-->` starts one instead of closing at once, which turned the
|
|
258
|
+
comment into text; an attribute counts by its name, namespace prefix and all, so that `q:Ccy` is not the currency of
|
|
259
|
+
an amount; an element named with a leading colon, such as `<:Ntry>`, is not the unprefixed one.
|
|
260
|
+
- The `EREF`, `MREF` and `CRED` of camt `purposeCodes` keep the place the remittance text gives them, before `SVWZ` as
|
|
261
|
+
banks write them, instead of following all other keywords. Their values still come from their elements only.
|
|
262
|
+
- MT940: the booking date of an MT942 lies between its value date and the creation date `:13D:`, which the statement's
|
|
263
|
+
balances otherwise bound, instead of in the year closest to the value date: a booking `1230` with value date
|
|
264
|
+
2023-06-15 in an MT942 created on 2024-01-02 is dated 2023-12-30, not 2022-12-30.
|
|
265
|
+
- MT940: a statement whose closing balance is dated before its opening balance, or whose creation date `:13D:` cannot be
|
|
266
|
+
read or is stated twice, is a `FormatError` (`FinTsProtocolError` in `getTransactions`) instead of being read.
|
|
267
|
+
- MT940: a statement that balances is read also where a sum on the way lies beyond what an `Amount` holds (about 90
|
|
268
|
+
trillion at two decimal places, less with more decimals), as camt batch bookings are. It failed `getTransactions` with
|
|
269
|
+
`FinTsProtocolError` 'Malformed bank data: MT940 amounts too large to add up', and `Mt940.parse` with `FormatError`. A
|
|
270
|
+
statement that does not balance fails with 'MT940 transactions do not add up to the closing balance' however large its
|
|
271
|
+
amounts, as in the Dart package.
|
|
272
|
+
- MT940: the subfield that ends a `:86:` field keeps the blanks at its end, as in the Dart package and before 0.2.0.
|
|
273
|
+
Where the bank writes it before subfields it continues, such as `?33Mustermann?32Max `, the purpose, the
|
|
274
|
+
counterparty's name and the SEPA keywords are joined with that blank (`Max Mustermann`, not `MaxMustermann`). Only the
|
|
275
|
+
statement end and line feeds are dropped from the end of a field.
|
|
276
|
+
- camt: a batch booking whose details add up to it is split also where their sum on the way lies beyond what an `Amount`
|
|
277
|
+
holds (about 90 trillion at two decimal places), whatever the order of the details; such a batch stayed one booking.
|
|
278
|
+
- U+0085 (NEL), the byte 0x85 in ISO 8859-1 text, counts as a blank wherever the client drops the blanks around a value,
|
|
279
|
+
as Unicode and the Dart package have it. That covers what it reads: MT940, SEPA purpose and camt values (a camt `Sts`
|
|
280
|
+
of `PDNG` followed by it reads as pending, not booked), the parameter data, such as the account owner, a segment's
|
|
281
|
+
type and numbers, amounts and challenge texts; and what it sends: segment values, the login details of `FinTsConfig`
|
|
282
|
+
and the TAN the user enters. The IBAN and BIC of an `Account`, which go without any blanks, drop it as well.
|
|
283
|
+
- camt: U+0085 (NEL), the byte 0x85 in ISO 8859-1, counts as white space between the parts of a start or end tag and
|
|
284
|
+
between the nodes outside the root element, as other Unicode white space did and as in the Dart package. Such a
|
|
285
|
+
document failed `getTransactions` with `FinTsProtocolError` and `Camt.parse` with `FormatError`.
|
|
286
|
+
- Bank text read as UTF-8 that starts with two byte order marks loses both, as in the Dart package; the second stayed as
|
|
287
|
+
U+FEFF in data element texts and the message log, and on an MT940 page after the first it failed `getTransactions`
|
|
288
|
+
with `FinTsProtocolError`.
|
|
289
|
+
- The security control reference that ties the signature head (HNSHK) to the signature end (HNSHA) is drawn uniformly:
|
|
290
|
+
its first nine digits up to 794967295 came up a quarter more often than the rest.
|
|
291
|
+
- A number in the parameter data beyond 9007199254740991 (2^53 - 1), which a JavaScript number holds only approximately,
|
|
292
|
+
counts as not stated, as a malformed one does. Such a version of the bank or user parameter data went back to the bank
|
|
293
|
+
as `100000000000000000000` or `1e+22` instead of `0`. A minimum PIN length of that size failed every login with a
|
|
294
|
+
`TypeError`. Polling parameters of that size let a decoupled TAN method poll every 60 seconds with no limit on the
|
|
295
|
+
number of requests other than the 10 minutes, instead of the defaults. An account type of that size made `category`
|
|
296
|
+
`'other'` instead of `'unknown'`.
|
|
297
|
+
- A number in the parameter data written `-0`, such as a version or an account type, reads as 0, as in the Dart package,
|
|
298
|
+
not as JavaScript's negative zero, which `util.inspect` shows as `-0` and `Object.is` tells apart from 0.
|
|
299
|
+
- An account in the user parameter data whose national account has the older layout without sub-account (number, country
|
|
300
|
+
and bank code, such as `1234567890:280:12345678`) keeps its country and bank code, as in the Dart package. It got the
|
|
301
|
+
sub-account `280`, the country code `12345678` and the configured bank code, so queries for it named an account the
|
|
302
|
+
bank does not know. Three elements whose last is a country code, such as `1234567890:01:280` or `987654321::040`,
|
|
303
|
+
still read as number, sub-account and country code: a country code has three digits, a German bank code eight.
|
|
304
|
+
- `getAccounts` completes an account of the user parameter data with the IBAN and BIC of the SEPA account list also
|
|
305
|
+
where one of the two states no bank or country code, which matches any, as in `Account.matches` and the Dart package.
|
|
306
|
+
This happens with a saved state edited so, or where a code the bank sent was only a byte order mark. The list entry
|
|
307
|
+
came out as an account of its own, and an account the app built from its IBAN went out as that entry, without bank
|
|
308
|
+
code, permitted transactions and currency.
|
|
309
|
+
- Up to three further pages of a query may ask for an approval, as its first page may: the client asks `tanCallback`, or
|
|
310
|
+
waits for the app approval, as for the first page. Until now only the first page could, and a bank that asked again
|
|
311
|
+
for a later page failed every such query with `FinTsProtocolError`, without asking the user. Where a fourth further
|
|
312
|
+
page of the same query asks for an approval, the call still fails with `FinTsProtocolError`, before the user is asked,
|
|
313
|
+
and the dialog ends. A query thus asks the user four times at most, and an approval the user cancels still fails the
|
|
314
|
+
call with `FinTsTanCancelledError` and loses the pages fetched so far. The Dart package 0.2.0 asks for every page, up
|
|
315
|
+
to 1000.
|
|
316
|
+
- `close` no longer waits for a transport that ignores the abort: five seconds after `close`, the request on its way
|
|
317
|
+
fails with a `FinTsTransportError` whatever the transport, and the dialog ends then have five seconds of their own.
|
|
318
|
+
A custom transport that ignored the `AbortSignal` and had no timeout of its own held up the call, and with it
|
|
319
|
+
`close`, forever.
|
|
320
|
+
- A network error whose cause has no message of its own, as Node.js reports a refused or failed connection to a host
|
|
321
|
+
with both IPv6 and IPv4 addresses, gives the reasons of the attempts or the error code, such as
|
|
322
|
+
`fetch failed: connect ECONNREFUSED ::1:3000; connect ECONNREFUSED 127.0.0.1:3000`, instead of just `fetch failed: `.
|
|
323
|
+
- The bank's dialog abort message (Formals B.7.6) fails the call with a `FinTsBankError` that carries the bank's
|
|
324
|
+
return codes and text, and ends the dialog. The bank sends it unencrypted, with the dialog ID `unbekannt` and message
|
|
325
|
+
number 9999, where it cannot tell them, such as for a broken message header, an unknown bank code or a bank locked
|
|
326
|
+
for a release. Such an answer to any message but the first of a dialog failed with the `FinTsProtocolError` 'The
|
|
327
|
+
answer belongs to another message than the one sent', which lost the bank's text, and the client then sent a dialog
|
|
328
|
+
end to the dialog the bank had aborted.
|
|
329
|
+
- Balance and transaction queries that name the account by its international account (`HKSAL` 7 and 8, `HKKAZ` 7,
|
|
330
|
+
`HKCAZ`) name an account with BIC by IBAN and BIC only, without account number, sub-account and bank code, where the
|
|
331
|
+
bank parameter data rule out the national account (`HISPAS` 'Nationale Kontoverbindung erlaubt' `N`). They no longer
|
|
332
|
+
send an IBAN without its BIC, which the specification rules out (Messages B.3.2): such an account goes out with its
|
|
333
|
+
account number, sub-account and bank code instead, where it has an account number. Until now these queries always
|
|
334
|
+
sent the national account, and an IBAN without BIC with an empty BIC.
|
|
335
|
+
- The account extension of the user parameter data (BIC, data status and complete balance) is read where the bank
|
|
336
|
+
pads it with U+0085 (NEL) or U+00A0, as the client allows for the other fields. Such an extension was ignored, so the
|
|
337
|
+
client fetched the BIC with the SEPA account list and the balance with a balance query.
|
|
338
|
+
- A synchronization with the one-step method that the bank answers with `9955` (one-step TAN method not allowed) and
|
|
339
|
+
`3920`, as PIN/TAN B.8.2 prescribes for a user bound to two-step methods, is repeated with a method the bank lists,
|
|
340
|
+
with or without `9800`. It refused the login for good and forgot the PIN.
|
|
341
|
+
- A call whose TAN method prompt after a refused login ends with an error, such as `close` during
|
|
342
|
+
`tanMethodSelector`, fails with that error and leaves no refusal behind. The refusal, which named a TAN method the
|
|
343
|
+
user may not use and not the PIN, outlasted the call: the client forgot the PIN, saved the refusal in `client.state`,
|
|
344
|
+
and refused every login until `clearLoginRefusal`.
|
|
345
|
+
- Plain JavaScript can no longer change `Transaction.purposeCodes` or `AccountDataStatus.inventory` through the map
|
|
346
|
+
inside them: `ImmutableMap` keeps its entries in an ECMAScript-private field.
|
|
347
|
+
- A flicker code whose start code states a length of 0, or sets bit 6 of its length, is refused, as a data element of
|
|
348
|
+
such a length already was. `FlickerCode.parse` read an empty start code, which rendered as ASCII data of length 0,
|
|
349
|
+
and dropped bit 6.
|
|
350
|
+
- A flicker code whose tenth control byte announces another one is refused. It was read as if the list had ended
|
|
351
|
+
there, and the rest of the code was read from the wrong position.
|
|
352
|
+
- A blank in the data of a flicker code, such as `1,00 EUR`, stays part of the data. The client removed every white
|
|
353
|
+
space before reading the code, so such a code in HHD_UC was refused and the challenge had no `flickerCode`.
|
|
354
|
+
- A challenge whose HHD_UC is neither a photoTAN image nor a flicker code takes the flicker code of its challenge text
|
|
355
|
+
(`CHLGUC`). `TanChallenge.flickerCode` was `undefined` then, although `plainMessage` left out the code.
|
|
356
|
+
- Challenge text counts as a combined challenge only where it starts with `CHLGUC`, after blanks, and the four digits
|
|
357
|
+
after it state the length of the code. Elsewhere it is shown as the bank sent it: `plainMessage` dropped everything
|
|
358
|
+
up to a `CHLGTEXT` anywhere in the text, such as in a payment purpose the bank copied in, and a `CHLGUC` in the
|
|
359
|
+
middle of the text gave a flicker code.
|
|
360
|
+
- `TanImage.tryParse` refuses a container that declares an image of 0 bytes. It gave an image whose `toDataUrl()` was
|
|
361
|
+
an empty `data:` URL.
|
|
362
|
+
- MT940: the balance date `0` or `000000`, which the specification allows for the first statement of an account,
|
|
363
|
+
reads as no date (`openingDate` or `closingDate` `undefined`). It failed `getTransactions` with
|
|
364
|
+
`FinTsProtocolError` and `Mt940.parse` with `FormatError`.
|
|
365
|
+
- MT940: the `:61:` customer reference `KREF+` reads as the `KREF+` value of `:86:`, as the specification has it,
|
|
366
|
+
instead of `'KREF+'` for every such transaction.
|
|
367
|
+
- MT940: a bank code in `?30` next to an IBAN in `?31` is `counterpartyBankCode`, not `counterpartyBic`.
|
|
368
|
+
- `Mt940.parse` reads text that starts with a byte order mark or blanks, as `fs.readFile(…, 'utf8')` returns it. It
|
|
369
|
+
dropped the first `:20:` and returned its statement without `reference`.
|
|
370
|
+
- camt: a transaction whose remittance information is structured only (`Strd/CdtrRefInf/Ref`, such as an RF creditor
|
|
371
|
+
reference) takes that reference as its `purpose`, which was `undefined` or the `AddtlTxInf`.
|
|
372
|
+
- The README example saves `client.state` after `close`, not before, also where `close` fails: the answers `close`
|
|
373
|
+
waits for may bring a PIN the bank rejects at the dialog end, which a client restored from a state saved before would
|
|
374
|
+
send again, as well as the parameter data and the customer system ID of a request on its way.
|
|
375
|
+
- The README says what the type declarations need: the global `URL`, `AbortSignal` and `fetch` types, from the
|
|
376
|
+
TypeScript lib `DOM` or `@types/node`, instead of a TypeScript version.
|
|
377
|
+
|
|
378
|
+
## 0.2.0
|
|
379
|
+
|
|
380
|
+
### Breaking
|
|
381
|
+
|
|
382
|
+
- Keep a `FinTs3Client` out of Vue's reactive state (`ref`, `reactive`, Pinia): its fields are ECMAScript private now,
|
|
383
|
+
which Vue's proxies cannot reach, so every call fails with a `TypeError`. Use a plain variable, a `shallowRef` or
|
|
384
|
+
`markRaw`.
|
|
385
|
+
- `FinTsTransport.post` takes an `AbortSignal` as fourth argument, which the client aborts on `close`: pass it to
|
|
386
|
+
`fetch`. Code that calls `post` itself must pass one; `HttpTransport.post` takes it optionally.
|
|
387
|
+
- A custom transport reports failures as `FinTsTransportError`, with `statusCode` for an HTTP error. The client turns
|
|
388
|
+
any other error, another `FinTsError` included, into a `FinTsTransportError` that keeps only its message and that of
|
|
389
|
+
its cause, and `FinTsTransportError` takes and carries no `cause` any more.
|
|
390
|
+
- A refused login is a `FinTsLoginRefusedError`, which `FinTsPinError` and `FinTsLoginDataChangedError` now extend, also
|
|
391
|
+
where the bank ends the dialog in answer to the login (it was `FinTsDialogAbortedError`). The client sends the PIN no
|
|
392
|
+
more then: see Added for `loginRefusal` and `clearLoginRefusal`.
|
|
393
|
+
- `FinTsTanSetupError` replaces `FinTsUnsupportedError` where the client has no TAN method or medium to log in with: let
|
|
394
|
+
the user choose a medium or another method (`selectTanMethod`) rather than hide the feature.
|
|
395
|
+
- `FinTsError` takes the message only, as `Error` does, and `FinTsBankError` takes no `name`: a subclass declares
|
|
396
|
+
`override name = '…'`.
|
|
397
|
+
- `FinTsConfig` throws a `TypeError` for what the bank would refuse: a URL with user name or password, a country code of
|
|
398
|
+
other than three digits (280 for Germany, not 276), a German bank code of other than eight, and login details outside
|
|
399
|
+
ISO 8859-1. It trims the login details and the product, and `config.url` is a new copy at each access.
|
|
400
|
+
- `HttpTransport` throws a `TypeError` for a `timeoutMs` that is no positive number up to 2147483647, and for a
|
|
401
|
+
`maxResponseBytes` that is no positive number.
|
|
402
|
+
- A TAN longer than `TanMethod.maxTanLength`, with anything but the digits 0 to 9 for a `numericTan` method, or with
|
|
403
|
+
characters outside ISO 8859-1 fails the call with a `TypeError` before it is sent. Full-width digits count as digits
|
|
404
|
+
(NFKC).
|
|
405
|
+
- A TAN callback answer that is no `TanAnswer`, such as the `undefined` of a callback that returns nothing, fails the
|
|
406
|
+
call with a `TypeError`.
|
|
407
|
+
- Bank data are read strictly, failing `getTransactions` with `FinTsProtocolError` and the parsers with `FormatError`:
|
|
408
|
+
an MT940 statement that does not balance, states a balance, its account or its number twice, or holds an unreadable
|
|
409
|
+
balance, and MT940 text without fields; in camt, an unreadable date, a `DtTm` without time, and a document without
|
|
410
|
+
statements.
|
|
411
|
+
- A negative amount next to a credit/debit mark is malformed: in camt and HISAL it fails the call, and it voids the
|
|
412
|
+
account extension of the user parameter data; a camt debit of `-5.00` used to read as a credit.
|
|
413
|
+
- `TanImage.tryParse` takes PNG, JPEG, GIF, WebP and BMP only, no SVG, and `TanImage.mimeType` is in lower case.
|
|
414
|
+
`FlickerCode.parse` rejects a code that would not render as the bank sent it, so `TanChallenge.flickerCode` is
|
|
415
|
+
`undefined` for it.
|
|
416
|
+
- `Account` keeps IBAN and BIC without blanks and in capitals. `Account.allowedTransactions` counts segment IDs only,
|
|
417
|
+
such as `HKCAZ`, no versioned names such as `HKCAZ_1`.
|
|
418
|
+
- `FinTsFeedback.parameters`, and with them the new login data of `FinTsLoginDataChangedError`, and
|
|
419
|
+
`TanChallenge.reference` are read one character per byte (ISO 8859-1), as the client sends them back.
|
|
420
|
+
|
|
421
|
+
### Security
|
|
422
|
+
|
|
423
|
+
- The client keeps the PIN in a private field, out of reach of `JSON.stringify` and Node.js's `util.inspect`, though not
|
|
424
|
+
of a debugger or the browser's DevTools: never log the client. It forgets the PIN once closed or refused.
|
|
425
|
+
- A refused login is kept in `state`, as the bank's return codes, so that a client restored from it, also one for
|
|
426
|
+
another URL of the bank, does not send the PIN. Any error in the answer to a login refuses it, and so does a wrong PIN
|
|
427
|
+
reported later, at the dialog end included. Run the clients of one user one after another: the state saved last wins.
|
|
428
|
+
- After two logins in a row whose answer was lost, timed out or could not be read, which the bank may have counted, the
|
|
429
|
+
client refuses the login itself, with a `FinTsLoginRefusedError` without return codes, also across restored clients.
|
|
430
|
+
- A call sends at most three logins the bank refuses: another TAN method and a new customer system ID count once per
|
|
431
|
+
call each, and a refused one-step login is repeated with another method only where the bank names the method (9075, or
|
|
432
|
+
a 3920 next to no error but 9050 or 9800).
|
|
433
|
+
- New login data (3072) fail the call as soon as an answer to the login brings them, before any approval and also next
|
|
434
|
+
to errors; `clearLoginRefusal` cannot lift them.
|
|
435
|
+
- `close` stops a running call at its next message and aborts the request on its way; only the ends of its dialogs go
|
|
436
|
+
out after it.
|
|
437
|
+
- Error messages keep the PIN and account data out: a transport's error passes on its message only, without `cause`;
|
|
438
|
+
`FormatError` and `FinTsProtocolError` leave out the data; a URL with credentials is rejected before `fetch` puts it
|
|
439
|
+
in an error.
|
|
440
|
+
- Messages go to the bank's URL only: `HttpTransport` rejects the answer to a redirect its `fetch` followed or from
|
|
441
|
+
another URL, and the transport gets a copy of the checked URL for each message.
|
|
442
|
+
- An answer must be one complete message, with the number and, once assigned, the dialog ID of the message sent: one cut
|
|
443
|
+
short, broken in its framing, joined to another or answering another message fails with `FinTsProtocolError`. The
|
|
444
|
+
first answer of a dialog cannot be matched, so a relay must never mix up answers.
|
|
445
|
+
- Parameter data come only from the answers to a dialog's opening; the anonymous dialog's serve until the user's arrive,
|
|
446
|
+
and those of another user, of a rejected customer system ID (9391) or of a state from an earlier version or the Dart
|
|
447
|
+
package are fetched anew.
|
|
448
|
+
- A balance (HISAL) and camt transactions (HICAZ) must be for the account asked for, or the call fails with
|
|
449
|
+
`FinTsProtocolError`. MT940 is not checked, since banks write the `:25:` line in many ways.
|
|
450
|
+
- An account the app builds itself goes out as the bank knows it and is checked against the transactions the bank
|
|
451
|
+
permits for it; one the bank names nowhere fails with `FinTsUnsupportedError` where those lists are complete
|
|
452
|
+
(UPD-Verwendung 0).
|
|
453
|
+
- Hostile answers no longer exhaust the memory or hold up the thread: past 200,000 data elements per answer, 128 MiB or
|
|
454
|
+
200,000 statements and transactions per query, or XML of 256 levels or a million elements and attributes, a call fails
|
|
455
|
+
with `FinTsProtocolError`, and `Mt940.parse` and `Camt.parse` with `FormatError`; reading takes linear time.
|
|
456
|
+
- An MT940 statement must balance, and name its account and number once, so that a payer cannot add a transaction or an
|
|
457
|
+
account with a purpose line that starts like a field, such as `:61:` or `:25:`.
|
|
458
|
+
- A SEPA keyword in the text the payer or payee writes (`SVWZ+`, `ABWA+`, `ABWE+`) is part of that text, and one that
|
|
459
|
+
occurs twice has no value: such text replaced the creditor ID, mandate reference or IBAN the bank stated.
|
|
460
|
+
- The creditor ID of a camt transaction is the creditor's (`Cdtr`) only, and the `EREF`, `MREF` and `CRED` of
|
|
461
|
+
`purposeCodes` come from their elements only, never from the remittance text.
|
|
462
|
+
- A flicker code that would not render as the bank sent it is refused rather than shown altered on the TAN generator,
|
|
463
|
+
and so is a data element length of 0 or above 63. A TAN image of type SVG, which may carry scripts, is refused.
|
|
464
|
+
- The docs say to show challenge text as text, never as HTML (`innerHTML`, `v-html`): it is the bank's text, or a
|
|
465
|
+
relay's.
|
|
466
|
+
- The README relay serves the signed-in sessions of the app only, limits their requests, forwards to the bank of the
|
|
467
|
+
session only, refuses redirects and passes the signal on: update relays built from it.
|
|
468
|
+
|
|
469
|
+
### Fixed
|
|
470
|
+
|
|
471
|
+
- The README relay reports the relay's HTTP status as `FinTsTransportError.statusCode`, and its server passes the bank's
|
|
472
|
+
on. Without it, a bank that fails on the anonymous announcement of strong authentication never delivered its parameter
|
|
473
|
+
data.
|
|
474
|
+
- The README names the minimum Deno (2.1) and Bun (1.2.6): with older ones a call from inside a callback waits forever
|
|
475
|
+
instead of failing with `FinTsStateError`.
|
|
476
|
+
- The docs say when a call logs in again, which may ask for another approval, that `getTanMethods` may log in, that
|
|
477
|
+
`FinTsUnsupportedError` may follow a login, and the client's own limits of an app approval: 60 status requests where
|
|
478
|
+
the bank states none, and 10 minutes.
|
|
479
|
+
- The PIN's length limits apply to the login only: a synchronization whose first parameter data ruled out the PIN the
|
|
480
|
+
bank had accepted failed its own dialog end.
|
|
481
|
+
- An answer to a TAN or an app approval that asks for an approval once more (0030, 3955) fails with `FinTsProtocolError`
|
|
482
|
+
instead of reading as done, and only the first page of a query may ask for an approval.
|
|
483
|
+
- While the client polls for an app approval, new instructions of the bank replace the open prompt, whose
|
|
484
|
+
`TanChallenge.resolved` settles; a settled prompt is no longer kept until `close`.
|
|
485
|
+
- `getTanMedia` asks the bank unless the same call has just looked the media up; the list of a lookup that found no
|
|
486
|
+
active medium is handed out by every call; a TAN method switched back to has its media looked up anew;
|
|
487
|
+
`clearLoginRefusal` forgets the TAN medium, which the bank may have refused.
|
|
488
|
+
- `getTransactions` rejects a `from` or `to` that is no valid `Date` with a `TypeError`, before it waits for other
|
|
489
|
+
calls; an Invalid Date went out as `0NaNNaNNaN`.
|
|
490
|
+
- Values the bank issued go back as it sent them: dialog ID, customer system ID, TAN order reference, position to
|
|
491
|
+
continue at and TAN medium name, such as one in UTF-8 that fits ISO 8859-1, which the bank did not know otherwise.
|
|
492
|
+
- A SEPA account list the bank answers by ending the dialog counts as rejected, and an empty one is not saved, so that
|
|
493
|
+
neither costs every client another login.
|
|
494
|
+
- `HttpTransport` calls its `fetch` as a plain function (a browser's native one failed with `Illegal invocation`),
|
|
495
|
+
checks the size of an answer without a stream body, and reads the body of node-fetch.
|
|
496
|
+
- MT940: `@@` separates the lines wherever the first line holds it; each page is decoded on its own; a booking date lies
|
|
497
|
+
in the year that places it within its statement; only `?` separates the subfields of `:86:`.
|
|
498
|
+
- camt: a batch booking is split only into details that add up to it, in its currency; details count in `NtryDtls` and
|
|
499
|
+
purpose lines in `RmtInf` only; a `DtTm` counts on its German day; purpose lines cut at 35 characters keep their
|
|
500
|
+
blanks; `&constructor;` is an unknown entity.
|
|
501
|
+
- Models keep copies of the `Date`s they are given, so that changing one in place changes no other, nor what a later
|
|
502
|
+
`getAccounts`, `getBalance` or `getTanMedia` returns. A complete balance of the account extension states the
|
|
503
|
+
`productName`.
|
|
504
|
+
- An account of the user parameter data whose national account leaves out the bank code keeps its country code.
|
|
505
|
+
- `state` encodes the parameter data once, as the bank sent them, and bank text is decoded in bulk: both held up the
|
|
506
|
+
thread with large data.
|
|
507
|
+
- `FinTs3Client` extends no internal class, so that its declarations name no internal types.
|
|
508
|
+
|
|
509
|
+
### Added
|
|
510
|
+
|
|
511
|
+
- `FinTsClient.loginRefusal`, the refused login that keeps the client from sending the PIN, and
|
|
512
|
+
`clearLoginRefusal(pin)`, which lifts it with a PIN the user has entered anew; `FinTsLoginRefusedError`.
|
|
513
|
+
- `FinTsTanSetupError`, for a missing TAN method or medium.
|
|
514
|
+
- `Camt.parse`, which gives each statement of a camt document as a `CamtStatement` with its account.
|
|
515
|
+
- `close` aborts a request on its way, through the signal of `FinTsTransport.post`; `HttpTransport` stops it.
|
|
516
|
+
|
|
1
517
|
## 0.1.0
|
|
2
518
|
|
|
3
519
|
First release: a TypeScript port of the FinTS 3.0 client of the Dart package `fints`.
|
|
@@ -7,5 +523,7 @@ First release: a TypeScript port of the FinTS 3.0 client of the Dart package `fi
|
|
|
7
523
|
parameters; TAN method and medium selection, chipTAN flicker codes and photoTAN images.
|
|
8
524
|
- Bank parameter data, customer system ID and the chosen TAN method in an exportable state string, in the layout of the
|
|
9
525
|
Dart package.
|
|
10
|
-
- A client never sends its PIN again once the bank has refused a login
|
|
526
|
+
- A client never sends its PIN again once the bank has refused a login, but where the bank names a reason the client
|
|
527
|
+
takes care of in the same call: another TAN method (3920, or 9075 after the one-step method) or a new customer system
|
|
528
|
+
ID (9391).
|
|
11
529
|
- Runs wherever `fetch`, Web Crypto and `TextDecoder` are available; no runtime dependencies.
|