@open-nav/core 0.1.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 (133) hide show
  1. package/LICENSE +29 -0
  2. package/README.md +132 -0
  3. package/dist/constants.d.ts +49 -0
  4. package/dist/constants.d.ts.map +1 -0
  5. package/dist/constants.js +58 -0
  6. package/dist/constants.js.map +1 -0
  7. package/dist/crypto/hash.d.ts +16 -0
  8. package/dist/crypto/hash.d.ts.map +1 -0
  9. package/dist/crypto/hash.js +30 -0
  10. package/dist/crypto/hash.js.map +1 -0
  11. package/dist/crypto/node-provider.d.ts +9 -0
  12. package/dist/crypto/node-provider.d.ts.map +1 -0
  13. package/dist/crypto/node-provider.js +18 -0
  14. package/dist/crypto/node-provider.js.map +1 -0
  15. package/dist/crypto/provider.d.ts +28 -0
  16. package/dist/crypto/provider.d.ts.map +1 -0
  17. package/dist/crypto/provider.js +14 -0
  18. package/dist/crypto/provider.js.map +1 -0
  19. package/dist/crypto/request-id.d.ts +16 -0
  20. package/dist/crypto/request-id.d.ts.map +1 -0
  21. package/dist/crypto/request-id.js +59 -0
  22. package/dist/crypto/request-id.js.map +1 -0
  23. package/dist/crypto/signature.d.ts +40 -0
  24. package/dist/crypto/signature.d.ts.map +1 -0
  25. package/dist/crypto/signature.js +38 -0
  26. package/dist/crypto/signature.js.map +1 -0
  27. package/dist/crypto/token.d.ts +14 -0
  28. package/dist/crypto/token.d.ts.map +1 -0
  29. package/dist/crypto/token.js +82 -0
  30. package/dist/crypto/token.js.map +1 -0
  31. package/dist/crypto/web-provider.d.ts +18 -0
  32. package/dist/crypto/web-provider.d.ts.map +1 -0
  33. package/dist/crypto/web-provider.js +31 -0
  34. package/dist/crypto/web-provider.js.map +1 -0
  35. package/dist/errors.d.ts +75 -0
  36. package/dist/errors.d.ts.map +1 -0
  37. package/dist/errors.js +71 -0
  38. package/dist/errors.js.map +1 -0
  39. package/dist/generated/fault-codes.d.ts +1343 -0
  40. package/dist/generated/fault-codes.d.ts.map +1 -0
  41. package/dist/generated/fault-codes.js +1331 -0
  42. package/dist/generated/fault-codes.js.map +1 -0
  43. package/dist/generated/index.d.ts +4 -0
  44. package/dist/generated/index.d.ts.map +1 -0
  45. package/dist/generated/index.js +5 -0
  46. package/dist/generated/index.js.map +1 -0
  47. package/dist/generated/schema.d.ts +13 -0
  48. package/dist/generated/schema.d.ts.map +1 -0
  49. package/dist/generated/schema.js +3756 -0
  50. package/dist/generated/schema.js.map +1 -0
  51. package/dist/generated/types.d.ts +5580 -0
  52. package/dist/generated/types.d.ts.map +1 -0
  53. package/dist/generated/types.js +6 -0
  54. package/dist/generated/types.js.map +1 -0
  55. package/dist/index.d.ts +23 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +23 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/invoice/payload.d.ts +40 -0
  60. package/dist/invoice/payload.d.ts.map +1 -0
  61. package/dist/invoice/payload.js +66 -0
  62. package/dist/invoice/payload.js.map +1 -0
  63. package/dist/money/decimal.d.ts +69 -0
  64. package/dist/money/decimal.d.ts.map +1 -0
  65. package/dist/money/decimal.js +190 -0
  66. package/dist/money/decimal.js.map +1 -0
  67. package/dist/money/summary.d.ts +60 -0
  68. package/dist/money/summary.d.ts.map +1 -0
  69. package/dist/money/summary.js +236 -0
  70. package/dist/money/summary.js.map +1 -0
  71. package/dist/time.d.ts +16 -0
  72. package/dist/time.d.ts.map +1 -0
  73. package/dist/time.js +41 -0
  74. package/dist/time.js.map +1 -0
  75. package/dist/validation/issue.d.ts +67 -0
  76. package/dist/validation/issue.d.ts.map +1 -0
  77. package/dist/validation/issue.js +40 -0
  78. package/dist/validation/issue.js.map +1 -0
  79. package/dist/validation/rules.d.ts +34 -0
  80. package/dist/validation/rules.d.ts.map +1 -0
  81. package/dist/validation/rules.js +290 -0
  82. package/dist/validation/rules.js.map +1 -0
  83. package/dist/validation/schema.d.ts +14 -0
  84. package/dist/validation/schema.d.ts.map +1 -0
  85. package/dist/validation/schema.js +231 -0
  86. package/dist/validation/schema.js.map +1 -0
  87. package/dist/validation/tax-number.d.ts +39 -0
  88. package/dist/validation/tax-number.d.ts.map +1 -0
  89. package/dist/validation/tax-number.js +79 -0
  90. package/dist/validation/tax-number.js.map +1 -0
  91. package/dist/validation/validate.d.ts +29 -0
  92. package/dist/validation/validate.d.ts.map +1 -0
  93. package/dist/validation/validate.js +33 -0
  94. package/dist/validation/validate.js.map +1 -0
  95. package/dist/xml/descriptor.d.ts +82 -0
  96. package/dist/xml/descriptor.d.ts.map +1 -0
  97. package/dist/xml/descriptor.js +32 -0
  98. package/dist/xml/descriptor.js.map +1 -0
  99. package/dist/xml/read.d.ts +25 -0
  100. package/dist/xml/read.d.ts.map +1 -0
  101. package/dist/xml/read.js +230 -0
  102. package/dist/xml/read.js.map +1 -0
  103. package/dist/xml/write.d.ts +28 -0
  104. package/dist/xml/write.d.ts.map +1 -0
  105. package/dist/xml/write.js +299 -0
  106. package/dist/xml/write.js.map +1 -0
  107. package/package.json +55 -0
  108. package/src/constants.ts +76 -0
  109. package/src/crypto/hash.ts +35 -0
  110. package/src/crypto/node-provider.ts +19 -0
  111. package/src/crypto/provider.ts +37 -0
  112. package/src/crypto/request-id.ts +63 -0
  113. package/src/crypto/signature.ts +58 -0
  114. package/src/crypto/token.ts +86 -0
  115. package/src/crypto/web-provider.ts +32 -0
  116. package/src/errors.ts +109 -0
  117. package/src/generated/fault-codes.ts +1338 -0
  118. package/src/generated/index.ts +4 -0
  119. package/src/generated/schema.ts +3760 -0
  120. package/src/generated/types.ts +5829 -0
  121. package/src/index.ts +22 -0
  122. package/src/invoice/payload.ts +102 -0
  123. package/src/money/decimal.ts +218 -0
  124. package/src/money/summary.ts +380 -0
  125. package/src/time.ts +44 -0
  126. package/src/validation/issue.ts +102 -0
  127. package/src/validation/rules.ts +548 -0
  128. package/src/validation/schema.ts +315 -0
  129. package/src/validation/tax-number.ts +96 -0
  130. package/src/validation/validate.ts +45 -0
  131. package/src/xml/descriptor.ts +112 -0
  132. package/src/xml/read.ts +303 -0
  133. package/src/xml/write.ts +391 -0
package/LICENSE ADDED
@@ -0,0 +1,29 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 open-nav contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ ---
24
+
25
+ This repository vendors XML schemas, sample documents and validation message
26
+ catalogues published by the Hungarian Tax and Customs Administration
27
+ (Nemzeti Adó- és Vámhivatal) under the MIT license. Those files live under
28
+ `schemas/` and `conformance/`, retain NAV's copyright, and are covered by
29
+ `schemas/NAV-LICENCE.md`. See `schemas/README.md` for provenance.
package/README.md ADDED
@@ -0,0 +1,132 @@
1
+ # @open-nav/core
2
+
3
+ The parts of the NAV Online Számla interface that have a right answer:
4
+ authentication, the schema, XML, exact decimal arithmetic and validation.
5
+ No network access — everything here is pure, so it is testable and safe to
6
+ run anywhere.
7
+
8
+ ```sh
9
+ npm install @open-nav/core
10
+ ```
11
+
12
+ ## Authentication
13
+
14
+ Every request NAV accepts carries a SHA-512 password hash and a SHA3-512
15
+ request signature. The signature is not over the request body: it is over
16
+ `requestId + yyyyMMddHHmmss + signKey`, followed by a **concatenation of
17
+ per-invoice hashes in index order** when the operation submits invoices.
18
+
19
+ ```ts
20
+ import { passwordHash, requestSignature, createRequestId } from '@open-nav/core';
21
+
22
+ const requestId = createRequestId(); // safe against the 30 char / [+a-zA-Z0-9_] rule
23
+ const timestamp = new Date();
24
+
25
+ const signature = requestSignature(requestId, timestamp, process.env.NAV_SIGN_KEY!, [
26
+ { index: 1, operation: 'CREATE', base64Payload: encoded },
27
+ ]);
28
+ const hash = passwordHash(process.env.NAV_PASSWORD!); // the SHA-512 half
29
+ ```
30
+
31
+ Verified against **all 11 of NAV's published request samples**, the
32
+ three-invoice batch included, which is the case that catches an
33
+ implementation that hashes in the wrong order or hashes a re-serialised copy
34
+ of the payload.
35
+
36
+ `decodeExchangeToken` handles the other half: the token NAV returns is
37
+ AES-128-ECB encrypted with your exchange key, and arrives padded or unpadded
38
+ depending on the operation.
39
+
40
+ ## The schema, generated from the XSDs
41
+
42
+ The types and the runtime metadata that drives serialisation, parsing and
43
+ validation are generated from NAV's own XSDs — ~700 elements across six
44
+ namespaces — and must not be hand-edited. One descriptor table drives all
45
+ three directions, so they cannot disagree with each other.
46
+
47
+ ```ts
48
+ import {
49
+ serializeDocument,
50
+ parseDocumentAs,
51
+ encodeInvoiceData,
52
+ decodeInvoiceData,
53
+ } from '@open-nav/core';
54
+
55
+ const xml = serializeDocument('InvoiceData', document);
56
+ const back = parseDocumentAs<InvoiceData>(xml, 'InvoiceData');
57
+ const base64 = encodeInvoiceData(document); // what goes in the request
58
+ ```
59
+
60
+ All **41 official NAV sample documents** round-trip to canonically equal XML.
61
+
62
+ Namespaces are the trap worth naming: a tax number sits in `OSA/3.0/data`
63
+ while its `taxpayerId` child sits in `OSA/3.0/base`. The generated
64
+ descriptors know which, so you never write a prefix.
65
+
66
+ ## Exact arithmetic
67
+
68
+ Invoice amounts run to 18 digits and quantities to 10 decimal places. IEEE
69
+ 754 doubles cannot carry either, and being one forint out rejects the whole
70
+ batch, so amounts are **decimal strings end to end** and arithmetic goes
71
+ through `Decimal`, which is BigInt-scaled.
72
+
73
+ ```ts
74
+ import { Decimal, computeInvoiceSummary, checkInvoiceSummary } from '@open-nav/core';
75
+
76
+ Decimal.from('0.1').add('0.2').toString(); // '0.3', not 0.30000000000000004
77
+
78
+ const invoice = document.invoiceMain.invoice!; // an InvoiceType
79
+ const summary = computeInvoiceSummary(invoice); // per VAT rate, plus the totals
80
+ const findings = checkInvoiceSummary(invoice); // where it fails to reconcile
81
+ ```
82
+
83
+ Summation is not the whole rule. A line that omits its VAT amount has it
84
+ **derived from the rate**, a VAT exemption is identified by its legal case
85
+ and not by the free text beside it, and a foreign-currency invoice needs a
86
+ forint twin for every amount. Reproduces the summaries of 24 of NAV's 30
87
+ sample invoices; the remaining 6 are internally contradictory upstream — see
88
+ [`conformance/README.md`](../../conformance/README.md).
89
+
90
+ ## Validating before NAV does
91
+
92
+ Two layers, both local: the generated schema, and the business rules that are
93
+ `INVALID_...` faults in NAV's catalogue.
94
+
95
+ ```ts
96
+ import { validateInvoice, faultMessage } from '@open-nav/core';
97
+
98
+ const report = validateInvoice(document, { operation: 'CREATE', language: 'hu' });
99
+ if (!report.valid) {
100
+ for (const issue of report.errors) {
101
+ console.error(issue.path, issue.code, issue.message, issue.navMessage);
102
+ }
103
+ }
104
+ faultMessage('ANNULMENT_IN_PROGRESS', 'hu'); // NAV's own wording, in hu, en or de
105
+ ```
106
+
107
+ Findings carry NAV's own fault code where one exists, so an error you see
108
+ locally is the error you would have seen remotely. The catalogue is generated
109
+ from `schemas/i18n/` — 236 codes, in Hungarian, English and German. It covers
110
+ NAV's _business validation_ codes; the technical ones (`INVALID_SIGNATURE`,
111
+ `INVALID_REQUEST_ID` and the rest) are not in NAV's message files, and arrive
112
+ with their own text on the response instead.
113
+
114
+ Rules NAV can only decide server-side — whether the invoice number is
115
+ already used, whether the customer's tax number is live — are listed in
116
+ `LOCALLY_UNDECIDABLE` rather than guessed at.
117
+
118
+ Warnings do not make a report invalid, and that distinction is load-bearing:
119
+ the taxpayer-id check digit is a warning because 2 of the 4 tax numbers in
120
+ NAV's own samples fail it while NAV itself validates against its registry. A
121
+ validator that cries wolf gets switched off.
122
+
123
+ ## Also here
124
+
125
+ `OPERATIONS`, `BASE_URLS`, `MAX_INVOICE_BATCH_SIZE`, `QUERY_PAGE_SIZE` and
126
+ the other interface constants; `parseTaxNumber` and the county/VAT-code
127
+ tables; NAV's timestamp formats; and the `NavError` hierarchy the client
128
+ throws.
129
+
130
+ ## Licence
131
+
132
+ MIT. Not affiliated with NAV.
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Protocol level constants for the NAV Online Számla (Online Invoice) system.
3
+ *
4
+ * The reference documentation is published by NAV at
5
+ * https://onlineszamla.nav.gov.hu/dokumentaciok — this library targets
6
+ * interface version 3.0 of the invoice service.
7
+ */
8
+ /** XML namespace of the invoice service request/response envelopes. */
9
+ export declare const NS_API = "http://schemas.nav.gov.hu/OSA/3.0/api";
10
+ /** XML namespace of the invoice payload (`InvoiceData`). */
11
+ export declare const NS_DATA = "http://schemas.nav.gov.hu/OSA/3.0/data";
12
+ /** XML namespace of shared invoice building blocks (addresses, tax numbers). */
13
+ export declare const NS_BASE = "http://schemas.nav.gov.hu/OSA/3.0/base";
14
+ /** XML namespace of the annulment payload (`InvoiceAnnulment`). */
15
+ export declare const NS_ANNUL = "http://schemas.nav.gov.hu/OSA/3.0/annul";
16
+ /** XML namespace of the NTCA common header/user blocks. */
17
+ export declare const NS_COMMON = "http://schemas.nav.gov.hu/NTCA/1.0/common";
18
+ /** Value of `header/requestVersion` for this interface version. */
19
+ export declare const REQUEST_VERSION = "3.0";
20
+ /** Value of `header/headerVersion` for this interface version. */
21
+ export declare const HEADER_VERSION = "1.0";
22
+ /** Base URL of the NAV production invoice service. */
23
+ export declare const PRODUCTION_BASE_URL = "https://api.onlineszamla.nav.gov.hu/invoiceService/v3";
24
+ /** Base URL of the NAV test ("teszt") invoice service. */
25
+ export declare const TEST_BASE_URL = "https://api-test.onlineszamla.nav.gov.hu/invoiceService/v3";
26
+ /** Well known NAV environments and their base URLs. */
27
+ export declare const BASE_URLS: {
28
+ readonly production: "https://api.onlineszamla.nav.gov.hu/invoiceService/v3";
29
+ readonly test: "https://api-test.onlineszamla.nav.gov.hu/invoiceService/v3";
30
+ };
31
+ export type NavEnvironment = keyof typeof BASE_URLS;
32
+ /** Operation names (path segments) exposed by the invoice service. */
33
+ export declare const OPERATIONS: readonly ["tokenExchange", "manageInvoice", "manageAnnulment", "queryTransactionStatus", "queryTransactionList", "queryInvoiceData", "queryInvoiceDigest", "queryInvoiceChainDigest", "queryInvoiceCheck", "queryTaxpayer"];
34
+ export type NavOperation = (typeof OPERATIONS)[number];
35
+ /**
36
+ * Maximum number of invoice operations NAV accepts in a single
37
+ * `manageInvoice` request.
38
+ */
39
+ export declare const MAX_INVOICE_BATCH_SIZE = 100;
40
+ /** Page size used by NAV for every paged query response. */
41
+ export declare const QUERY_PAGE_SIZE = 100;
42
+ /**
43
+ * Maximum length of the `requestId` header field. NAV also requires it to be
44
+ * unique per taxpayer, forever.
45
+ */
46
+ export declare const REQUEST_ID_MAX_LENGTH = 30;
47
+ /** Characters NAV allows in a `requestId`. */
48
+ export declare const REQUEST_ID_PATTERN: RegExp;
49
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,uEAAuE;AACvE,eAAO,MAAM,MAAM,0CAA0C,CAAC;AAE9D,4DAA4D;AAC5D,eAAO,MAAM,OAAO,2CAA2C,CAAC;AAEhE,gFAAgF;AAChF,eAAO,MAAM,OAAO,2CAA2C,CAAC;AAEhE,mEAAmE;AACnE,eAAO,MAAM,QAAQ,4CAA4C,CAAC;AAElE,2DAA2D;AAC3D,eAAO,MAAM,SAAS,8CAA8C,CAAC;AAErE,mEAAmE;AACnE,eAAO,MAAM,eAAe,QAAQ,CAAC;AAErC,kEAAkE;AAClE,eAAO,MAAM,cAAc,QAAQ,CAAC;AAEpC,sDAAsD;AACtD,eAAO,MAAM,mBAAmB,0DAA0D,CAAC;AAE3F,0DAA0D;AAC1D,eAAO,MAAM,aAAa,+DAA+D,CAAC;AAE1F,uDAAuD;AACvD,eAAO,MAAM,SAAS;;;CAGZ,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,MAAM,OAAO,SAAS,CAAC;AAEpD,sEAAsE;AACtE,eAAO,MAAM,UAAU,6NAWb,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD;;;GAGG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,4DAA4D;AAC5D,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC;;;GAGG;AACH,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC,8CAA8C;AAC9C,eAAO,MAAM,kBAAkB,QAA0B,CAAC"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Protocol level constants for the NAV Online Számla (Online Invoice) system.
3
+ *
4
+ * The reference documentation is published by NAV at
5
+ * https://onlineszamla.nav.gov.hu/dokumentaciok — this library targets
6
+ * interface version 3.0 of the invoice service.
7
+ */
8
+ /** XML namespace of the invoice service request/response envelopes. */
9
+ export const NS_API = 'http://schemas.nav.gov.hu/OSA/3.0/api';
10
+ /** XML namespace of the invoice payload (`InvoiceData`). */
11
+ export const NS_DATA = 'http://schemas.nav.gov.hu/OSA/3.0/data';
12
+ /** XML namespace of shared invoice building blocks (addresses, tax numbers). */
13
+ export const NS_BASE = 'http://schemas.nav.gov.hu/OSA/3.0/base';
14
+ /** XML namespace of the annulment payload (`InvoiceAnnulment`). */
15
+ export const NS_ANNUL = 'http://schemas.nav.gov.hu/OSA/3.0/annul';
16
+ /** XML namespace of the NTCA common header/user blocks. */
17
+ export const NS_COMMON = 'http://schemas.nav.gov.hu/NTCA/1.0/common';
18
+ /** Value of `header/requestVersion` for this interface version. */
19
+ export const REQUEST_VERSION = '3.0';
20
+ /** Value of `header/headerVersion` for this interface version. */
21
+ export const HEADER_VERSION = '1.0';
22
+ /** Base URL of the NAV production invoice service. */
23
+ export const PRODUCTION_BASE_URL = 'https://api.onlineszamla.nav.gov.hu/invoiceService/v3';
24
+ /** Base URL of the NAV test ("teszt") invoice service. */
25
+ export const TEST_BASE_URL = 'https://api-test.onlineszamla.nav.gov.hu/invoiceService/v3';
26
+ /** Well known NAV environments and their base URLs. */
27
+ export const BASE_URLS = {
28
+ production: PRODUCTION_BASE_URL,
29
+ test: TEST_BASE_URL,
30
+ };
31
+ /** Operation names (path segments) exposed by the invoice service. */
32
+ export const OPERATIONS = [
33
+ 'tokenExchange',
34
+ 'manageInvoice',
35
+ 'manageAnnulment',
36
+ 'queryTransactionStatus',
37
+ 'queryTransactionList',
38
+ 'queryInvoiceData',
39
+ 'queryInvoiceDigest',
40
+ 'queryInvoiceChainDigest',
41
+ 'queryInvoiceCheck',
42
+ 'queryTaxpayer',
43
+ ];
44
+ /**
45
+ * Maximum number of invoice operations NAV accepts in a single
46
+ * `manageInvoice` request.
47
+ */
48
+ export const MAX_INVOICE_BATCH_SIZE = 100;
49
+ /** Page size used by NAV for every paged query response. */
50
+ export const QUERY_PAGE_SIZE = 100;
51
+ /**
52
+ * Maximum length of the `requestId` header field. NAV also requires it to be
53
+ * unique per taxpayer, forever.
54
+ */
55
+ export const REQUEST_ID_MAX_LENGTH = 30;
56
+ /** Characters NAV allows in a `requestId`. */
57
+ export const REQUEST_ID_PATTERN = /^[+a-zA-Z0-9_]{1,30}$/;
58
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,uEAAuE;AACvE,MAAM,CAAC,MAAM,MAAM,GAAG,uCAAuC,CAAC;AAE9D,4DAA4D;AAC5D,MAAM,CAAC,MAAM,OAAO,GAAG,wCAAwC,CAAC;AAEhE,gFAAgF;AAChF,MAAM,CAAC,MAAM,OAAO,GAAG,wCAAwC,CAAC;AAEhE,mEAAmE;AACnE,MAAM,CAAC,MAAM,QAAQ,GAAG,yCAAyC,CAAC;AAElE,2DAA2D;AAC3D,MAAM,CAAC,MAAM,SAAS,GAAG,2CAA2C,CAAC;AAErE,mEAAmE;AACnE,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,CAAC;AAErC,kEAAkE;AAClE,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,CAAC;AAEpC,sDAAsD;AACtD,MAAM,CAAC,MAAM,mBAAmB,GAAG,uDAAuD,CAAC;AAE3F,0DAA0D;AAC1D,MAAM,CAAC,MAAM,aAAa,GAAG,4DAA4D,CAAC;AAE1F,uDAAuD;AACvD,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,UAAU,EAAE,mBAAmB;IAC/B,IAAI,EAAE,aAAa;CACX,CAAC;AAIX,sEAAsE;AACtE,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,eAAe;IACf,eAAe;IACf,iBAAiB;IACjB,wBAAwB;IACxB,sBAAsB;IACtB,kBAAkB;IAClB,oBAAoB;IACpB,yBAAyB;IACzB,mBAAmB;IACnB,eAAe;CACP,CAAC;AAIX;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAE1C,4DAA4D;AAC5D,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,CAAC;AAEnC;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAC;AAExC,8CAA8C;AAC9C,MAAM,CAAC,MAAM,kBAAkB,GAAG,uBAAuB,CAAC"}
@@ -0,0 +1,16 @@
1
+ /** Uppercase hexadecimal SHA-512 digest of a UTF-8 string. */
2
+ export declare function sha512(value: string): string;
3
+ /** Uppercase hexadecimal SHA3-512 digest of a UTF-8 string. */
4
+ export declare function sha3_512(value: string): string;
5
+ /**
6
+ * Hash of the technical user's password for the `user/passwordHash` field.
7
+ *
8
+ * NAV expects the uppercase hex SHA-512 digest of the password, declared on
9
+ * the element with `cryptoType="SHA-512"`.
10
+ */
11
+ export declare function passwordHash(password: string): string;
12
+ /** `cryptoType` attribute value used for `passwordHash`. */
13
+ export declare const PASSWORD_HASH_CRYPTO_TYPE = "SHA-512";
14
+ /** `cryptoType` attribute value used for `requestSignature` and invoice hashes. */
15
+ export declare const SIGNATURE_CRYPTO_TYPE = "SHA3-512";
16
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/crypto/hash.ts"],"names":[],"mappings":"AAUA,8DAA8D;AAC9D,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,+DAA+D;AAC/D,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,4DAA4D;AAC5D,eAAO,MAAM,yBAAyB,YAAY,CAAC;AAEnD,mFAAmF;AACnF,eAAO,MAAM,qBAAqB,aAAa,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { getCryptoProvider } from './provider.js';
2
+ const encoder = new TextEncoder();
3
+ function toHexUpper(bytes) {
4
+ let out = '';
5
+ for (const byte of bytes)
6
+ out += byte.toString(16).padStart(2, '0');
7
+ return out.toUpperCase();
8
+ }
9
+ /** Uppercase hexadecimal SHA-512 digest of a UTF-8 string. */
10
+ export function sha512(value) {
11
+ return toHexUpper(getCryptoProvider().sha512(encoder.encode(value)));
12
+ }
13
+ /** Uppercase hexadecimal SHA3-512 digest of a UTF-8 string. */
14
+ export function sha3_512(value) {
15
+ return toHexUpper(getCryptoProvider().sha3_512(encoder.encode(value)));
16
+ }
17
+ /**
18
+ * Hash of the technical user's password for the `user/passwordHash` field.
19
+ *
20
+ * NAV expects the uppercase hex SHA-512 digest of the password, declared on
21
+ * the element with `cryptoType="SHA-512"`.
22
+ */
23
+ export function passwordHash(password) {
24
+ return sha512(password);
25
+ }
26
+ /** `cryptoType` attribute value used for `passwordHash`. */
27
+ export const PASSWORD_HASH_CRYPTO_TYPE = 'SHA-512';
28
+ /** `cryptoType` attribute value used for `requestSignature` and invoice hashes. */
29
+ export const SIGNATURE_CRYPTO_TYPE = 'SHA3-512';
30
+ //# sourceMappingURL=hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/crypto/hash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;AAElC,SAAS,UAAU,CAAC,KAAiB;IACnC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACpE,OAAO,GAAG,CAAC,WAAW,EAAE,CAAC;AAC3B,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,MAAM,CAAC,KAAa;IAClC,OAAO,UAAU,CAAC,iBAAiB,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,OAAO,UAAU,CAAC,iBAAiB,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACzE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AAED,4DAA4D;AAC5D,MAAM,CAAC,MAAM,yBAAyB,GAAG,SAAS,CAAC;AAEnD,mFAAmF;AACnF,MAAM,CAAC,MAAM,qBAAqB,GAAG,UAAU,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { CryptoProvider } from './provider.js';
2
+ /**
3
+ * The default {@link CryptoProvider}, backed by Node's built-in `node:crypto`.
4
+ *
5
+ * Works on Node, Bun and Deno. It does **not** work on Cloudflare Workers,
6
+ * whose `node:crypto` lacks SHA-3 — use {@link createWebCryptoProvider} there.
7
+ */
8
+ export declare const nodeCryptoProvider: CryptoProvider;
9
+ //# sourceMappingURL=node-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-provider.d.ts","sourceRoot":"","sources":["../../src/crypto/node-provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAE,cAShC,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { createHash, createDecipheriv, randomBytes } from 'node:crypto';
2
+ /**
3
+ * The default {@link CryptoProvider}, backed by Node's built-in `node:crypto`.
4
+ *
5
+ * Works on Node, Bun and Deno. It does **not** work on Cloudflare Workers,
6
+ * whose `node:crypto` lacks SHA-3 — use {@link createWebCryptoProvider} there.
7
+ */
8
+ export const nodeCryptoProvider = {
9
+ sha512: (data) => Uint8Array.from(createHash('sha512').update(data).digest()),
10
+ sha3_512: (data) => Uint8Array.from(createHash('sha3-512').update(data).digest()),
11
+ aes128EcbDecrypt: (ciphertext, key) => {
12
+ const decipher = createDecipheriv('aes-128-ecb', key, null);
13
+ decipher.setAutoPadding(false);
14
+ return Uint8Array.from(Buffer.concat([decipher.update(ciphertext), decipher.final()]));
15
+ },
16
+ randomBytes: (length) => Uint8Array.from(randomBytes(length)),
17
+ };
18
+ //# sourceMappingURL=node-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-provider.js","sourceRoot":"","sources":["../../src/crypto/node-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAGxE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAmB;IAChD,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;IAC7E,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;IACjF,gBAAgB,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE,EAAE;QACpC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,aAAa,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QAC5D,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAC/B,OAAO,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IACzF,CAAC;IACD,WAAW,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;CAC9D,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The low-level cryptographic primitives the NAV protocol needs, abstracted so
3
+ * the library can run on any JavaScript runtime.
4
+ *
5
+ * The default is {@link nodeCryptoProvider}, backed by Node's built-in
6
+ * `node:crypto`. On runtimes whose `node:crypto` lacks SHA-3 — notably
7
+ * Cloudflare Workers (workerd/BoringSSL), where `createHash('sha3-512')` throws
8
+ * `Digest method not supported` — install {@link createWebCryptoProvider} via
9
+ * {@link setCryptoProvider} once at startup, before making any request.
10
+ */
11
+ export interface CryptoProvider {
12
+ /** Raw SHA-512 digest of `data`. */
13
+ sha512(data: Uint8Array): Uint8Array;
14
+ /** Raw SHA3-512 digest of `data`. */
15
+ sha3_512(data: Uint8Array): Uint8Array;
16
+ /** AES-128 ECB decryption without padding; `key` is exactly 16 bytes. */
17
+ aes128EcbDecrypt(ciphertext: Uint8Array, key: Uint8Array): Uint8Array;
18
+ /** `length` cryptographically strong random bytes. */
19
+ randomBytes(length: number): Uint8Array;
20
+ }
21
+ /** The crypto provider currently backing every cryptographic helper. */
22
+ export declare function getCryptoProvider(): CryptoProvider;
23
+ /**
24
+ * Replace the active crypto provider. Call once at startup, before any NAV
25
+ * request — e.g. `setCryptoProvider(createWebCryptoProvider())` in a Worker.
26
+ */
27
+ export declare function setCryptoProvider(provider: CryptoProvider): void;
28
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/crypto/provider.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,MAAM,WAAW,cAAc;IAC7B,oCAAoC;IACpC,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;IACrC,qCAAqC;IACrC,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;IACvC,yEAAyE;IACzE,gBAAgB,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,GAAG,UAAU,CAAC;IACtE,sDAAsD;IACtD,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC;CACzC;AAID,wEAAwE;AACxE,wBAAgB,iBAAiB,IAAI,cAAc,CAElD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAEhE"}
@@ -0,0 +1,14 @@
1
+ import { nodeCryptoProvider } from './node-provider.js';
2
+ let activeProvider = nodeCryptoProvider;
3
+ /** The crypto provider currently backing every cryptographic helper. */
4
+ export function getCryptoProvider() {
5
+ return activeProvider;
6
+ }
7
+ /**
8
+ * Replace the active crypto provider. Call once at startup, before any NAV
9
+ * request — e.g. `setCryptoProvider(createWebCryptoProvider())` in a Worker.
10
+ */
11
+ export function setCryptoProvider(provider) {
12
+ activeProvider = provider;
13
+ }
14
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/crypto/provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAuBxD,IAAI,cAAc,GAAmB,kBAAkB,CAAC;AAExD,wEAAwE;AACxE,MAAM,UAAU,iBAAiB;IAC/B,OAAO,cAAc,CAAC;AACxB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAwB;IACxD,cAAc,GAAG,QAAQ,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Generate a `requestId` that satisfies NAV's constraints.
3
+ *
4
+ * NAV requires the value to match `[+a-zA-Z0-9_]{1,30}` and to be unique for
5
+ * the taxpayer across all requests ever sent — a replayed identifier is
6
+ * rejected with `INVALID_REQUEST_ID`. The generated value combines a
7
+ * millisecond timestamp with random characters, which is collision safe for
8
+ * practical throughput, but persisting issued identifiers is still the only
9
+ * way to be certain after a clock change.
10
+ *
11
+ * @param prefix optional caller prefix, useful for tracing (`[a-zA-Z0-9_+]`)
12
+ */
13
+ export declare function createRequestId(prefix?: string): string;
14
+ /** Throw unless `value` is a valid `requestId`. */
15
+ export declare function assertRequestId(value: string): void;
16
+ //# sourceMappingURL=request-id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-id.d.ts","sourceRoot":"","sources":["../../src/crypto/request-id.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,MAAM,SAAO,GAAG,MAAM,CAcrD;AAED,mDAAmD;AACnD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAUnD"}
@@ -0,0 +1,59 @@
1
+ import { getCryptoProvider } from './provider.js';
2
+ import { REQUEST_ID_MAX_LENGTH, REQUEST_ID_PATTERN } from '../constants.js';
3
+ import { NavValidationError } from '../errors.js';
4
+ const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
5
+ /**
6
+ * Generate a `requestId` that satisfies NAV's constraints.
7
+ *
8
+ * NAV requires the value to match `[+a-zA-Z0-9_]{1,30}` and to be unique for
9
+ * the taxpayer across all requests ever sent — a replayed identifier is
10
+ * rejected with `INVALID_REQUEST_ID`. The generated value combines a
11
+ * millisecond timestamp with random characters, which is collision safe for
12
+ * practical throughput, but persisting issued identifiers is still the only
13
+ * way to be certain after a clock change.
14
+ *
15
+ * @param prefix optional caller prefix, useful for tracing (`[a-zA-Z0-9_+]`)
16
+ */
17
+ export function createRequestId(prefix = 'ON') {
18
+ assertRequestIdChars(prefix, 'prefix');
19
+ const stamp = Date.now().toString(36).toUpperCase();
20
+ const available = REQUEST_ID_MAX_LENGTH - prefix.length - stamp.length;
21
+ if (available < 4) {
22
+ throw new NavValidationError('requestId prefix is too long', [
23
+ {
24
+ path: 'prefix',
25
+ code: 'REQUEST_ID_PREFIX_TOO_LONG',
26
+ message: `leaves only ${available} characters of entropy, need at least 4`,
27
+ },
28
+ ]);
29
+ }
30
+ return `${prefix}${stamp}${randomChars(Math.min(available, 8))}`;
31
+ }
32
+ /** Throw unless `value` is a valid `requestId`. */
33
+ export function assertRequestId(value) {
34
+ if (!REQUEST_ID_PATTERN.test(value)) {
35
+ throw new NavValidationError('Invalid requestId', [
36
+ {
37
+ path: 'requestId',
38
+ code: 'INVALID_REQUEST_ID',
39
+ message: `must match ${REQUEST_ID_PATTERN.source}, got ${JSON.stringify(value)}`,
40
+ },
41
+ ]);
42
+ }
43
+ }
44
+ function assertRequestIdChars(value, path) {
45
+ if (!/^[+a-zA-Z0-9_]*$/.test(value)) {
46
+ throw new NavValidationError('Invalid requestId characters', [
47
+ { path, code: 'INVALID_REQUEST_ID', message: 'may only contain [+a-zA-Z0-9_]' },
48
+ ]);
49
+ }
50
+ }
51
+ function randomChars(length) {
52
+ const bytes = getCryptoProvider().randomBytes(length);
53
+ let out = '';
54
+ for (let i = 0; i < length; i += 1) {
55
+ out += ALPHABET[bytes[i] % ALPHABET.length];
56
+ }
57
+ return out;
58
+ }
59
+ //# sourceMappingURL=request-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-id.js","sourceRoot":"","sources":["../../src/crypto/request-id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,MAAM,QAAQ,GAAG,gEAAgE,CAAC;AAElF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,MAAM,GAAG,IAAI;IAC3C,oBAAoB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACpD,MAAM,SAAS,GAAG,qBAAqB,GAAG,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IACvE,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QAClB,MAAM,IAAI,kBAAkB,CAAC,8BAA8B,EAAE;YAC3D;gBACE,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,4BAA4B;gBAClC,OAAO,EAAE,eAAe,SAAS,yCAAyC;aAC3E;SACF,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACnE,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,kBAAkB,CAAC,mBAAmB,EAAE;YAChD;gBACE,IAAI,EAAE,WAAW;gBACjB,IAAI,EAAE,oBAAoB;gBAC1B,OAAO,EAAE,cAAc,kBAAkB,CAAC,MAAM,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE;aACjF;SACF,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAa,EAAE,IAAY;IACvD,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,kBAAkB,CAAC,8BAA8B,EAAE;YAC3D,EAAE,IAAI,EAAE,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,gCAAgC,EAAE;SAChF,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,MAAc;IACjC,MAAM,KAAK,GAAG,iBAAiB,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACtD,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,GAAG,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * A single invoice (or annulment) operation as it contributes to the request
3
+ * signature of a `manageInvoice` / `manageAnnulment` call.
4
+ */
5
+ export interface SignedOperation {
6
+ /** 1-based position inside the batch; operations are hashed in index order. */
7
+ index: number;
8
+ /** `CREATE`, `MODIFY`, `STORNO` or `ANNUL`. */
9
+ operation: string;
10
+ /** Base64 encoded payload exactly as it appears in the request XML. */
11
+ base64Payload: string;
12
+ }
13
+ /**
14
+ * Hash of one invoice operation, as consumed by {@link requestSignature} and
15
+ * as sent in the optional `electronicInvoiceHash` element.
16
+ *
17
+ * NAV defines it as `SHA3-512(operation || base64Payload)`, uppercase hex.
18
+ */
19
+ export declare function operationHash(operation: string, base64Payload: string): string;
20
+ /**
21
+ * Compute the `user/requestSignature` value.
22
+ *
23
+ * NAV specifies the signature as
24
+ *
25
+ * ```text
26
+ * SHA3-512( requestId || yyyyMMddHHmmss(timestamp) || signKey || hash(op1) || hash(op2) ... )
27
+ * ```
28
+ *
29
+ * where the per-operation hashes are only present for `manageInvoice` and
30
+ * `manageAnnulment` requests and must be concatenated in ascending `index`
31
+ * order. The timestamp must be the request header timestamp truncated to
32
+ * whole seconds and rendered in UTC without separators.
33
+ *
34
+ * @param requestId the `header/requestId` of the same request
35
+ * @param timestamp the `header/timestamp` of the same request
36
+ * @param signKey the technical user's signature key (aláírókulcs)
37
+ * @param operations invoice/annulment operations of the batch, if any
38
+ */
39
+ export declare function requestSignature(requestId: string, timestamp: Date | string, signKey: string, operations?: SignedOperation[]): string;
40
+ //# sourceMappingURL=signature.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature.d.ts","sourceRoot":"","sources":["../../src/crypto/signature.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAE9E;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,IAAI,GAAG,MAAM,EACxB,OAAO,EAAE,MAAM,EACf,UAAU,GAAE,eAAe,EAAO,GACjC,MAAM,CAOR"}
@@ -0,0 +1,38 @@
1
+ import { sha3_512 } from './hash.js';
2
+ import { toSignatureTimestamp } from '../time.js';
3
+ /**
4
+ * Hash of one invoice operation, as consumed by {@link requestSignature} and
5
+ * as sent in the optional `electronicInvoiceHash` element.
6
+ *
7
+ * NAV defines it as `SHA3-512(operation || base64Payload)`, uppercase hex.
8
+ */
9
+ export function operationHash(operation, base64Payload) {
10
+ return sha3_512(`${operation}${base64Payload}`);
11
+ }
12
+ /**
13
+ * Compute the `user/requestSignature` value.
14
+ *
15
+ * NAV specifies the signature as
16
+ *
17
+ * ```text
18
+ * SHA3-512( requestId || yyyyMMddHHmmss(timestamp) || signKey || hash(op1) || hash(op2) ... )
19
+ * ```
20
+ *
21
+ * where the per-operation hashes are only present for `manageInvoice` and
22
+ * `manageAnnulment` requests and must be concatenated in ascending `index`
23
+ * order. The timestamp must be the request header timestamp truncated to
24
+ * whole seconds and rendered in UTC without separators.
25
+ *
26
+ * @param requestId the `header/requestId` of the same request
27
+ * @param timestamp the `header/timestamp` of the same request
28
+ * @param signKey the technical user's signature key (aláírókulcs)
29
+ * @param operations invoice/annulment operations of the batch, if any
30
+ */
31
+ export function requestSignature(requestId, timestamp, signKey, operations = []) {
32
+ const operationDigests = [...operations]
33
+ .sort((a, b) => a.index - b.index)
34
+ .map((op) => operationHash(op.operation, op.base64Payload))
35
+ .join('');
36
+ return sha3_512(`${requestId}${toSignatureTimestamp(timestamp)}${signKey}${operationDigests}`);
37
+ }
38
+ //# sourceMappingURL=signature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature.js","sourceRoot":"","sources":["../../src/crypto/signature.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAelD;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,SAAiB,EAAE,aAAqB;IACpE,OAAO,QAAQ,CAAC,GAAG,SAAS,GAAG,aAAa,EAAE,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,gBAAgB,CAC9B,SAAiB,EACjB,SAAwB,EACxB,OAAe,EACf,aAAgC,EAAE;IAElC,MAAM,gBAAgB,GAAG,CAAC,GAAG,UAAU,CAAC;SACrC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;SACjC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC;SAC1D,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,OAAO,QAAQ,CAAC,GAAG,SAAS,GAAG,oBAAoB,CAAC,SAAS,CAAC,GAAG,OAAO,GAAG,gBAAgB,EAAE,CAAC,CAAC;AACjG,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Decrypt the `encodedExchangeToken` returned by `tokenExchange`.
3
+ *
4
+ * NAV encrypts the 16 character exchange token with AES-128 in ECB mode using
5
+ * the technical user's exchange key (csereklucs / "XML aláírás kulcs" pair) as
6
+ * the raw key, then base64 encodes the result. Padding is optional in
7
+ * practice: NAV historically returned an unpadded 16 byte block, while some
8
+ * environments return a PKCS#7 padded 32 byte block, so both are accepted.
9
+ *
10
+ * @param encodedToken base64 payload from the response
11
+ * @param exchangeKey 16 character exchange key of the technical user
12
+ */
13
+ export declare function decodeExchangeToken(encodedToken: string, exchangeKey: string): string;
14
+ //# sourceMappingURL=token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../src/crypto/token.ts"],"names":[],"mappings":"AA0BA;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CA6BrF"}