ksef-client-ts 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -7
- package/dist/cli.js +30 -3
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +182 -67
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -6
- package/dist/index.d.ts +52 -6
- package/dist/index.js +181 -70
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -65,7 +65,8 @@ function resolveOptions(options = {}) {
|
|
|
65
65
|
lighthouseUrl: options.lighthouseUrl ?? env.lighthouseUrl,
|
|
66
66
|
apiVersion: options.apiVersion ?? DEFAULT_API_VERSION,
|
|
67
67
|
timeout: options.timeout ?? DEFAULT_TIMEOUT,
|
|
68
|
-
customHeaders: options.customHeaders ?? {}
|
|
68
|
+
customHeaders: options.customHeaders ?? {},
|
|
69
|
+
environmentName: options.environment ?? (options.baseUrl ? void 0 : "TEST")
|
|
69
70
|
};
|
|
70
71
|
}
|
|
71
72
|
var DEFAULT_API_VERSION, DEFAULT_TIMEOUT;
|
|
@@ -1573,84 +1574,111 @@ var init_test_data = __esm({
|
|
|
1573
1574
|
"use strict";
|
|
1574
1575
|
init_rest_request();
|
|
1575
1576
|
init_routes();
|
|
1577
|
+
init_ksef_error();
|
|
1576
1578
|
TestDataService = class {
|
|
1577
1579
|
restClient;
|
|
1578
|
-
|
|
1580
|
+
environmentName;
|
|
1581
|
+
constructor(restClient, environmentName) {
|
|
1579
1582
|
this.restClient = restClient;
|
|
1583
|
+
this.environmentName = environmentName;
|
|
1584
|
+
}
|
|
1585
|
+
ensureTestEnvironment() {
|
|
1586
|
+
if (this.environmentName && this.environmentName !== "TEST") {
|
|
1587
|
+
throw new KSeFError(
|
|
1588
|
+
`Test data APIs are only available on the TEST environment (current: ${this.environmentName})`
|
|
1589
|
+
);
|
|
1590
|
+
}
|
|
1580
1591
|
}
|
|
1581
1592
|
// Subject management
|
|
1582
1593
|
async createSubject(request) {
|
|
1594
|
+
this.ensureTestEnvironment();
|
|
1583
1595
|
const req = RestRequest.post(Routes.TestData.createSubject).body(request);
|
|
1584
1596
|
await this.restClient.executeVoid(req);
|
|
1585
1597
|
}
|
|
1586
1598
|
async removeSubject(request) {
|
|
1599
|
+
this.ensureTestEnvironment();
|
|
1587
1600
|
const req = RestRequest.post(Routes.TestData.removeSubject).body(request);
|
|
1588
1601
|
await this.restClient.executeVoid(req);
|
|
1589
1602
|
}
|
|
1590
1603
|
// Person management
|
|
1591
1604
|
async createPerson(request) {
|
|
1605
|
+
this.ensureTestEnvironment();
|
|
1592
1606
|
const req = RestRequest.post(Routes.TestData.createPerson).body(request);
|
|
1593
1607
|
await this.restClient.executeVoid(req);
|
|
1594
1608
|
}
|
|
1595
1609
|
async removePerson(request) {
|
|
1610
|
+
this.ensureTestEnvironment();
|
|
1596
1611
|
const req = RestRequest.post(Routes.TestData.removePerson).body(request);
|
|
1597
1612
|
await this.restClient.executeVoid(req);
|
|
1598
1613
|
}
|
|
1599
1614
|
// Permissions
|
|
1600
1615
|
async grantPermissions(request) {
|
|
1616
|
+
this.ensureTestEnvironment();
|
|
1601
1617
|
const req = RestRequest.post(Routes.TestData.grantPerms).body(request);
|
|
1602
1618
|
await this.restClient.executeVoid(req);
|
|
1603
1619
|
}
|
|
1604
1620
|
async revokePermissions(request) {
|
|
1621
|
+
this.ensureTestEnvironment();
|
|
1605
1622
|
const req = RestRequest.post(Routes.TestData.revokePerms).body(request);
|
|
1606
1623
|
await this.restClient.executeVoid(req);
|
|
1607
1624
|
}
|
|
1608
1625
|
// Attachment permissions
|
|
1609
1626
|
async enableAttachment(request) {
|
|
1627
|
+
this.ensureTestEnvironment();
|
|
1610
1628
|
const req = RestRequest.post(Routes.TestData.enableAttach).body(request);
|
|
1611
1629
|
await this.restClient.executeVoid(req);
|
|
1612
1630
|
}
|
|
1613
1631
|
async disableAttachment(request) {
|
|
1632
|
+
this.ensureTestEnvironment();
|
|
1614
1633
|
const req = RestRequest.post(Routes.TestData.disableAttach).body(request);
|
|
1615
1634
|
await this.restClient.executeVoid(req);
|
|
1616
1635
|
}
|
|
1617
1636
|
// Session limits
|
|
1618
1637
|
async changeSessionLimits(request) {
|
|
1638
|
+
this.ensureTestEnvironment();
|
|
1619
1639
|
const req = RestRequest.post(Routes.TestData.changeSessionLimitsInCurrentContext).body(request);
|
|
1620
1640
|
await this.restClient.executeVoid(req);
|
|
1621
1641
|
}
|
|
1622
1642
|
async restoreDefaultSessionLimits() {
|
|
1643
|
+
this.ensureTestEnvironment();
|
|
1623
1644
|
const req = RestRequest.delete(Routes.TestData.restoreDefaultSessionLimitsInCurrentContext);
|
|
1624
1645
|
await this.restClient.executeVoid(req);
|
|
1625
1646
|
}
|
|
1626
1647
|
// Certificate limits
|
|
1627
1648
|
async changeCertificatesLimit(request) {
|
|
1649
|
+
this.ensureTestEnvironment();
|
|
1628
1650
|
const req = RestRequest.post(Routes.TestData.changeCertificatesLimitInCurrentSubject).body(request);
|
|
1629
1651
|
await this.restClient.executeVoid(req);
|
|
1630
1652
|
}
|
|
1631
1653
|
async restoreDefaultCertificatesLimit() {
|
|
1654
|
+
this.ensureTestEnvironment();
|
|
1632
1655
|
const req = RestRequest.delete(Routes.TestData.restoreDefaultCertificatesLimitInCurrentSubject);
|
|
1633
1656
|
await this.restClient.executeVoid(req);
|
|
1634
1657
|
}
|
|
1635
1658
|
// Rate limits
|
|
1636
1659
|
async setRateLimits(request) {
|
|
1660
|
+
this.ensureTestEnvironment();
|
|
1637
1661
|
const req = RestRequest.post(Routes.TestData.rateLimits).body(request);
|
|
1638
1662
|
await this.restClient.executeVoid(req);
|
|
1639
1663
|
}
|
|
1640
1664
|
async restoreDefaultRateLimits() {
|
|
1665
|
+
this.ensureTestEnvironment();
|
|
1641
1666
|
const req = RestRequest.delete(Routes.TestData.rateLimits);
|
|
1642
1667
|
await this.restClient.executeVoid(req);
|
|
1643
1668
|
}
|
|
1644
1669
|
async setProductionRateLimits() {
|
|
1670
|
+
this.ensureTestEnvironment();
|
|
1645
1671
|
const req = RestRequest.post(Routes.TestData.productionRateLimits);
|
|
1646
1672
|
await this.restClient.executeVoid(req);
|
|
1647
1673
|
}
|
|
1648
1674
|
// Context blocking
|
|
1649
1675
|
async blockContext(request) {
|
|
1676
|
+
this.ensureTestEnvironment();
|
|
1650
1677
|
const req = RestRequest.post(Routes.TestData.blockContext).body(request);
|
|
1651
1678
|
await this.restClient.executeVoid(req);
|
|
1652
1679
|
}
|
|
1653
1680
|
async unblockContext(request) {
|
|
1681
|
+
this.ensureTestEnvironment();
|
|
1654
1682
|
const req = RestRequest.post(Routes.TestData.unblockContext).body(request);
|
|
1655
1683
|
await this.restClient.executeVoid(req);
|
|
1656
1684
|
}
|
|
@@ -1727,10 +1755,10 @@ ${lines.join("\n")}
|
|
|
1727
1755
|
});
|
|
1728
1756
|
|
|
1729
1757
|
// src/crypto/cryptography-service.ts
|
|
1730
|
-
import * as
|
|
1758
|
+
import * as crypto2 from "crypto";
|
|
1731
1759
|
import * as x509 from "@peculiar/x509";
|
|
1732
1760
|
function setCryptoProvider() {
|
|
1733
|
-
x509.cryptoProvider.set(
|
|
1761
|
+
x509.cryptoProvider.set(crypto2.webcrypto);
|
|
1734
1762
|
}
|
|
1735
1763
|
function buildX500Name(fields) {
|
|
1736
1764
|
const parts = [];
|
|
@@ -1772,12 +1800,12 @@ var init_cryptography_service = __esm({
|
|
|
1772
1800
|
// ---------------------------------------------------------------------------
|
|
1773
1801
|
/** Encrypt with AES-256-CBC (PKCS7 padding is automatic in Node). */
|
|
1774
1802
|
encryptAES256(content, key, iv) {
|
|
1775
|
-
const cipher =
|
|
1803
|
+
const cipher = crypto2.createCipheriv("aes-256-cbc", key, iv);
|
|
1776
1804
|
return new Uint8Array(Buffer.concat([cipher.update(content), cipher.final()]));
|
|
1777
1805
|
}
|
|
1778
1806
|
/** Decrypt with AES-256-CBC. */
|
|
1779
1807
|
decryptAES256(content, key, iv) {
|
|
1780
|
-
const decipher =
|
|
1808
|
+
const decipher = crypto2.createDecipheriv("aes-256-cbc", key, iv);
|
|
1781
1809
|
return new Uint8Array(Buffer.concat([decipher.update(content), decipher.final()]));
|
|
1782
1810
|
}
|
|
1783
1811
|
// ---------------------------------------------------------------------------
|
|
@@ -1788,14 +1816,14 @@ var init_cryptography_service = __esm({
|
|
|
1788
1816
|
* SymmetricKeyEncryption certificate's RSA public key (RSA-OAEP SHA-256).
|
|
1789
1817
|
*/
|
|
1790
1818
|
getEncryptionData() {
|
|
1791
|
-
const key =
|
|
1792
|
-
const iv =
|
|
1819
|
+
const key = crypto2.randomBytes(32);
|
|
1820
|
+
const iv = crypto2.randomBytes(16);
|
|
1793
1821
|
const certPem = this.fetcher.getSymmetricKeyEncryptionPem();
|
|
1794
|
-
const encryptedKey =
|
|
1822
|
+
const encryptedKey = crypto2.publicEncrypt(
|
|
1795
1823
|
{
|
|
1796
1824
|
key: certPem,
|
|
1797
1825
|
oaepHash: "sha256",
|
|
1798
|
-
padding:
|
|
1826
|
+
padding: crypto2.constants.RSA_PKCS1_OAEP_PADDING
|
|
1799
1827
|
},
|
|
1800
1828
|
key
|
|
1801
1829
|
);
|
|
@@ -1829,7 +1857,7 @@ var init_cryptography_service = __esm({
|
|
|
1829
1857
|
const timestampMs = new Date(challengeTimestamp).getTime();
|
|
1830
1858
|
const plaintext = Buffer.from(`${token}|${timestampMs}`, "utf-8");
|
|
1831
1859
|
const certPem = this.fetcher.getKsefTokenEncryptionPem();
|
|
1832
|
-
const cert = new
|
|
1860
|
+
const cert = new crypto2.X509Certificate(certPem);
|
|
1833
1861
|
const publicKey = cert.publicKey;
|
|
1834
1862
|
if (publicKey.asymmetricKeyType === "rsa") {
|
|
1835
1863
|
return this.encryptRsaOaep(certPem, plaintext);
|
|
@@ -1844,7 +1872,7 @@ var init_cryptography_service = __esm({
|
|
|
1844
1872
|
// ---------------------------------------------------------------------------
|
|
1845
1873
|
/** Compute SHA-256 hash (base64) and byte length. */
|
|
1846
1874
|
getFileMetadata(file) {
|
|
1847
|
-
const hash =
|
|
1875
|
+
const hash = crypto2.createHash("sha256").update(file).digest("base64");
|
|
1848
1876
|
return { hashSHA: hash, fileSize: file.length };
|
|
1849
1877
|
}
|
|
1850
1878
|
// ---------------------------------------------------------------------------
|
|
@@ -1859,7 +1887,7 @@ var init_cryptography_service = __esm({
|
|
|
1859
1887
|
publicExponent: new Uint8Array([1, 0, 1]),
|
|
1860
1888
|
modulusLength: 2048
|
|
1861
1889
|
};
|
|
1862
|
-
const keys = await
|
|
1890
|
+
const keys = await crypto2.webcrypto.subtle.generateKey(
|
|
1863
1891
|
algorithm,
|
|
1864
1892
|
true,
|
|
1865
1893
|
["sign", "verify"]
|
|
@@ -1870,7 +1898,7 @@ var init_cryptography_service = __esm({
|
|
|
1870
1898
|
signingAlgorithm: algorithm
|
|
1871
1899
|
});
|
|
1872
1900
|
const csrDer = new Uint8Array(csr.rawData);
|
|
1873
|
-
const pkcs8 = await
|
|
1901
|
+
const pkcs8 = await crypto2.webcrypto.subtle.exportKey("pkcs8", keys.privateKey);
|
|
1874
1902
|
const privateKeyPem = pemEncode(new Uint8Array(pkcs8), "PRIVATE KEY");
|
|
1875
1903
|
return { csrDer, privateKeyPem };
|
|
1876
1904
|
}
|
|
@@ -1881,7 +1909,7 @@ var init_cryptography_service = __esm({
|
|
|
1881
1909
|
name: "ECDSA",
|
|
1882
1910
|
namedCurve: "P-256"
|
|
1883
1911
|
};
|
|
1884
|
-
const keys = await
|
|
1912
|
+
const keys = await crypto2.webcrypto.subtle.generateKey(
|
|
1885
1913
|
algorithm,
|
|
1886
1914
|
true,
|
|
1887
1915
|
["sign", "verify"]
|
|
@@ -1892,7 +1920,7 @@ var init_cryptography_service = __esm({
|
|
|
1892
1920
|
signingAlgorithm: { name: "ECDSA", hash: "SHA-256" }
|
|
1893
1921
|
});
|
|
1894
1922
|
const csrDer = new Uint8Array(csr.rawData);
|
|
1895
|
-
const pkcs8 = await
|
|
1923
|
+
const pkcs8 = await crypto2.webcrypto.subtle.exportKey("pkcs8", keys.privateKey);
|
|
1896
1924
|
const privateKeyPem = pemEncode(new Uint8Array(pkcs8), "PRIVATE KEY");
|
|
1897
1925
|
return { csrDer, privateKeyPem };
|
|
1898
1926
|
}
|
|
@@ -1901,7 +1929,7 @@ var init_cryptography_service = __esm({
|
|
|
1901
1929
|
// ---------------------------------------------------------------------------
|
|
1902
1930
|
/** Parse a PEM-encoded private key into a Node.js KeyObject. */
|
|
1903
1931
|
parsePrivateKey(pem) {
|
|
1904
|
-
return
|
|
1932
|
+
return crypto2.createPrivateKey(pem);
|
|
1905
1933
|
}
|
|
1906
1934
|
// ---------------------------------------------------------------------------
|
|
1907
1935
|
// Private helpers
|
|
@@ -1909,11 +1937,11 @@ var init_cryptography_service = __esm({
|
|
|
1909
1937
|
/** RSA-OAEP SHA-256 encryption. */
|
|
1910
1938
|
encryptRsaOaep(certPem, plaintext) {
|
|
1911
1939
|
return new Uint8Array(
|
|
1912
|
-
|
|
1940
|
+
crypto2.publicEncrypt(
|
|
1913
1941
|
{
|
|
1914
1942
|
key: certPem,
|
|
1915
1943
|
oaepHash: "sha256",
|
|
1916
|
-
padding:
|
|
1944
|
+
padding: crypto2.constants.RSA_PKCS1_OAEP_PADDING
|
|
1917
1945
|
},
|
|
1918
1946
|
plaintext
|
|
1919
1947
|
)
|
|
@@ -1930,15 +1958,15 @@ var init_cryptography_service = __esm({
|
|
|
1930
1958
|
* (Java-compatible — GCM appends the 16-byte tag to the ciphertext).
|
|
1931
1959
|
*/
|
|
1932
1960
|
encryptEcdhAesGcm(receiverPublicKey, plaintext) {
|
|
1933
|
-
const { privateKey: ephPrivKey, publicKey: ephPubKey } =
|
|
1961
|
+
const { privateKey: ephPrivKey, publicKey: ephPubKey } = crypto2.generateKeyPairSync("ec", {
|
|
1934
1962
|
namedCurve: "prime256v1"
|
|
1935
1963
|
});
|
|
1936
|
-
const sharedSecret =
|
|
1964
|
+
const sharedSecret = crypto2.diffieHellman({
|
|
1937
1965
|
privateKey: ephPrivKey,
|
|
1938
1966
|
publicKey: receiverPublicKey
|
|
1939
1967
|
});
|
|
1940
|
-
const nonce =
|
|
1941
|
-
const cipher =
|
|
1968
|
+
const nonce = crypto2.randomBytes(12);
|
|
1969
|
+
const cipher = crypto2.createCipheriv("aes-256-gcm", sharedSecret, nonce);
|
|
1942
1970
|
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
1943
1971
|
const tag = cipher.getAuthTag();
|
|
1944
1972
|
const ephemeralSpki = ephPubKey.export({ type: "spki", format: "der" });
|
|
@@ -6489,7 +6517,7 @@ var signature_service_exports = {};
|
|
|
6489
6517
|
__export(signature_service_exports, {
|
|
6490
6518
|
SignatureService: () => SignatureService
|
|
6491
6519
|
});
|
|
6492
|
-
import * as
|
|
6520
|
+
import * as crypto3 from "crypto";
|
|
6493
6521
|
import { ExclusiveCanonicalization } from "xml-crypto";
|
|
6494
6522
|
function extractDerFromPem(pem) {
|
|
6495
6523
|
const base64 = pem.replace(/-----BEGIN [A-Z\s]+-----/g, "").replace(/-----END [A-Z\s]+-----/g, "").replace(/\s+/g, "");
|
|
@@ -6508,7 +6536,7 @@ function canonicalize(elem) {
|
|
|
6508
6536
|
function computeRootDigest(doc) {
|
|
6509
6537
|
const root = doc.documentElement;
|
|
6510
6538
|
const canonical = canonicalize(root);
|
|
6511
|
-
return
|
|
6539
|
+
return crypto3.createHash("sha256").update(canonical, "utf-8").digest("base64");
|
|
6512
6540
|
}
|
|
6513
6541
|
function computeSignedPropertiesDigest(qualifyingPropertiesXml) {
|
|
6514
6542
|
const parser = new import_xmldom.DOMParser();
|
|
@@ -6518,7 +6546,7 @@ function computeSignedPropertiesDigest(qualifyingPropertiesXml) {
|
|
|
6518
6546
|
throw new Error("SignedProperties element not found in QualifyingProperties");
|
|
6519
6547
|
}
|
|
6520
6548
|
const canonical = canonicalize(signedProps);
|
|
6521
|
-
return
|
|
6549
|
+
return crypto3.createHash("sha256").update(canonical, "utf-8").digest("base64");
|
|
6522
6550
|
}
|
|
6523
6551
|
function buildSignedInfo(signatureAlgorithm, rootDigest, signedPropertiesDigest) {
|
|
6524
6552
|
return [
|
|
@@ -6549,12 +6577,12 @@ function computeSignatureValue(canonicalSignedInfo, privateKeyPem, isEc) {
|
|
|
6549
6577
|
const data = Buffer.from(canonicalSignedInfo, "utf-8");
|
|
6550
6578
|
let signature;
|
|
6551
6579
|
if (isEc) {
|
|
6552
|
-
signature =
|
|
6580
|
+
signature = crypto3.sign("sha256", data, {
|
|
6553
6581
|
key: privateKeyPem,
|
|
6554
6582
|
dsaEncoding: "ieee-p1363"
|
|
6555
6583
|
});
|
|
6556
6584
|
} else {
|
|
6557
|
-
signature =
|
|
6585
|
+
signature = crypto3.sign("sha256", data, privateKeyPem);
|
|
6558
6586
|
}
|
|
6559
6587
|
return signature.toString("base64");
|
|
6560
6588
|
}
|
|
@@ -6654,11 +6682,11 @@ var init_signature_service = __esm({
|
|
|
6654
6682
|
}
|
|
6655
6683
|
const certDer = extractDerFromPem(certPem);
|
|
6656
6684
|
const certBase64 = certDer.toString("base64");
|
|
6657
|
-
const certDigest =
|
|
6658
|
-
const x5093 = new
|
|
6685
|
+
const certDigest = crypto3.createHash("sha256").update(certDer).digest("base64");
|
|
6686
|
+
const x5093 = new crypto3.X509Certificate(certPem);
|
|
6659
6687
|
const issuerName = normalizeIssuerDn(x5093.issuer);
|
|
6660
6688
|
const serialNumber = hexSerialToDecimal(x5093.serialNumber);
|
|
6661
|
-
const privateKey =
|
|
6689
|
+
const privateKey = crypto3.createPrivateKey(privateKeyPem);
|
|
6662
6690
|
const isEc = privateKey.asymmetricKeyType === "ec";
|
|
6663
6691
|
const signatureAlgorithm = isEc ? ECDSA_SHA256_SIGNATURE : RSA_SHA256_SIGNATURE;
|
|
6664
6692
|
const signingTime = new Date(Date.now() + CLOCK_SKEW_BUFFER_MS).toISOString();
|
|
@@ -6762,7 +6790,7 @@ var init_pkcs12_loader = __esm({
|
|
|
6762
6790
|
});
|
|
6763
6791
|
|
|
6764
6792
|
// src/qr/verification-link-service.ts
|
|
6765
|
-
import
|
|
6793
|
+
import crypto5 from "crypto";
|
|
6766
6794
|
var VerificationLinkService;
|
|
6767
6795
|
var init_verification_link_service = __esm({
|
|
6768
6796
|
"src/qr/verification-link-service.ts"() {
|
|
@@ -6792,16 +6820,16 @@ var init_verification_link_service = __esm({
|
|
|
6792
6820
|
const hashBase64Url = this.base64ToBase64Url(invoiceHashBase64);
|
|
6793
6821
|
const pathWithoutSignature = `${this.baseQrUrl}/certificate/${contextType}/${contextId}/${sellerNip}/${certSerial}/${hashBase64Url}`;
|
|
6794
6822
|
const dataToSign = pathWithoutSignature.replace(/^https?:\/\//, "");
|
|
6795
|
-
const key =
|
|
6823
|
+
const key = crypto5.createPrivateKey(privateKeyPem);
|
|
6796
6824
|
let signature;
|
|
6797
6825
|
if (key.asymmetricKeyType === "rsa") {
|
|
6798
|
-
signature =
|
|
6826
|
+
signature = crypto5.sign("sha256", Buffer.from(dataToSign), {
|
|
6799
6827
|
key,
|
|
6800
|
-
padding:
|
|
6828
|
+
padding: crypto5.constants.RSA_PKCS1_PSS_PADDING,
|
|
6801
6829
|
saltLength: 32
|
|
6802
6830
|
});
|
|
6803
6831
|
} else if (key.asymmetricKeyType === "ec") {
|
|
6804
|
-
signature =
|
|
6832
|
+
signature = crypto5.sign("sha256", Buffer.from(dataToSign), {
|
|
6805
6833
|
key,
|
|
6806
6834
|
dsaEncoding: "ieee-p1363"
|
|
6807
6835
|
});
|
|
@@ -6933,7 +6961,7 @@ var init_client = __esm({
|
|
|
6933
6961
|
this.lighthouse = new LighthouseService(this.options);
|
|
6934
6962
|
this.limits = new LimitsService(restClient);
|
|
6935
6963
|
this.peppol = new PeppolService(restClient);
|
|
6936
|
-
this.testData = new TestDataService(restClient);
|
|
6964
|
+
this.testData = new TestDataService(restClient, this.options.environmentName);
|
|
6937
6965
|
this.qr = new VerificationLinkService(this.options.baseQrUrl);
|
|
6938
6966
|
}
|
|
6939
6967
|
async loginWithToken(token, nip) {
|
|
@@ -7480,18 +7508,86 @@ var AuthorizationPermissionGrantBuilder = class {
|
|
|
7480
7508
|
}
|
|
7481
7509
|
};
|
|
7482
7510
|
|
|
7511
|
+
// src/builders/batch-file.ts
|
|
7512
|
+
init_ksef_validation_error();
|
|
7513
|
+
import * as crypto from "crypto";
|
|
7514
|
+
var BATCH_MAX_PART_SIZE = 1e8;
|
|
7515
|
+
var BATCH_MAX_TOTAL_SIZE = 5e9;
|
|
7516
|
+
var BATCH_MAX_PARTS = 50;
|
|
7517
|
+
var BatchFileBuilder = class {
|
|
7518
|
+
/**
|
|
7519
|
+
* Build batch file metadata and encrypted parts from a raw ZIP.
|
|
7520
|
+
*
|
|
7521
|
+
* @param zipBytes - Unencrypted ZIP data
|
|
7522
|
+
* @param encryptFn - AES-256-CBC encryption function (called per part)
|
|
7523
|
+
* @param options - Optional configuration
|
|
7524
|
+
*/
|
|
7525
|
+
static build(zipBytes, encryptFn, options) {
|
|
7526
|
+
const maxPartSize = options?.maxPartSize ?? BATCH_MAX_PART_SIZE;
|
|
7527
|
+
if (maxPartSize <= 0) {
|
|
7528
|
+
throw new KSeFValidationError("maxPartSize must be a positive number");
|
|
7529
|
+
}
|
|
7530
|
+
if (zipBytes.length === 0) {
|
|
7531
|
+
throw new KSeFValidationError("ZIP data must not be empty");
|
|
7532
|
+
}
|
|
7533
|
+
if (zipBytes.length > BATCH_MAX_TOTAL_SIZE) {
|
|
7534
|
+
throw new KSeFValidationError(
|
|
7535
|
+
`ZIP size ${zipBytes.length} exceeds maximum of ${BATCH_MAX_TOTAL_SIZE} bytes (5 GB)`
|
|
7536
|
+
);
|
|
7537
|
+
}
|
|
7538
|
+
const rawParts = splitBuffer(zipBytes, maxPartSize);
|
|
7539
|
+
if (rawParts.length > BATCH_MAX_PARTS) {
|
|
7540
|
+
throw new KSeFValidationError(
|
|
7541
|
+
`Data requires ${rawParts.length} parts, exceeding maximum of ${BATCH_MAX_PARTS}`
|
|
7542
|
+
);
|
|
7543
|
+
}
|
|
7544
|
+
const zipHash = sha256Base64(zipBytes);
|
|
7545
|
+
const encryptedParts = [];
|
|
7546
|
+
const fileParts = rawParts.map((raw, i) => {
|
|
7547
|
+
const encrypted = encryptFn(raw);
|
|
7548
|
+
encryptedParts.push(encrypted);
|
|
7549
|
+
return {
|
|
7550
|
+
ordinalNumber: i + 1,
|
|
7551
|
+
fileSize: encrypted.length,
|
|
7552
|
+
fileHash: sha256Base64(encrypted)
|
|
7553
|
+
};
|
|
7554
|
+
});
|
|
7555
|
+
return {
|
|
7556
|
+
batchFile: {
|
|
7557
|
+
fileSize: zipBytes.length,
|
|
7558
|
+
fileHash: zipHash,
|
|
7559
|
+
fileParts
|
|
7560
|
+
},
|
|
7561
|
+
encryptedParts
|
|
7562
|
+
};
|
|
7563
|
+
}
|
|
7564
|
+
};
|
|
7565
|
+
function splitBuffer(data, maxPartSize) {
|
|
7566
|
+
if (data.length <= maxPartSize) {
|
|
7567
|
+
return [data];
|
|
7568
|
+
}
|
|
7569
|
+
const parts = [];
|
|
7570
|
+
for (let offset = 0; offset < data.length; offset += maxPartSize) {
|
|
7571
|
+
parts.push(data.subarray(offset, Math.min(offset + maxPartSize, data.length)));
|
|
7572
|
+
}
|
|
7573
|
+
return parts;
|
|
7574
|
+
}
|
|
7575
|
+
function sha256Base64(data) {
|
|
7576
|
+
return crypto.createHash("sha256").update(data).digest("base64");
|
|
7577
|
+
}
|
|
7578
|
+
|
|
7483
7579
|
// src/crypto/index.ts
|
|
7484
7580
|
init_certificate_fetcher();
|
|
7485
7581
|
init_cryptography_service();
|
|
7486
7582
|
init_signature_service();
|
|
7487
7583
|
|
|
7488
7584
|
// src/crypto/certificate-service.ts
|
|
7489
|
-
import * as
|
|
7585
|
+
import * as crypto4 from "crypto";
|
|
7490
7586
|
import * as x5092 from "@peculiar/x509";
|
|
7491
7587
|
var CertificateService = class {
|
|
7492
7588
|
static getSha256Fingerprint(certPem) {
|
|
7493
7589
|
const der = extractDerFromPem2(certPem);
|
|
7494
|
-
return
|
|
7590
|
+
return crypto4.createHash("sha256").update(der).digest("hex").toUpperCase();
|
|
7495
7591
|
}
|
|
7496
7592
|
static async generatePersonalCertificate(givenName, surname, serialNumber, commonName, method = "RSA") {
|
|
7497
7593
|
const nameParts = [];
|
|
@@ -7514,7 +7610,7 @@ var CertificateService = class {
|
|
|
7514
7610
|
}
|
|
7515
7611
|
};
|
|
7516
7612
|
async function generateSelfSigned(subject, method) {
|
|
7517
|
-
x5092.cryptoProvider.set(
|
|
7613
|
+
x5092.cryptoProvider.set(crypto4.webcrypto);
|
|
7518
7614
|
let algorithm;
|
|
7519
7615
|
let signingAlgorithm;
|
|
7520
7616
|
if (method === "ECDSA") {
|
|
@@ -7529,7 +7625,7 @@ async function generateSelfSigned(subject, method) {
|
|
|
7529
7625
|
};
|
|
7530
7626
|
signingAlgorithm = algorithm;
|
|
7531
7627
|
}
|
|
7532
|
-
const keys = await
|
|
7628
|
+
const keys = await crypto4.webcrypto.subtle.generateKey(
|
|
7533
7629
|
algorithm,
|
|
7534
7630
|
true,
|
|
7535
7631
|
["sign", "verify"]
|
|
@@ -7546,9 +7642,9 @@ async function generateSelfSigned(subject, method) {
|
|
|
7546
7642
|
serialNumber: Date.now().toString(16)
|
|
7547
7643
|
});
|
|
7548
7644
|
const certPem = cert.toString("pem");
|
|
7549
|
-
const pkcs8 = await
|
|
7645
|
+
const pkcs8 = await crypto4.webcrypto.subtle.exportKey("pkcs8", keys.privateKey);
|
|
7550
7646
|
const privateKeyPem = pemEncode2(new Uint8Array(pkcs8), "PRIVATE KEY");
|
|
7551
|
-
const fingerprint =
|
|
7647
|
+
const fingerprint = crypto4.createHash("sha256").update(Buffer.from(cert.rawData)).digest("hex").toUpperCase();
|
|
7552
7648
|
return { certificatePem: certPem, privateKeyPem, fingerprint };
|
|
7553
7649
|
}
|
|
7554
7650
|
function extractDerFromPem2(pem) {
|
|
@@ -7682,7 +7778,7 @@ async function openOnlineSession(client, options) {
|
|
|
7682
7778
|
async waitForUpo(pollOpts) {
|
|
7683
7779
|
const result = await pollUntil(
|
|
7684
7780
|
() => client.sessionStatus.getSessionStatus(sessionRef),
|
|
7685
|
-
(s) => s.status.code
|
|
7781
|
+
(s) => s.status.code === 200 || s.status.code >= 400,
|
|
7686
7782
|
{ ...pollOpts, description: `UPO for session ${sessionRef}` }
|
|
7687
7783
|
);
|
|
7688
7784
|
if (result.status.code !== 200) {
|
|
@@ -7708,31 +7804,36 @@ async function openSendAndClose(client, invoices, options) {
|
|
|
7708
7804
|
|
|
7709
7805
|
// src/workflows/batch-session-workflow.ts
|
|
7710
7806
|
var DEFAULT_FORM_CODE2 = { systemCode: "FA", schemaVersion: "3", value: "FA (3)" };
|
|
7711
|
-
async function uploadBatch(client,
|
|
7807
|
+
async function uploadBatch(client, zipData, options) {
|
|
7712
7808
|
await client.crypto.init();
|
|
7713
7809
|
const encData = client.crypto.getEncryptionData();
|
|
7714
7810
|
const formCode = options?.formCode ?? DEFAULT_FORM_CODE2;
|
|
7715
|
-
const
|
|
7716
|
-
|
|
7717
|
-
|
|
7811
|
+
const encryptFn = (part) => client.crypto.encryptAES256(part, encData.cipherKey, encData.cipherIv);
|
|
7812
|
+
const { batchFile, encryptedParts } = BatchFileBuilder.build(zipData, encryptFn, {
|
|
7813
|
+
maxPartSize: options?.maxPartSize
|
|
7718
7814
|
});
|
|
7719
7815
|
const openResp = await client.batchSession.openSession(
|
|
7720
7816
|
{
|
|
7721
7817
|
formCode,
|
|
7722
7818
|
encryption: encData.encryptionInfo,
|
|
7723
|
-
batchFile
|
|
7819
|
+
batchFile,
|
|
7820
|
+
offlineMode: options?.offlineMode
|
|
7724
7821
|
},
|
|
7725
7822
|
options?.upoVersion
|
|
7726
7823
|
);
|
|
7727
|
-
const sendingParts =
|
|
7728
|
-
|
|
7729
|
-
|
|
7730
|
-
|
|
7824
|
+
const sendingParts = encryptedParts.map((part, i) => ({
|
|
7825
|
+
data: part.buffer.slice(part.byteOffset, part.byteOffset + part.byteLength),
|
|
7826
|
+
metadata: {
|
|
7827
|
+
hashSHA: batchFile.fileParts[i].fileHash,
|
|
7828
|
+
fileSize: batchFile.fileParts[i].fileSize
|
|
7829
|
+
},
|
|
7830
|
+
ordinalNumber: i + 1
|
|
7831
|
+
}));
|
|
7731
7832
|
await client.batchSession.sendParts(openResp, sendingParts);
|
|
7732
7833
|
await client.batchSession.closeSession(openResp.referenceNumber);
|
|
7733
7834
|
const result = await pollUntil(
|
|
7734
7835
|
() => client.sessionStatus.getSessionStatus(openResp.referenceNumber),
|
|
7735
|
-
(s) => s.status.code
|
|
7836
|
+
(s) => s.status.code === 200 || s.status.code >= 400,
|
|
7736
7837
|
{ ...options?.pollOptions, description: `UPO for batch ${openResp.referenceNumber}` }
|
|
7737
7838
|
);
|
|
7738
7839
|
if (result.status.code !== 200) {
|
|
@@ -7750,7 +7851,7 @@ async function uploadBatch(client, zipParts, totalFileSize, totalFileHash, optio
|
|
|
7750
7851
|
}
|
|
7751
7852
|
|
|
7752
7853
|
// src/workflows/invoice-export-workflow.ts
|
|
7753
|
-
async function
|
|
7854
|
+
async function doExport(client, filters, options) {
|
|
7754
7855
|
await client.crypto.init();
|
|
7755
7856
|
const encData = client.crypto.getEncryptionData();
|
|
7756
7857
|
const opResp = await client.invoices.exportInvoices({
|
|
@@ -7760,7 +7861,7 @@ async function exportInvoices(client, filters, options) {
|
|
|
7760
7861
|
});
|
|
7761
7862
|
const result = await pollUntil(
|
|
7762
7863
|
() => client.invoices.getInvoiceExportStatus(opResp.referenceNumber),
|
|
7763
|
-
(s) => s.status.code
|
|
7864
|
+
(s) => s.status.code === 200 || s.status.code >= 400,
|
|
7764
7865
|
{ ...options?.pollOptions, description: `export ${opResp.referenceNumber}` }
|
|
7765
7866
|
);
|
|
7766
7867
|
if (result.status.code !== 200) {
|
|
@@ -7770,23 +7871,29 @@ async function exportInvoices(client, filters, options) {
|
|
|
7770
7871
|
throw new Error("Export completed but no package available");
|
|
7771
7872
|
}
|
|
7772
7873
|
return {
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
|
|
7780
|
-
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
|
|
7784
|
-
|
|
7874
|
+
encData,
|
|
7875
|
+
result: {
|
|
7876
|
+
parts: result.package.parts.map((p) => ({
|
|
7877
|
+
ordinalNumber: p.ordinalNumber,
|
|
7878
|
+
url: p.url,
|
|
7879
|
+
method: p.method,
|
|
7880
|
+
partSize: p.partSize,
|
|
7881
|
+
encryptedPartSize: p.encryptedPartSize,
|
|
7882
|
+
encryptedPartHash: p.encryptedPartHash,
|
|
7883
|
+
expirationDate: p.expirationDate
|
|
7884
|
+
})),
|
|
7885
|
+
invoiceCount: result.package.invoiceCount,
|
|
7886
|
+
isTruncated: result.package.isTruncated,
|
|
7887
|
+
permanentStorageHwmDate: result.package.permanentStorageHwmDate
|
|
7888
|
+
}
|
|
7785
7889
|
};
|
|
7786
7890
|
}
|
|
7891
|
+
async function exportInvoices(client, filters, options) {
|
|
7892
|
+
const { result } = await doExport(client, filters, options);
|
|
7893
|
+
return result;
|
|
7894
|
+
}
|
|
7787
7895
|
async function exportAndDownload(client, filters, options) {
|
|
7788
|
-
const encData = client
|
|
7789
|
-
const exportResult = await exportInvoices(client, filters, options);
|
|
7896
|
+
const { result: exportResult, encData } = await doExport(client, filters, options);
|
|
7790
7897
|
const download = options?.transport ?? fetch;
|
|
7791
7898
|
const decryptedParts = [];
|
|
7792
7899
|
for (const part of exportResult.parts) {
|
|
@@ -7879,7 +7986,11 @@ export {
|
|
|
7879
7986
|
AuthService,
|
|
7880
7987
|
AuthTokenRequestBuilder,
|
|
7881
7988
|
AuthorizationPermissionGrantBuilder,
|
|
7989
|
+
BATCH_MAX_PARTS,
|
|
7990
|
+
BATCH_MAX_PART_SIZE,
|
|
7991
|
+
BATCH_MAX_TOTAL_SIZE,
|
|
7882
7992
|
Base64String,
|
|
7993
|
+
BatchFileBuilder,
|
|
7883
7994
|
BatchSessionService,
|
|
7884
7995
|
CERTIFICATE_NAME_MAX_LENGTH,
|
|
7885
7996
|
CERTIFICATE_NAME_MIN_LENGTH,
|