@coderoftime/fints 0.1.0 → 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 (272) hide show
  1. package/CHANGELOG.md +142 -1
  2. package/README.md +127 -37
  3. package/dist/client.d.ts +48 -0
  4. package/dist/client.d.ts.map +1 -0
  5. package/dist/client.js +199 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/core/account.d.ts +35 -7
  8. package/dist/core/account.d.ts.map +1 -1
  9. package/dist/core/account.js +84 -13
  10. package/dist/core/account.js.map +1 -1
  11. package/dist/core/amount.d.ts +2 -1
  12. package/dist/core/amount.d.ts.map +1 -1
  13. package/dist/core/amount.js +4 -1
  14. package/dist/core/amount.js.map +1 -1
  15. package/dist/core/balance.d.ts +1 -0
  16. package/dist/core/balance.d.ts.map +1 -1
  17. package/dist/core/balance.js +6 -5
  18. package/dist/core/balance.js.map +1 -1
  19. package/dist/core/bank-info.d.ts +1 -1
  20. package/dist/core/bank-info.js +1 -1
  21. package/dist/core/client.d.ts +50 -15
  22. package/dist/core/client.d.ts.map +1 -1
  23. package/dist/core/config.d.ts +28 -16
  24. package/dist/core/config.d.ts.map +1 -1
  25. package/dist/core/config.js +66 -26
  26. package/dist/core/config.js.map +1 -1
  27. package/dist/core/errors.d.ts +85 -23
  28. package/dist/core/errors.d.ts.map +1 -1
  29. package/dist/core/errors.js +112 -47
  30. package/dist/core/errors.js.map +1 -1
  31. package/dist/core/feedback.d.ts +4 -1
  32. package/dist/core/feedback.d.ts.map +1 -1
  33. package/dist/core/feedback.js +4 -1
  34. package/dist/core/feedback.js.map +1 -1
  35. package/dist/core/transaction.d.ts +6 -1
  36. package/dist/core/transaction.d.ts.map +1 -1
  37. package/dist/core/transaction.js +9 -4
  38. package/dist/core/transaction.js.map +1 -1
  39. package/dist/core/transport.d.ts +33 -6
  40. package/dist/core/transport.d.ts.map +1 -1
  41. package/dist/core/transport.js +77 -20
  42. package/dist/core/transport.js.map +1 -1
  43. package/dist/formats/camt.d.ts +24 -4
  44. package/dist/formats/camt.d.ts.map +1 -1
  45. package/dist/formats/camt.js +124 -41
  46. package/dist/formats/camt.js.map +1 -1
  47. package/dist/formats/mt940.d.ts +15 -3
  48. package/dist/formats/mt940.d.ts.map +1 -1
  49. package/dist/formats/mt940.js +161 -82
  50. package/dist/formats/mt940.js.map +1 -1
  51. package/dist/formats/readers.d.ts +6 -2
  52. package/dist/formats/readers.d.ts.map +1 -1
  53. package/dist/formats/readers.js +24 -29
  54. package/dist/formats/readers.js.map +1 -1
  55. package/dist/formats/record-budget.d.ts +7 -0
  56. package/dist/formats/record-budget.d.ts.map +1 -0
  57. package/dist/formats/record-budget.js +17 -0
  58. package/dist/formats/record-budget.js.map +1 -0
  59. package/dist/formats/sepa-purpose.d.ts +6 -0
  60. package/dist/formats/sepa-purpose.d.ts.map +1 -1
  61. package/dist/formats/sepa-purpose.js +23 -2
  62. package/dist/formats/sepa-purpose.js.map +1 -1
  63. package/dist/index.d.ts +3 -3
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +2 -2
  66. package/dist/index.js.map +1 -1
  67. package/dist/session/app-approval.d.ts +11 -5
  68. package/dist/session/app-approval.d.ts.map +1 -1
  69. package/dist/session/app-approval.js +23 -12
  70. package/dist/session/app-approval.js.map +1 -1
  71. package/dist/session/dialog-runner.d.ts +7 -10
  72. package/dist/session/dialog-runner.d.ts.map +1 -1
  73. package/dist/session/dialog-runner.js +15 -16
  74. package/dist/session/dialog-runner.js.map +1 -1
  75. package/dist/session/login-guard.d.ts +54 -49
  76. package/dist/session/login-guard.d.ts.map +1 -1
  77. package/dist/session/login-guard.js +156 -84
  78. package/dist/session/login-guard.js.map +1 -1
  79. package/dist/session/sepa-accounts.d.ts +20 -14
  80. package/dist/session/sepa-accounts.d.ts.map +1 -1
  81. package/dist/session/sepa-accounts.js +62 -46
  82. package/dist/session/sepa-accounts.js.map +1 -1
  83. package/dist/session/session-setup.d.ts +33 -25
  84. package/dist/session/session-setup.d.ts.map +1 -1
  85. package/dist/session/session-setup.js +87 -65
  86. package/dist/session/session-setup.js.map +1 -1
  87. package/dist/session/session-state.d.ts +9 -6
  88. package/dist/session/session-state.d.ts.map +1 -1
  89. package/dist/session/session-state.js +52 -17
  90. package/dist/session/session-state.js.map +1 -1
  91. package/dist/session/signed-dialog.d.ts +77 -0
  92. package/dist/session/signed-dialog.d.ts.map +1 -0
  93. package/dist/session/signed-dialog.js +170 -0
  94. package/dist/session/signed-dialog.js.map +1 -0
  95. package/dist/session/tan-selection.d.ts +26 -18
  96. package/dist/session/tan-selection.d.ts.map +1 -1
  97. package/dist/session/tan-selection.js +44 -33
  98. package/dist/session/tan-selection.js.map +1 -1
  99. package/dist/session/user-prompts.d.ts +8 -4
  100. package/dist/session/user-prompts.d.ts.map +1 -1
  101. package/dist/session/user-prompts.js +34 -14
  102. package/dist/session/user-prompts.js.map +1 -1
  103. package/dist/tan/challenge.d.ts +34 -13
  104. package/dist/tan/challenge.d.ts.map +1 -1
  105. package/dist/tan/challenge.js +25 -26
  106. package/dist/tan/challenge.js.map +1 -1
  107. package/dist/tan/flicker.d.ts +7 -1
  108. package/dist/tan/flicker.d.ts.map +1 -1
  109. package/dist/tan/flicker.js +40 -6
  110. package/dist/tan/flicker.js.map +1 -1
  111. package/dist/tan/tan-image.d.ts +3 -2
  112. package/dist/tan/tan-image.d.ts.map +1 -1
  113. package/dist/tan/tan-image.js +7 -5
  114. package/dist/tan/tan-image.js.map +1 -1
  115. package/dist/tan/tan-models.d.ts +5 -1
  116. package/dist/tan/tan-models.d.ts.map +1 -1
  117. package/dist/tan/tan-models.js +10 -5
  118. package/dist/tan/tan-models.js.map +1 -1
  119. package/dist/util/async.d.ts +0 -2
  120. package/dist/util/async.d.ts.map +1 -1
  121. package/dist/util/async.js +0 -4
  122. package/dist/util/async.js.map +1 -1
  123. package/dist/util/bytes.d.ts +2 -3
  124. package/dist/util/bytes.d.ts.map +1 -1
  125. package/dist/util/bytes.js +12 -20
  126. package/dist/util/bytes.js.map +1 -1
  127. package/dist/util/call-context.d.ts.map +1 -1
  128. package/dist/util/call-context.js +3 -2
  129. package/dist/util/call-context.js.map +1 -1
  130. package/dist/util/dates.d.ts +9 -16
  131. package/dist/util/dates.d.ts.map +1 -1
  132. package/dist/util/dates.js +39 -19
  133. package/dist/util/dates.js.map +1 -1
  134. package/dist/util/errors.d.ts +9 -1
  135. package/dist/util/errors.d.ts.map +1 -1
  136. package/dist/util/errors.js +12 -3
  137. package/dist/util/errors.js.map +1 -1
  138. package/dist/util/json.d.ts +4 -0
  139. package/dist/util/json.d.ts.map +1 -1
  140. package/dist/util/json.js +18 -0
  141. package/dist/util/json.js.map +1 -1
  142. package/dist/util/text.d.ts +21 -4
  143. package/dist/util/text.d.ts.map +1 -1
  144. package/dist/util/text.js +42 -13
  145. package/dist/util/text.js.map +1 -1
  146. package/dist/util/xml.d.ts +4 -3
  147. package/dist/util/xml.d.ts.map +1 -1
  148. package/dist/util/xml.js +37 -26
  149. package/dist/util/xml.js.map +1 -1
  150. package/dist/v3/account-extension.d.ts.map +1 -1
  151. package/dist/v3/account-extension.js +7 -10
  152. package/dist/v3/account-extension.js.map +1 -1
  153. package/dist/v3/bank-connection.d.ts +34 -0
  154. package/dist/v3/bank-connection.d.ts.map +1 -0
  155. package/dist/v3/bank-connection.js +58 -0
  156. package/dist/v3/bank-connection.js.map +1 -0
  157. package/dist/v3/dialog.d.ts +80 -46
  158. package/dist/v3/dialog.d.ts.map +1 -1
  159. package/dist/v3/dialog.js +162 -59
  160. package/dist/v3/dialog.js.map +1 -1
  161. package/dist/v3/message.d.ts +17 -4
  162. package/dist/v3/message.d.ts.map +1 -1
  163. package/dist/v3/message.js +62 -18
  164. package/dist/v3/message.js.map +1 -1
  165. package/dist/v3/parameter-store.d.ts +75 -0
  166. package/dist/v3/parameter-store.d.ts.map +1 -0
  167. package/dist/v3/parameter-store.js +143 -0
  168. package/dist/v3/parameter-store.js.map +1 -0
  169. package/dist/v3/parameters.d.ts +38 -12
  170. package/dist/v3/parameters.d.ts.map +1 -1
  171. package/dist/v3/parameters.js +91 -37
  172. package/dist/v3/parameters.js.map +1 -1
  173. package/dist/v3/protocol.d.ts +43 -50
  174. package/dist/v3/protocol.d.ts.map +1 -1
  175. package/dist/v3/protocol.js +58 -208
  176. package/dist/v3/protocol.js.map +1 -1
  177. package/dist/v3/queries.d.ts +51 -0
  178. package/dist/v3/queries.d.ts.map +1 -0
  179. package/dist/v3/queries.js +120 -0
  180. package/dist/v3/queries.js.map +1 -0
  181. package/dist/v3/segments.d.ts +29 -12
  182. package/dist/v3/segments.d.ts.map +1 -1
  183. package/dist/v3/segments.js +65 -23
  184. package/dist/v3/segments.js.map +1 -1
  185. package/dist/v3/syntax.d.ts +65 -14
  186. package/dist/v3/syntax.d.ts.map +1 -1
  187. package/dist/v3/syntax.js +167 -101
  188. package/dist/v3/syntax.js.map +1 -1
  189. package/package.json +10 -6
  190. package/src/client.ts +252 -0
  191. package/src/core/account.ts +86 -13
  192. package/src/core/amount.ts +3 -1
  193. package/src/core/balance.ts +6 -5
  194. package/src/core/bank-info.ts +1 -1
  195. package/src/core/client.ts +52 -15
  196. package/src/core/config.ts +69 -28
  197. package/src/core/errors.ts +122 -48
  198. package/src/core/feedback.ts +4 -1
  199. package/src/core/transaction.ts +9 -4
  200. package/src/core/transport.ts +98 -23
  201. package/src/formats/camt.ts +136 -39
  202. package/src/formats/mt940.ts +167 -81
  203. package/src/formats/readers.ts +24 -31
  204. package/src/formats/record-budget.ts +18 -0
  205. package/src/formats/sepa-purpose.ts +21 -2
  206. package/src/index.ts +4 -2
  207. package/src/session/app-approval.ts +51 -38
  208. package/src/session/dialog-runner.ts +31 -28
  209. package/src/session/login-guard.ts +174 -88
  210. package/src/session/sepa-accounts.ts +63 -45
  211. package/src/session/session-setup.ts +90 -71
  212. package/src/session/session-state.ts +56 -22
  213. package/src/session/signed-dialog.ts +192 -0
  214. package/src/session/tan-selection.ts +50 -39
  215. package/src/session/user-prompts.ts +35 -16
  216. package/src/tan/challenge.ts +40 -31
  217. package/src/tan/flicker.ts +44 -6
  218. package/src/tan/tan-image.ts +7 -5
  219. package/src/tan/tan-models.ts +10 -5
  220. package/src/util/async.ts +0 -5
  221. package/src/util/bytes.ts +13 -19
  222. package/src/util/call-context.ts +3 -2
  223. package/src/util/dates.ts +41 -24
  224. package/src/util/errors.ts +14 -3
  225. package/src/util/json.ts +16 -0
  226. package/src/util/text.ts +42 -12
  227. package/src/util/xml.ts +37 -26
  228. package/src/v3/account-extension.ts +7 -12
  229. package/src/v3/bank-connection.ts +67 -0
  230. package/src/v3/dialog.ts +175 -91
  231. package/src/v3/message.ts +69 -17
  232. package/src/v3/parameter-store.ts +160 -0
  233. package/src/v3/parameters.ts +110 -37
  234. package/src/v3/protocol.ts +70 -253
  235. package/src/v3/queries.ts +190 -0
  236. package/src/v3/segments.ts +65 -22
  237. package/src/v3/syntax.ts +153 -91
  238. package/dist/session/bank-connection.d.ts +0 -28
  239. package/dist/session/bank-connection.d.ts.map +0 -1
  240. package/dist/session/bank-connection.js +0 -48
  241. package/dist/session/bank-connection.js.map +0 -1
  242. package/dist/session/parameter-data.d.ts +0 -83
  243. package/dist/session/parameter-data.d.ts.map +0 -1
  244. package/dist/session/parameter-data.js +0 -68
  245. package/dist/session/parameter-data.js.map +0 -1
  246. package/dist/session/pin-tan-client.d.ts +0 -54
  247. package/dist/session/pin-tan-client.d.ts.map +0 -1
  248. package/dist/session/pin-tan-client.js +0 -153
  249. package/dist/session/pin-tan-client.js.map +0 -1
  250. package/dist/session/pin-tan-dialog.d.ts +0 -71
  251. package/dist/session/pin-tan-dialog.d.ts.map +0 -1
  252. package/dist/session/pin-tan-dialog.js +0 -124
  253. package/dist/session/pin-tan-dialog.js.map +0 -1
  254. package/dist/session/protocol.d.ts +0 -209
  255. package/dist/session/protocol.d.ts.map +0 -1
  256. package/dist/session/protocol.js +0 -75
  257. package/dist/session/protocol.js.map +0 -1
  258. package/dist/session/response-handler.d.ts +0 -48
  259. package/dist/session/response-handler.d.ts.map +0 -1
  260. package/dist/session/response-handler.js +0 -121
  261. package/dist/session/response-handler.js.map +0 -1
  262. package/dist/v3/client.d.ts +0 -24
  263. package/dist/v3/client.d.ts.map +0 -1
  264. package/dist/v3/client.js +0 -16
  265. package/dist/v3/client.js.map +0 -1
  266. package/src/session/bank-connection.ts +0 -51
  267. package/src/session/parameter-data.ts +0 -137
  268. package/src/session/pin-tan-client.ts +0 -186
  269. package/src/session/pin-tan-dialog.ts +0 -160
  270. package/src/session/protocol.ts +0 -311
  271. package/src/session/response-handler.ts +0 -130
  272. package/src/v3/client.ts +0 -29
@@ -1,109 +1,181 @@
1
- import { FinTsBankError, FinTsLoginDataChangedError, FinTsPinError, FinTsTanError } from '../core/errors.js';
1
+ import { clientClosedError, FinTsLoginDataChangedError, FinTsLoginRefusedError, FinTsPinError, loginRefusalFor, } from '../core/errors.js';
2
2
  import { allowedTanMethodsIn, FeedbackCodes, hasCode } from '../core/feedback.js';
3
3
  /**
4
- * Keeps a retrying app from locking the user's access: once the bank has refused a login, the client does not send the
5
- * PIN again.
6
- *
7
- * Banks lock the access after a few failed attempts, and a return code does not always tell whether the PIN was the
8
- * reason. So `judge` counts as a refused login:
9
- * - a rejected PIN, wherever the bank reports it;
10
- * - any other error in the answer to a login, unless the login carries an order and the bank keeps the dialog open:
11
- * then the error concerns the order.
12
- *
13
- * Errors in the answer to an order or an approval are no refusal, such as a wrong TAN at login: the bank checks the PIN
14
- * before it asks for the approval. New login data (return code 3072) end the old ones for good (`refuse`).
4
+ * Logins in a row whose answer the client could not read, after which it sends the PIN no more: one may be a glitch of
5
+ * the connection, but with two the client would not learn of a wrong PIN before the bank locks the access.
6
+ */
7
+ const maxUnreadLogins = 2;
8
+ /**
9
+ * Holds the PIN and hands it out only while no login is refused (`pin`), so that a retrying app cannot lock the user's
10
+ * access. `FinTsLoginRefusedError` tells which logins count as refused; `judge` decides it for each answer.
15
11
  *
16
- * The guard fails closed: a refusal counts from the moment `judge` sees it, and only `pardon` lifts it, once the
17
- * session has taken care of a `RefusalReason` the refusal names (`remediableReasons`). The protocol calls `check`
18
- * before every message it signs with the PIN.
12
+ * A refusal counts at once and fails closed: only `remedied` lifts it, within the call that met it (`runCall`), once
13
+ * the session has taken care of a reason it names, each reason once per call, so that a call sends at most three
14
+ * logins the bank refuses. A refusal that outlasts the call is final, and the guard forgets the PIN; only a PIN the
15
+ * user enters anew lifts it (`replacePin`), unless it brings new login data.
19
16
  */
20
17
  export class LoginGuard {
21
- refusal;
22
- /** The TAN method of the refused login; `undefined` without a refusal, and for new login data. */
23
- refusedMethodValue;
24
- /** Throws the bank's refusal of an earlier login, so that the PIN is not sent again. */
18
+ // ECMAScript private, so that neither `util.inspect` nor `JSON.stringify` of the client reaches it.
19
+ #pin;
20
+ refusalValue;
21
+ /** The TAN method of the login `refusalValue` refused, which a restored refusal does not tell. */
22
+ refusedMethod;
23
+ /** Logins sent since the bank last took the PIN whose answer the client has not read. */
24
+ unreadLogins = 0;
25
+ /** The refusal of `maxUnreadLogins` unread logins, kept so that `check` throws the same error each time. */
26
+ unreadLoginsRefusal;
27
+ /** The reasons `remedied` has lifted a refusal for in the running call. */
28
+ pardonedReasons = new Set();
29
+ constructor(pin) {
30
+ this.#pin = pin;
31
+ }
32
+ /** The PIN to sign a message with; throws the refusal instead (`check`), and `FinTsStateError` once closed. */
33
+ get pin() {
34
+ this.check();
35
+ if (this.#pin === undefined)
36
+ throw clientClosedError();
37
+ return this.#pin;
38
+ }
39
+ /** Throws the refusal, if there is one. */
25
40
  check() {
26
- if (this.refusal !== undefined)
27
- throw this.refusal;
41
+ const refusal = this.refusal;
42
+ if (refusal !== undefined)
43
+ throw refusal;
28
44
  }
29
- /** Whether the guard holds a refusal. */
30
- get hasRefusal() {
31
- return this.refusal !== undefined;
45
+ /** The bank's refusal, else that of `maxUnreadLogins` unread logins; `undefined` while there is none. */
46
+ get refusal() {
47
+ if (this.refusalValue !== undefined || this.unreadLogins < maxUnreadLogins)
48
+ return this.refusalValue;
49
+ this.unreadLoginsRefusal ??= new FinTsLoginRefusedError([], `The answers to the last ${maxUnreadLogins} logins were lost or unreadable, and the bank may have counted them ` +
50
+ 'as failed attempts');
51
+ return this.unreadLoginsRefusal;
32
52
  }
33
- /** The TAN method the refused login was signed with; `undefined` where the guard holds no refusal of a login. */
34
- get refusedMethod() {
35
- return this.refusedMethodValue;
53
+ /** Counts a login signed with the PIN as unread until `judge` reads its answer. */
54
+ loginSent() {
55
+ this.unreadLogins++;
36
56
  }
37
57
  /**
38
- * Whether `error`, raised for the answer to a request of `kind` in a dialog signed with `method`, refuses the login;
39
- * records it if it does.
40
- *
41
- * `dialogOpen` tells whether the bank keeps the dialog open after its answer.
58
+ * Judges `error`, if the answer to a request of `kind` in a dialog signed with `method` has one: returns the refusal
59
+ * of the login it amounts to, and records it unless the guard holds one already. Any error refuses a login; after the
60
+ * login only one that refuses it itself, a rejected PIN or new login data, since the bank checked the PIN before.
42
61
  */
43
- judge(error, kind, dialogOpen, method) {
44
- const refused = error instanceof FinTsPinError || kind === 'login' || (kind === 'loginWithOrder' && !dialogOpen);
45
- if (refused && this.refusal === undefined) {
46
- this.refusal = error;
47
- this.refusedMethodValue = method;
62
+ judge(error, kind, method) {
63
+ const refused = error instanceof FinTsLoginRefusedError || (error !== undefined && kind === 'login');
64
+ if (kind === 'login')
65
+ this.unreadLogins = refused ? Math.max(0, this.unreadLogins - 1) : 0;
66
+ if (!refused)
67
+ return undefined;
68
+ const refusal = loginRefusalFor(error.feedback);
69
+ if (this.refusalValue === undefined) {
70
+ this.refusalValue = refusal;
71
+ this.refusedMethod = method;
48
72
  }
49
- return refused;
50
- }
51
- /** Records `error` as the reason the client logs in no more, unless it holds a refusal already. */
52
- refuse(error) {
53
- this.refusal ??= error;
73
+ return refusal;
54
74
  }
55
- /**
56
- * Runs `lookup`, which only completes data, such as the SEPA account list; `undefined` where the bank rejects it, so
57
- * that the caller carries on without it.
58
- *
59
- * A refused login is thrown, and so is a wrong TAN, which the user must hear of. An aborted dialog counts as a
60
- * rejection: banks end the dialog along with many.
61
- */
62
- async tryLookUp(lookup) {
75
+ /** Runs `call`, one call of the client; a refusal that outlasts it is final, and the next call remedies anew. */
76
+ async runCall(call) {
63
77
  try {
64
- return await lookup();
78
+ return await call();
65
79
  }
66
- catch (error) {
67
- if (!(error instanceof FinTsBankError) || this.isRefusal(error) || error instanceof FinTsTanError)
68
- throw error;
69
- return undefined;
80
+ finally {
81
+ this.pardonedReasons.clear();
82
+ this.forgetPinIfRefused();
70
83
  }
71
84
  }
72
85
  /**
73
- * The reasons the session can take care of in `error`: 3920 without the TAN method of the refused login, 9075 after
74
- * the one-step method, and 9391. Empty if `error` is not the refusal the guard holds, rejects the PIN, or brings new
75
- * login data.
76
- *
77
- * Only the return codes of the refusal itself count: TAN methods listed earlier say nothing about this login.
86
+ * Runs `attempt`, which may log in, and runs it once more each time `remedy` takes care of a reason the refusal it
87
+ * failed with names; `remedy` gets the reason and the TAN method of the refused login, and returns whether it could.
78
88
  */
79
- remediableReasons(error) {
80
- const method = this.refusedMethodValue;
81
- if (!this.isRefusal(error) ||
82
- method === undefined ||
83
- error instanceof FinTsPinError ||
84
- error instanceof FinTsLoginDataChangedError) {
85
- return [];
86
- }
87
- const feedback = error.feedback;
88
- const allowed = allowedTanMethodsIn(feedback);
89
- const reasons = [];
90
- if ((allowed.length > 0 && !allowed.includes(method.securityFunction)) ||
91
- (method.isOneStep && hasCode(feedback, FeedbackCodes.scaRequired))) {
92
- reasons.push('tanMethodNotAllowed');
89
+ async remedied(attempt, remedy) {
90
+ // A refusal of an earlier call stops the attempt before it sends the PIN; there is nothing to remedy.
91
+ if (this.refusal !== undefined)
92
+ return attempt();
93
+ for (;;) {
94
+ try {
95
+ return await attempt();
96
+ }
97
+ catch (error) {
98
+ const refusal = this.refusalValue;
99
+ const rejected = this.refusedMethod;
100
+ // Only the bank's refusal the guard holds names reasons; any other error, a second refusal too, fails the call.
101
+ if (refusal === undefined || error !== refusal || rejected === undefined)
102
+ throw error;
103
+ const reason = remediableReasons(refusal, rejected).find((r) => !this.pardonedReasons.has(r));
104
+ if (reason === undefined || !(await remedy(reason, rejected)))
105
+ throw error;
106
+ this.pardonedReasons.add(reason);
107
+ // A closed client keeps the refusal.
108
+ if (this.#pin !== undefined)
109
+ this.liftRefusal();
110
+ }
93
111
  }
94
- if (hasCode(feedback, FeedbackCodes.newSystemIdRequired))
95
- reasons.push('systemIdRejected');
96
- return reasons;
97
112
  }
98
- /** Lifts `refusal` once the session has taken care of its reason, so that the next login may send the PIN. */
99
- pardon(refusal) {
100
- if (!this.isRefusal(refusal))
101
- return;
102
- this.refusal = undefined;
103
- this.refusedMethodValue = undefined;
113
+ /**
114
+ * Signs with `pin` from now on, a PIN the user has entered anew and the protocol can send, and lifts the refusal.
115
+ * Throws the refusal instead where it brings new login data, which end the old ones for good.
116
+ */
117
+ replacePin(pin) {
118
+ if (this.refusalValue instanceof FinTsLoginDataChangedError)
119
+ throw this.refusalValue;
120
+ this.#pin = pin;
121
+ this.liftRefusal();
122
+ this.unreadLogins = 0;
123
+ this.unreadLoginsRefusal = undefined;
124
+ }
125
+ /** Forgets the PIN; the client calls it once it is closed. */
126
+ close() {
127
+ this.#pin = undefined;
128
+ }
129
+ saveState() {
130
+ return { refusal: this.refusalValue?.feedback, unreadLogins: this.unreadLogins };
104
131
  }
105
- isRefusal(error) {
106
- return error === this.refusal;
132
+ /** Restores what `saveState` returned; a restored refusal is final. */
133
+ restoreState(saved) {
134
+ if (saved.refusal !== undefined)
135
+ this.refusalValue = loginRefusalFor(saved.refusal);
136
+ this.unreadLogins = Math.max(0, saved.unreadLogins);
137
+ this.forgetPinIfRefused();
138
+ }
139
+ liftRefusal() {
140
+ this.refusalValue = undefined;
141
+ this.refusedMethod = undefined;
142
+ }
143
+ forgetPinIfRefused() {
144
+ if (this.refusal !== undefined)
145
+ this.#pin = undefined;
107
146
  }
108
147
  }
148
+ /**
149
+ * The reasons `refusal`, of a login signed with `method`, names that the session can take care of: a TAN method the
150
+ * refusal names as not allowed (`refusesMethod`), and 9391. None for a rejected PIN or new login data.
151
+ */
152
+ function remediableReasons(refusal, method) {
153
+ if (refusal instanceof FinTsPinError || refusal instanceof FinTsLoginDataChangedError)
154
+ return [];
155
+ const reasons = [];
156
+ if (refusesMethod(refusal.feedback, method))
157
+ reasons.push('tanMethodNotAllowed');
158
+ if (hasCode(refusal.feedback, FeedbackCodes.newSystemIdRequired))
159
+ reasons.push('systemIdRejected');
160
+ return reasons;
161
+ }
162
+ /** Error codes that only say that the message failed, not why: 9050 (the message contains errors) and 9800. */
163
+ const unspecificErrors = new Set(['9050', FeedbackCodes.dialogAborted]);
164
+ /**
165
+ * Whether `feedback`, which refuses a login signed with `method`, names the method as the reason: a 3920 that lists the
166
+ * methods the user may use without it, or 9075 after the one-step method.
167
+ *
168
+ * Only the return codes of the refusal itself count: TAN methods listed earlier say nothing about this login. Banks
169
+ * list two-step methods only, so a 3920 always leaves the one-step method out, also where the login succeeds. After
170
+ * the one-step method a 3920 counts only where the bank names no other error than an unspecific one: any other, such
171
+ * as "Anmeldung fehlgeschlagen", may be about the PIN.
172
+ */
173
+ function refusesMethod(feedback, method) {
174
+ if (method.isOneStep && hasCode(feedback, FeedbackCodes.scaRequired))
175
+ return true;
176
+ const allowed = allowedTanMethodsIn(feedback);
177
+ if (allowed.length === 0 || allowed.includes(method.securityFunction))
178
+ return false;
179
+ return !method.isOneStep || feedback.every((f) => !f.isError || unspecificErrors.has(f.code));
180
+ }
109
181
  //# sourceMappingURL=login-guard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"login-guard.js","sourceRoot":"","sources":["../../src/session/login-guard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"login-guard.js","sourceRoot":"","sources":["../../src/session/login-guard.ts"],"names":[],"mappings":"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"}
@@ -1,32 +1,38 @@
1
- import type { Account } from '../core/account.js';
1
+ import { Account } from '../core/account.js';
2
+ import type { ParameterStore } from '../v3/parameter-store.js';
2
3
  import type { DialogRunner } from './dialog-runner.js';
3
- import type { LoginGuard } from './login-guard.js';
4
- import type { BankResponse, PinTanProtocol } from './protocol.js';
5
4
  import type { SessionState } from './session-state.js';
6
5
  /**
7
6
  * IBAN and BIC of the user's accounts, from the bank's SEPA account list where the user parameter data lack them
8
- * (Formals F.3.4).
7
+ * (Formals F.3.4), and the accounts the app passes completed from both.
9
8
  *
10
9
  * The list is read once per version of the user parameter data and kept in the saved state. Under version 0, which
11
- * holds for one dialog only (Formals E.2), without user parameter data, or where the bank rejects the list, it is kept
12
- * for this client only. Where the bank ends the dialog in answer to the list, the next call asks once more.
10
+ * holds for one dialog only (Formals E.2), without user parameter data, or where the bank rejects the list, also by
11
+ * ending the dialog, or names no account in it, it is kept for this client only: an empty list completes nothing, and
12
+ * saved it would outlast a fault of a single answer until the bank changes its user parameter data.
13
13
  */
14
- export declare class SepaAccounts<R extends BankResponse, O> {
15
- private readonly protocol;
14
+ export declare class SepaAccounts {
15
+ private readonly parameters;
16
16
  private readonly state;
17
17
  private readonly dialogs;
18
- private readonly guard;
19
18
  /**
20
19
  * The list this client keeps unsaved, with the version of the user parameter data it was read under; empty where the
21
- * bank rejected it.
20
+ * bank rejected it or named no account.
22
21
  */
23
22
  private unsaved;
24
- /** Whether a call already went on without the list because the bank ended the dialog in answer to it. */
25
- private abortSkipped;
26
- constructor(protocol: PinTanProtocol<R, O>, state: SessionState, dialogs: DialogRunner<R, O>, guard: LoginGuard);
23
+ constructor(parameters: ParameterStore, state: SessionState, dialogs: DialogRunner);
27
24
  /** The accounts of the user parameter data completed with IBAN and BIC, then the accounts only the list names. */
28
25
  completedAccounts(): Promise<Account[]>;
29
- /** `account` with IBAN and BIC filled in from the list. */
26
+ /**
27
+ * `account` as the bank knows it: the one of `completedAccounts` it matches, with what the bank states of it first,
28
+ * so that an account the app has built itself, such as from an IBAN alone, goes out with the account number, the
29
+ * sub-account and the BIC the bank's orders take, and the currency of its statements. Where the bank names none it
30
+ * matches, only what identifies `account`, and its currency: the rest, such as the transactions it permits, only the
31
+ * bank can state.
32
+ *
33
+ * Throws `FinTsUnsupportedError` for such an account where the user parameter data list all permitted transactions:
34
+ * they permit nothing for an account they leave out, and the client cannot tell it from a mistyped one.
35
+ */
30
36
  complete(account: Account): Promise<Account>;
31
37
  /** The list, read in the session's dialog, whose start delivers the user parameter data it is cached for. */
32
38
  private list;
@@ -1 +1 @@
1
- {"version":3,"file":"sepa-accounts.d.ts","sourceRoot":"","sources":["../../src/session/sepa-accounts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;;;;GAOG;AACH,qBAAa,YAAY,CAAC,CAAC,SAAS,YAAY,EAAE,CAAC;IAW/C,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAbxB;;;OAGG;IACH,OAAO,CAAC,OAAO,CAA+E;IAE9F,yGAAyG;IACzG,OAAO,CAAC,YAAY,CAAS;gBAGV,QAAQ,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,EAC9B,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,EAC3B,KAAK,EAAE,UAAU;IAGpC,kHAAkH;IAC5G,iBAAiB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAS7C,2DAA2D;IACrD,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAKlD,6GAA6G;YAC/F,IAAI;CAwCnB"}
1
+ {"version":3,"file":"sepa-accounts.d.ts","sourceRoot":"","sources":["../../src/session/sepa-accounts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAgB,MAAM,oBAAoB,CAAC;AAE3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;;;;;GAQG;AACH,qBAAa,YAAY;IAQrB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAT1B;;;OAGG;IACH,OAAO,CAAC,OAAO,CAA+E;gBAG3E,UAAU,EAAE,cAAc,EAC1B,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,YAAY;IAGxC,kHAAkH;IAC5G,iBAAiB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAW7C;;;;;;;;;OASG;IACG,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IA2BlD,6GAA6G;YAC/F,IAAI;CA0BnB"}
@@ -1,49 +1,80 @@
1
- import { FinTsDialogAbortedError } from '../core/errors.js';
1
+ import { Account, AccountIndex } from '../core/account.js';
2
+ import { FinTsUnsupportedError, tryLookUp } from '../core/errors.js';
3
+ import { sepaAccountsQuery } from '../v3/queries.js';
2
4
  /**
3
5
  * IBAN and BIC of the user's accounts, from the bank's SEPA account list where the user parameter data lack them
4
- * (Formals F.3.4).
6
+ * (Formals F.3.4), and the accounts the app passes completed from both.
5
7
  *
6
8
  * The list is read once per version of the user parameter data and kept in the saved state. Under version 0, which
7
- * holds for one dialog only (Formals E.2), without user parameter data, or where the bank rejects the list, it is kept
8
- * for this client only. Where the bank ends the dialog in answer to the list, the next call asks once more.
9
+ * holds for one dialog only (Formals E.2), without user parameter data, or where the bank rejects the list, also by
10
+ * ending the dialog, or names no account in it, it is kept for this client only: an empty list completes nothing, and
11
+ * saved it would outlast a fault of a single answer until the bank changes its user parameter data.
9
12
  */
10
13
  export class SepaAccounts {
11
- protocol;
14
+ parameters;
12
15
  state;
13
16
  dialogs;
14
- guard;
15
17
  /**
16
18
  * The list this client keeps unsaved, with the version of the user parameter data it was read under; empty where the
17
- * bank rejected it.
19
+ * bank rejected it or named no account.
18
20
  */
19
21
  unsaved;
20
- /** Whether a call already went on without the list because the bank ended the dialog in answer to it. */
21
- abortSkipped = false;
22
- constructor(protocol, state, dialogs, guard) {
23
- this.protocol = protocol;
22
+ constructor(parameters, state, dialogs) {
23
+ this.parameters = parameters;
24
24
  this.state = state;
25
25
  this.dialogs = dialogs;
26
- this.guard = guard;
27
26
  }
28
27
  /** The accounts of the user parameter data completed with IBAN and BIC, then the accounts only the list names. */
29
28
  async completedAccounts() {
30
29
  const sepa = await this.list();
31
- const accounts = this.protocol.userParameters?.accounts ?? [];
30
+ const accounts = this.parameters.userParameters?.accounts ?? [];
31
+ const listed = new AccountIndex(sepa);
32
+ const known = new AccountIndex(accounts);
32
33
  return [
33
- ...accounts.map((account) => withSepaDetails(account, sepa)),
34
- ...sepa.filter((s) => !accounts.some((a) => s.matches(a))),
34
+ ...accounts.map((account) => withSepaDetails(account, listed.find(account))),
35
+ ...sepa.filter((s) => known.find(s) === undefined),
35
36
  ];
36
37
  }
37
- /** `account` with IBAN and BIC filled in from the list. */
38
+ /**
39
+ * `account` as the bank knows it: the one of `completedAccounts` it matches, with what the bank states of it first,
40
+ * so that an account the app has built itself, such as from an IBAN alone, goes out with the account number, the
41
+ * sub-account and the BIC the bank's orders take, and the currency of its statements. Where the bank names none it
42
+ * matches, only what identifies `account`, and its currency: the rest, such as the transactions it permits, only the
43
+ * bank can state.
44
+ *
45
+ * Throws `FinTsUnsupportedError` for such an account where the user parameter data list all permitted transactions:
46
+ * they permit nothing for an account they leave out, and the client cannot tell it from a mistyped one.
47
+ */
38
48
  async complete(account) {
39
- if (account.iban !== undefined && account.bic !== undefined)
40
- return account;
41
- return withSepaDetails(account, await this.list());
49
+ const known = (await this.completedAccounts()).find((a) => account.matches(a));
50
+ if (known !== undefined) {
51
+ // A sub-account belongs to the account number it comes with.
52
+ const national = known.accountNumber === undefined ? account : known;
53
+ return known.copyWith({
54
+ accountNumber: national.accountNumber,
55
+ subAccount: national.subAccount,
56
+ iban: known.iban ?? account.iban,
57
+ bic: known.bic ?? account.bic,
58
+ currency: known.currency ?? account.currency,
59
+ });
60
+ }
61
+ if (this.parameters.userParameters?.listsAllTransactions === true) {
62
+ throw new FinTsUnsupportedError("The bank does not name this account among the user's, and so permits nothing");
63
+ }
64
+ return new Account({
65
+ accountNumber: account.accountNumber,
66
+ subAccount: account.subAccount,
67
+ bankCode: account.bankCode,
68
+ countryCode: account.countryCode,
69
+ iban: account.iban,
70
+ bic: account.bic,
71
+ currency: account.currency,
72
+ });
42
73
  }
43
74
  /** The list, read in the session's dialog, whose start delivers the user parameter data it is cached for. */
44
75
  async list() {
45
76
  await this.dialogs.open();
46
- const upd = this.protocol.userParameters;
77
+ const upd = this.parameters.userParameters;
47
78
  if (upd !== undefined &&
48
79
  upd.accounts.length > 0 &&
49
80
  upd.accounts.every((a) => a.iban !== undefined && a.bic !== undefined)) {
@@ -55,29 +86,13 @@ export class SepaAccounts {
55
86
  return saved;
56
87
  if (this.unsaved !== undefined && this.unsaved.updVersion === updVersion)
57
88
  return this.unsaved.accounts;
58
- const query = this.protocol.sepaAccounts();
89
+ const query = sepaAccountsQuery(this.parameters);
59
90
  if (query === undefined)
60
91
  return [];
61
- // Where the bank rejects the list, the accounts stay as the user parameter data state them.
62
- const outcome = { aborted: false };
63
- const accounts = await this.guard.tryLookUp(async () => {
64
- try {
65
- return await this.dialogs.query(() => query);
66
- }
67
- catch (error) {
68
- if (error instanceof FinTsDialogAbortedError)
69
- outcome.aborted = true;
70
- throw error;
71
- }
72
- });
73
- if (outcome.aborted && !this.abortSkipped) {
74
- // The bank may have ended the dialog for a reason of its own, such as a timeout, so this call goes on without the
75
- // list and the next one asks again in its new dialog. Only once: banks also end the dialog when they reject the
76
- // list, and each time costs the next call a login.
77
- this.abortSkipped = true;
78
- return [];
79
- }
80
- if (accounts !== undefined && updVersion !== undefined && updVersion > 0) {
92
+ // Where the bank rejects the list, also by ending the dialog, the accounts stay as the user parameter data state
93
+ // them: asked again, a bank that ends the dialog in answer would cost each call a login.
94
+ const accounts = await tryLookUp(() => this.dialogs.query(() => query));
95
+ if (accounts !== undefined && accounts.length > 0 && updVersion !== undefined && updVersion > 0) {
81
96
  this.state.cacheSepaAccounts(accounts, updVersion);
82
97
  }
83
98
  else {
@@ -86,11 +101,12 @@ export class SepaAccounts {
86
101
  return accounts ?? [];
87
102
  }
88
103
  }
89
- function withSepaDetails(account, sepa) {
90
- const match = sepa.find((s) => account.matches(s));
91
- if (match === undefined)
92
- return account;
104
+ /**
105
+ * A copy of `account`, which shares no date with the user parameter data, with the IBAN and BIC of `match`, its entry
106
+ * in the SEPA account list, if any.
107
+ */
108
+ function withSepaDetails(account, match) {
93
109
  // A BIC of the list takes precedence over the one of the user parameter data (Formals E.3.1.1, "BIC").
94
- return account.copyWith({ iban: account.iban ?? match.iban, bic: match.bic ?? account.bic });
110
+ return account.copyWith({ iban: account.iban ?? match?.iban, bic: match?.bic ?? account.bic });
95
111
  }
96
112
  //# sourceMappingURL=sepa-accounts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sepa-accounts.js","sourceRoot":"","sources":["../../src/session/sepa-accounts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sepa-accounts.js","sourceRoot":"","sources":["../../src/session/sepa-accounts.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,7 @@
1
1
  import type { BankInfo } from '../core/bank-info.js';
2
- import type { TanMethod } from '../tan/tan-models.js';
3
- import type { LoginGuard } from './login-guard.js';
4
- import type { BankResponse, PinTanProtocol, ProtocolDialog } from './protocol.js';
5
- import type { ResponseHandler } from './response-handler.js';
2
+ import type { TanMedium, TanMethod } from '../tan/tan-models.js';
3
+ import type { FinTs3Protocol } from '../v3/protocol.js';
4
+ import { SignedDialog, type SessionParts } from './signed-dialog.js';
6
5
  import type { TanSelection } from './tan-selection.js';
7
6
  /**
8
7
  * What has to be settled before a login: the bank parameter data, the synchronization, and through `TanSelection` the
@@ -10,14 +9,11 @@ import type { TanSelection } from './tan-selection.js';
10
9
  *
11
10
  * Where the bank refuses a login for a reason the session can take care of, `remedied` does so and logs in again.
12
11
  */
13
- export declare class SessionSetup<R extends BankResponse, O> {
12
+ export declare class SessionSetup {
13
+ private readonly session;
14
14
  private readonly protocol;
15
- private readonly responses;
16
15
  private readonly tans;
17
- private readonly guard;
18
- /** Whether a synchronization dialog ran, so that a helpful one runs once only. */
19
- private synchronizationTried;
20
- constructor(protocol: PinTanProtocol<R, O>, responses: ResponseHandler<R>, tans: TanSelection<R, O>, guard: LoginGuard);
16
+ constructor(session: SessionParts, protocol: FinTs3Protocol, tans: TanSelection);
21
17
  /**
22
18
  * The bank's general information: from an anonymous dialog where the bank answers one, else from the synchronization.
23
19
  * No TAN method or medium is chosen for it.
@@ -25,21 +21,19 @@ export declare class SessionSetup<R extends BankResponse, O> {
25
21
  bankInfo(): Promise<BankInfo>;
26
22
  /** The TAN methods the bank allows for this user, which the synchronization reports. */
27
23
  methods(): Promise<TanMethod[]>;
28
- /** Settles what is still open: the bank parameter data, the synchronization, the TAN method and medium. */
29
- prepare(): Promise<void>;
30
- /** A new dialog signed with the TAN method and medium in use, once `prepare` has settled them. */
31
- newDialog(): Promise<ProtocolDialog<R, O>>;
32
24
  /**
33
- * Runs `attempt`, which may log in, and runs it once more for each reason of a refused login the session can take
34
- * care of, so that a bank that keeps refusing fails with its own error:
35
- *
36
- * | Refusal (`LoginGuard.remediableReasons`) | Remedy |
37
- * | --- | --- |
38
- * | 3920 without the method, or 9075 after the one-step method | another allowed method (`TanSelection.replace`) |
39
- * | 9391 | a new synchronization, which issues a customer system ID |
25
+ * Settles what is still open: the bank parameter data, the synchronization, the TAN method and medium. Returns the TAN
26
+ * media it looked up to choose the medium; `undefined` where it looked up none, or the bank listed none.
40
27
  */
28
+ prepare(): Promise<TanMedium[] | undefined>;
29
+ /** A new dialog signed with the TAN method and medium in use, once `prepare` has settled them. */
30
+ newDialog(): Promise<SignedDialog>;
31
+ /** Runs `attempt`, which may log in, once more after each refused login `remedy` takes care of. */
41
32
  remedied<T>(attempt: () => Promise<T>): Promise<T>;
42
- /** Takes care of `reason`, given for refusing a login signed with `rejected`; returns whether it could. */
33
+ /**
34
+ * Takes care of `reason`, given for refusing a login signed with `rejected`, with another TAN method or a new
35
+ * synchronization; returns whether it could.
36
+ */
43
37
  private remedy;
44
38
  /**
45
39
  * Loads the bank parameter data if they are missing, then synchronizes if that is due.
@@ -52,11 +46,25 @@ export declare class SessionSetup<R extends BankResponse, O> {
52
46
  */
53
47
  private loadParameters;
54
48
  /**
55
- * Asks for the bank parameter data without logging in. A bank that does not answer anonymously is no error, but a
56
- * failed connection is: the synchronization would only wait for the same server again.
49
+ * Asks for the bank parameter data without logging in, keeps them where there are none from a dialog signed with the
50
+ * PIN (`ParameterStore.keepAnonymous`), and passes the bank's messages on: all an anonymous dialog tells, since the
51
+ * TAN methods it lists are not those of a user. A bank that does not answer anonymously is no error, but a failed
52
+ * connection is: the synchronization would only wait for the same server again.
57
53
  */
58
54
  private fetchBankParametersAnonymously;
59
- /** Runs the synchronization dialog where it is due (`TanSelection.synchronizationDialog`). */
55
+ /**
56
+ * Asks for the bank parameter data in an anonymous dialog that announces strong customer authentication; a bank that
57
+ * rejects the announcement, with a return code or by failing on it, is asked again without it.
58
+ *
59
+ * A timeout or a broken connection is not a reason to ask again: it would only double the wait.
60
+ */
61
+ private requestBankParametersAnonymously;
62
+ private anonymousDialog;
63
+ /**
64
+ * Runs the synchronization, a login in a dialog of its own, while there is no customer system ID, without which no
65
+ * regular dialog starts. It runs before the TAN method and medium are settled (`TanSelection.synchronizationDialog`
66
+ * tells which method signs it).
67
+ */
60
68
  private synchronizeIfDue;
61
69
  /**
62
70
  * The TAN media of the method in use; `undefined` if the bank does not list them or rejects the list, after which the