fints-lib 0.7.0 → 0.9.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.
@@ -3,6 +3,9 @@ import { Dialog, DialogConfig } from "./dialog";
3
3
  import { Request } from "./request";
4
4
  import { ConnectionConfig } from "./http-connection";
5
5
  import { Segment } from "./segments";
6
+ import { DecoupledTanConfig, DecoupledTanStatusCallback } from "./decoupled-tan";
7
+ import { TanRequiredError } from "./errors/tan-required-error";
8
+ import { Response } from "./response";
6
9
  /**
7
10
  * Set of options needed to construct a `PinTanClient`.
8
11
  */
@@ -31,6 +34,10 @@ export interface PinTanClientConfig extends Partial<ConnectionConfig> {
31
34
  * If set to `true`, will log all requests performed and responses received.
32
35
  */
33
36
  debug?: boolean;
37
+ /**
38
+ * Configuration for decoupled TAN (asynchronous authentication)
39
+ */
40
+ decoupledTanConfig?: DecoupledTanConfig;
34
41
  }
35
42
  export declare class PinTanClient extends Client {
36
43
  /**
@@ -44,4 +51,40 @@ export declare class PinTanClient extends Client {
44
51
  constructor(config: PinTanClientConfig);
45
52
  createDialog(dialogConfig?: DialogConfig): Dialog;
46
53
  createRequest(dialog: Dialog, segments: Segment<any>[], tan?: string): Request;
54
+ /**
55
+ * Handle a decoupled TAN challenge with automatic polling
56
+ *
57
+ * High-level method for handling decoupled TAN authentication flow.
58
+ * Automatically manages the polling lifecycle and provides status updates
59
+ * through an optional callback.
60
+ *
61
+ * **Usage Pattern:**
62
+ * ```typescript
63
+ * try {
64
+ * await client.creditTransfer(account, transfer);
65
+ * } catch (error) {
66
+ * if (error instanceof TanRequiredError && error.isDecoupledTan()) {
67
+ * await client.handleDecoupledTanChallenge(error, (status) => {
68
+ * console.log(`State: ${status.state}, Requests: ${status.statusRequestCount}`);
69
+ * });
70
+ * }
71
+ * }
72
+ * ```
73
+ *
74
+ * **FinTS Specification:**
75
+ * - Implements tanProcess="2" polling per FinTS 3.0 PINTAN
76
+ * - Uses HKTAN segment for status checks
77
+ * - Respects server timing from HITANS segment
78
+ *
79
+ * @param error The TanRequiredError that contains the challenge information
80
+ * @param statusCallback Optional callback for status updates during polling
81
+ * @return The final response after confirmation
82
+ *
83
+ * @throws {Error} If the error is not a decoupled TAN challenge
84
+ * @throws {DecoupledTanError} If polling fails (timeout, cancellation, etc.)
85
+ *
86
+ * @see Dialog.handleDecoupledTan for lower-level control
87
+ * @see https://www.hbci-zka.de/ for FinTS specification
88
+ */
89
+ handleDecoupledTanChallenge(error: TanRequiredError, statusCallback?: DecoupledTanStatusCallback): Promise<Response>;
47
90
  }
@@ -1,4 +1,13 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
12
  exports.PinTanClient = void 0;
4
13
  const client_1 = require("./client");
@@ -21,15 +30,60 @@ class PinTanClient extends client_1.Client {
21
30
  this.connection = new http_connection_1.HttpConnection(connectionConfig);
22
31
  }
23
32
  createDialog(dialogConfig) {
24
- const { blz, name, pin, productId = constants_1.PRODUCT_NAME } = this.config;
33
+ const { blz, name, pin, productId = constants_1.PRODUCT_NAME, decoupledTanConfig } = this.config;
25
34
  const { connection } = this;
26
- return new dialog_1.Dialog(dialogConfig ? dialogConfig : { blz, name, pin, systemId: "0", productId }, connection);
35
+ return new dialog_1.Dialog(dialogConfig ? dialogConfig : { blz, name, pin, systemId: "0", productId }, connection, decoupledTanConfig);
27
36
  }
28
37
  createRequest(dialog, segments, tan) {
29
38
  const { blz, name, pin } = this.config;
30
39
  const { systemId, dialogId, msgNo, tanMethods } = dialog;
31
40
  return new request_1.Request({ blz, name, pin, systemId, dialogId, msgNo, segments, tanMethods, tan });
32
41
  }
42
+ /**
43
+ * Handle a decoupled TAN challenge with automatic polling
44
+ *
45
+ * High-level method for handling decoupled TAN authentication flow.
46
+ * Automatically manages the polling lifecycle and provides status updates
47
+ * through an optional callback.
48
+ *
49
+ * **Usage Pattern:**
50
+ * ```typescript
51
+ * try {
52
+ * await client.creditTransfer(account, transfer);
53
+ * } catch (error) {
54
+ * if (error instanceof TanRequiredError && error.isDecoupledTan()) {
55
+ * await client.handleDecoupledTanChallenge(error, (status) => {
56
+ * console.log(`State: ${status.state}, Requests: ${status.statusRequestCount}`);
57
+ * });
58
+ * }
59
+ * }
60
+ * ```
61
+ *
62
+ * **FinTS Specification:**
63
+ * - Implements tanProcess="2" polling per FinTS 3.0 PINTAN
64
+ * - Uses HKTAN segment for status checks
65
+ * - Respects server timing from HITANS segment
66
+ *
67
+ * @param error The TanRequiredError that contains the challenge information
68
+ * @param statusCallback Optional callback for status updates during polling
69
+ * @return The final response after confirmation
70
+ *
71
+ * @throws {Error} If the error is not a decoupled TAN challenge
72
+ * @throws {DecoupledTanError} If polling fails (timeout, cancellation, etc.)
73
+ *
74
+ * @see Dialog.handleDecoupledTan for lower-level control
75
+ * @see https://www.hbci-zka.de/ for FinTS specification
76
+ */
77
+ handleDecoupledTanChallenge(error, statusCallback) {
78
+ return __awaiter(this, void 0, void 0, function* () {
79
+ if (!error.isDecoupledTan()) {
80
+ throw new Error("The provided TanRequiredError does not represent a decoupled TAN challenge. " +
81
+ "Only call handleDecoupledTanChallenge when error.isDecoupledTan() returns true. " +
82
+ "For regular TAN challenges, use your normal TAN handling flow instead.");
83
+ }
84
+ return error.dialog.handleDecoupledTan(error.transactionReference, error.challengeText, statusCallback);
85
+ });
86
+ }
33
87
  }
34
88
  exports.PinTanClient = PinTanClient;
35
89
  //# sourceMappingURL=pin-tan-client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pin-tan-client.js","sourceRoot":"","sources":["../src/pin-tan-client.ts"],"names":[],"mappings":";;;AAAA,qCAAkC;AAClC,qCAAgD;AAChD,uCAAoC;AACpC,uDAAqE;AAGrE,2CAA2C;AAgC3C,MAAa,YAAa,SAAQ,eAAM;IAUpC,YAAY,MAA0B;QAClC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC;QAC/D,MAAM,gBAAgB,GAAqB;YACvC,GAAG;YACH,KAAK,EAAE,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,KAAK;YACrB,OAAO,EAAE,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,KAAK;YACzB,UAAU,EAAE,UAAU,aAAV,UAAU,cAAV,UAAU,GAAI,CAAC;YAC3B,UAAU,EAAE,UAAU,aAAV,UAAU,cAAV,UAAU,GAAI,IAAI;SACjC,CAAC;QACF,IAAI,CAAC,UAAU,GAAG,IAAI,gCAAc,CAAC,gBAAgB,CAAC,CAAC;IAC3D,CAAC;IAEM,YAAY,CAAC,YAA2B;QAC3C,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,GAAG,wBAAY,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;QACjE,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;QAC5B,OAAO,IAAI,eAAM,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,UAAU,CAAC,CAAC;IAC9G,CAAC;IAEM,aAAa,CAAC,MAAc,EAAE,QAAwB,EAAE,GAAY;QACvE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;QACvC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC;QACzD,OAAO,IAAI,iBAAO,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;IACjG,CAAC;CACJ;AAnCD,oCAmCC"}
1
+ {"version":3,"file":"pin-tan-client.js","sourceRoot":"","sources":["../src/pin-tan-client.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAAkC;AAClC,qCAAgD;AAChD,uCAAoC;AACpC,uDAAqE;AAGrE,2CAA2C;AAuC3C,MAAa,YAAa,SAAQ,eAAM;IAUpC,YAAY,MAA0B;QAClC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC;QAC/D,MAAM,gBAAgB,GAAqB;YACvC,GAAG;YACH,KAAK,EAAE,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,KAAK;YACrB,OAAO,EAAE,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,KAAK;YACzB,UAAU,EAAE,UAAU,aAAV,UAAU,cAAV,UAAU,GAAI,CAAC;YAC3B,UAAU,EAAE,UAAU,aAAV,UAAU,cAAV,UAAU,GAAI,IAAI;SACjC,CAAC;QACF,IAAI,CAAC,UAAU,GAAG,IAAI,gCAAc,CAAC,gBAAgB,CAAC,CAAC;IAC3D,CAAC;IAEM,YAAY,CAAC,YAA2B;QAC3C,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,GAAG,wBAAY,EAAE,kBAAkB,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;QACrF,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;QAC5B,OAAO,IAAI,eAAM,CACb,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,EAC1E,UAAU,EACV,kBAAkB,CACrB,CAAC;IACN,CAAC;IAEM,aAAa,CAAC,MAAc,EAAE,QAAwB,EAAE,GAAY;QACvE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;QACvC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC;QACzD,OAAO,IAAI,iBAAO,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;IACjG,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkCG;IACU,2BAA2B,CACpC,KAAuB,EACvB,cAA2C;;YAE3C,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,CAAC;gBAC1B,MAAM,IAAI,KAAK,CACX,8EAA8E;oBAC1E,kFAAkF;oBAClF,wEAAwE,CAC/E,CAAC;YACN,CAAC;YAED,OAAO,KAAK,CAAC,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;QAC5G,CAAC;KAAA;CACJ;AAzFD,oCAyFC"}
@@ -14,5 +14,10 @@ export declare class HNSHA extends HNSHA_base {
14
14
  protected defaults(): void;
15
15
  protected serialize(): (string | string[])[];
16
16
  protected deserialize(): void;
17
+ /**
18
+ * Override debugString to mask sensitive data (PIN/TAN).
19
+ * This prevents credentials from being exposed in logs.
20
+ */
21
+ get debugString(): string | string[];
17
22
  }
18
23
  export {};
@@ -25,6 +25,26 @@ class HNSHA extends (0, segment_1.SegmentClass)(HNSHAProps) {
25
25
  deserialize() {
26
26
  throw new Error("Not implemented.");
27
27
  }
28
+ /**
29
+ * Override debugString to mask sensitive data (PIN/TAN).
30
+ * This prevents credentials from being exposed in logs.
31
+ */
32
+ get debugString() {
33
+ const info = `Type: ${this.type}\n` +
34
+ `Version: ${this.version}\n` +
35
+ `Segment Number: ${this.segNo}\n` +
36
+ `Referencing: ${this.reference === undefined ? "None" : this.reference}\n` +
37
+ `----\n`;
38
+ const { secRef, tan } = this;
39
+ const maskedData = [
40
+ format_1.Format.num(secRef),
41
+ format_1.Format.empty(),
42
+ tan ? ["***MASKED***", "***MASKED***"] : "***MASKED***",
43
+ ];
44
+ return maskedData.reduce((result, group, index) => {
45
+ return `${result}DG ${index}: ${Array.isArray(group) ? group.join(", ") : group}\n`;
46
+ }, info);
47
+ }
28
48
  }
29
49
  exports.HNSHA = HNSHA;
30
50
  //# sourceMappingURL=hnsha.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hnsha.js","sourceRoot":"","sources":["../../src/segments/hnsha.ts"],"names":[],"mappings":";;;AAAA,uCAAyC;AACzC,sCAAmC;AAEnC,MAAa,UAAU;CAKtB;AALD,gCAKC;AAED;;;GAGG;AACH,MAAa,KAAM,SAAQ,IAAA,sBAAY,EAAC,UAAU,CAAC;IAAnD;;QACW,SAAI,GAAG,OAAO,CAAC;IAc1B,CAAC;IAZa,QAAQ;QACd,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;IACrB,CAAC;IAES,SAAS;QACf,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QAClC,OAAO,CAAC,eAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,eAAM,CAAC,KAAK,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACxE,CAAC;IAES,WAAW;QACjB,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACxC,CAAC;CACJ;AAfD,sBAeC"}
1
+ {"version":3,"file":"hnsha.js","sourceRoot":"","sources":["../../src/segments/hnsha.ts"],"names":[],"mappings":";;;AAAA,uCAAyC;AACzC,sCAAmC;AAEnC,MAAa,UAAU;CAKtB;AALD,gCAKC;AAED;;;GAGG;AACH,MAAa,KAAM,SAAQ,IAAA,sBAAY,EAAC,UAAU,CAAC;IAAnD;;QACW,SAAI,GAAG,OAAO,CAAC;IAoC1B,CAAC;IAlCa,QAAQ;QACd,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;IACrB,CAAC;IAES,SAAS;QACf,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QAClC,OAAO,CAAC,eAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,eAAM,CAAC,KAAK,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACxE,CAAC;IAES,WAAW;QACjB,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACxC,CAAC;IAED;;;OAGG;IACH,IAAW,WAAW;QAClB,MAAM,IAAI,GACN,SAAS,IAAI,CAAC,IAAI,IAAI;YACtB,YAAY,IAAI,CAAC,OAAO,IAAI;YAC5B,mBAAmB,IAAI,CAAC,KAAK,IAAI;YACjC,gBAAgB,IAAI,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,IAAI;YAC1E,QAAQ,CAAC;QACb,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QAC7B,MAAM,UAAU,GAAG;YACf,eAAM,CAAC,GAAG,CAAC,MAAM,CAAC;YAClB,eAAM,CAAC,KAAK,EAAE;YACd,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc;SAC1D,CAAC;QACF,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YAC9C,OAAO,GAAG,MAAM,MAAM,KAAK,KAAK,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;QACxF,CAAC,EAAE,IAAI,CAAC,CAAC;IACb,CAAC;CACJ;AArCD,sBAqCC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fints-lib",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "FinTS client library with psd2 support",
5
5
  "keywords": [
6
6
  "fints",
@@ -56,16 +56,16 @@
56
56
  "@types/invariant": "^2.2.37",
57
57
  "@types/isomorphic-fetch": "^0.0.39",
58
58
  "@types/istanbul-lib-report": "^3.0.3",
59
- "@types/jest": "^29.5.14",
59
+ "@types/jest": "^30.0.0",
60
60
  "@types/node": "^25.0.3",
61
61
  "cxsd": "^0.1.1",
62
62
  "fetch-mock": "^12.6.0",
63
63
  "fints-institute-db": "^0.16.0",
64
- "jest": "^29.7.0",
65
- "minimatch": "^10.0.1",
64
+ "jest": "^30.2.0",
65
+ "minimatch": "^10.1.1",
66
66
  "ts-jest": "^29.4.6",
67
- "typedoc": "^0.27.9",
68
- "typescript": "^5.8.0"
67
+ "typedoc": "^0.28.15",
68
+ "typescript": "^5.9.3"
69
69
  },
70
70
  "dependencies": {
71
71
  "bind-decorator": "^1.0.11",