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.cjs
CHANGED
|
@@ -67,7 +67,8 @@ function resolveOptions(options = {}) {
|
|
|
67
67
|
lighthouseUrl: options.lighthouseUrl ?? env.lighthouseUrl,
|
|
68
68
|
apiVersion: options.apiVersion ?? DEFAULT_API_VERSION,
|
|
69
69
|
timeout: options.timeout ?? DEFAULT_TIMEOUT,
|
|
70
|
-
customHeaders: options.customHeaders ?? {}
|
|
70
|
+
customHeaders: options.customHeaders ?? {},
|
|
71
|
+
environmentName: options.environment ?? (options.baseUrl ? void 0 : "TEST")
|
|
71
72
|
};
|
|
72
73
|
}
|
|
73
74
|
var DEFAULT_API_VERSION, DEFAULT_TIMEOUT;
|
|
@@ -1575,84 +1576,111 @@ var init_test_data = __esm({
|
|
|
1575
1576
|
"use strict";
|
|
1576
1577
|
init_rest_request();
|
|
1577
1578
|
init_routes();
|
|
1579
|
+
init_ksef_error();
|
|
1578
1580
|
TestDataService = class {
|
|
1579
1581
|
restClient;
|
|
1580
|
-
|
|
1582
|
+
environmentName;
|
|
1583
|
+
constructor(restClient, environmentName) {
|
|
1581
1584
|
this.restClient = restClient;
|
|
1585
|
+
this.environmentName = environmentName;
|
|
1586
|
+
}
|
|
1587
|
+
ensureTestEnvironment() {
|
|
1588
|
+
if (this.environmentName && this.environmentName !== "TEST") {
|
|
1589
|
+
throw new KSeFError(
|
|
1590
|
+
`Test data APIs are only available on the TEST environment (current: ${this.environmentName})`
|
|
1591
|
+
);
|
|
1592
|
+
}
|
|
1582
1593
|
}
|
|
1583
1594
|
// Subject management
|
|
1584
1595
|
async createSubject(request) {
|
|
1596
|
+
this.ensureTestEnvironment();
|
|
1585
1597
|
const req = RestRequest.post(Routes.TestData.createSubject).body(request);
|
|
1586
1598
|
await this.restClient.executeVoid(req);
|
|
1587
1599
|
}
|
|
1588
1600
|
async removeSubject(request) {
|
|
1601
|
+
this.ensureTestEnvironment();
|
|
1589
1602
|
const req = RestRequest.post(Routes.TestData.removeSubject).body(request);
|
|
1590
1603
|
await this.restClient.executeVoid(req);
|
|
1591
1604
|
}
|
|
1592
1605
|
// Person management
|
|
1593
1606
|
async createPerson(request) {
|
|
1607
|
+
this.ensureTestEnvironment();
|
|
1594
1608
|
const req = RestRequest.post(Routes.TestData.createPerson).body(request);
|
|
1595
1609
|
await this.restClient.executeVoid(req);
|
|
1596
1610
|
}
|
|
1597
1611
|
async removePerson(request) {
|
|
1612
|
+
this.ensureTestEnvironment();
|
|
1598
1613
|
const req = RestRequest.post(Routes.TestData.removePerson).body(request);
|
|
1599
1614
|
await this.restClient.executeVoid(req);
|
|
1600
1615
|
}
|
|
1601
1616
|
// Permissions
|
|
1602
1617
|
async grantPermissions(request) {
|
|
1618
|
+
this.ensureTestEnvironment();
|
|
1603
1619
|
const req = RestRequest.post(Routes.TestData.grantPerms).body(request);
|
|
1604
1620
|
await this.restClient.executeVoid(req);
|
|
1605
1621
|
}
|
|
1606
1622
|
async revokePermissions(request) {
|
|
1623
|
+
this.ensureTestEnvironment();
|
|
1607
1624
|
const req = RestRequest.post(Routes.TestData.revokePerms).body(request);
|
|
1608
1625
|
await this.restClient.executeVoid(req);
|
|
1609
1626
|
}
|
|
1610
1627
|
// Attachment permissions
|
|
1611
1628
|
async enableAttachment(request) {
|
|
1629
|
+
this.ensureTestEnvironment();
|
|
1612
1630
|
const req = RestRequest.post(Routes.TestData.enableAttach).body(request);
|
|
1613
1631
|
await this.restClient.executeVoid(req);
|
|
1614
1632
|
}
|
|
1615
1633
|
async disableAttachment(request) {
|
|
1634
|
+
this.ensureTestEnvironment();
|
|
1616
1635
|
const req = RestRequest.post(Routes.TestData.disableAttach).body(request);
|
|
1617
1636
|
await this.restClient.executeVoid(req);
|
|
1618
1637
|
}
|
|
1619
1638
|
// Session limits
|
|
1620
1639
|
async changeSessionLimits(request) {
|
|
1640
|
+
this.ensureTestEnvironment();
|
|
1621
1641
|
const req = RestRequest.post(Routes.TestData.changeSessionLimitsInCurrentContext).body(request);
|
|
1622
1642
|
await this.restClient.executeVoid(req);
|
|
1623
1643
|
}
|
|
1624
1644
|
async restoreDefaultSessionLimits() {
|
|
1645
|
+
this.ensureTestEnvironment();
|
|
1625
1646
|
const req = RestRequest.delete(Routes.TestData.restoreDefaultSessionLimitsInCurrentContext);
|
|
1626
1647
|
await this.restClient.executeVoid(req);
|
|
1627
1648
|
}
|
|
1628
1649
|
// Certificate limits
|
|
1629
1650
|
async changeCertificatesLimit(request) {
|
|
1651
|
+
this.ensureTestEnvironment();
|
|
1630
1652
|
const req = RestRequest.post(Routes.TestData.changeCertificatesLimitInCurrentSubject).body(request);
|
|
1631
1653
|
await this.restClient.executeVoid(req);
|
|
1632
1654
|
}
|
|
1633
1655
|
async restoreDefaultCertificatesLimit() {
|
|
1656
|
+
this.ensureTestEnvironment();
|
|
1634
1657
|
const req = RestRequest.delete(Routes.TestData.restoreDefaultCertificatesLimitInCurrentSubject);
|
|
1635
1658
|
await this.restClient.executeVoid(req);
|
|
1636
1659
|
}
|
|
1637
1660
|
// Rate limits
|
|
1638
1661
|
async setRateLimits(request) {
|
|
1662
|
+
this.ensureTestEnvironment();
|
|
1639
1663
|
const req = RestRequest.post(Routes.TestData.rateLimits).body(request);
|
|
1640
1664
|
await this.restClient.executeVoid(req);
|
|
1641
1665
|
}
|
|
1642
1666
|
async restoreDefaultRateLimits() {
|
|
1667
|
+
this.ensureTestEnvironment();
|
|
1643
1668
|
const req = RestRequest.delete(Routes.TestData.rateLimits);
|
|
1644
1669
|
await this.restClient.executeVoid(req);
|
|
1645
1670
|
}
|
|
1646
1671
|
async setProductionRateLimits() {
|
|
1672
|
+
this.ensureTestEnvironment();
|
|
1647
1673
|
const req = RestRequest.post(Routes.TestData.productionRateLimits);
|
|
1648
1674
|
await this.restClient.executeVoid(req);
|
|
1649
1675
|
}
|
|
1650
1676
|
// Context blocking
|
|
1651
1677
|
async blockContext(request) {
|
|
1678
|
+
this.ensureTestEnvironment();
|
|
1652
1679
|
const req = RestRequest.post(Routes.TestData.blockContext).body(request);
|
|
1653
1680
|
await this.restClient.executeVoid(req);
|
|
1654
1681
|
}
|
|
1655
1682
|
async unblockContext(request) {
|
|
1683
|
+
this.ensureTestEnvironment();
|
|
1656
1684
|
const req = RestRequest.post(Routes.TestData.unblockContext).body(request);
|
|
1657
1685
|
await this.restClient.executeVoid(req);
|
|
1658
1686
|
}
|
|
@@ -1730,7 +1758,7 @@ ${lines.join("\n")}
|
|
|
1730
1758
|
|
|
1731
1759
|
// src/crypto/cryptography-service.ts
|
|
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 = [];
|
|
@@ -1754,11 +1782,11 @@ function pemEncode(der, label) {
|
|
|
1754
1782
|
${lines.join("\n")}
|
|
1755
1783
|
-----END ${label}-----`;
|
|
1756
1784
|
}
|
|
1757
|
-
var
|
|
1785
|
+
var crypto2, x509, CryptographyService;
|
|
1758
1786
|
var init_cryptography_service = __esm({
|
|
1759
1787
|
"src/crypto/cryptography-service.ts"() {
|
|
1760
1788
|
"use strict";
|
|
1761
|
-
|
|
1789
|
+
crypto2 = __toESM(require("crypto"), 1);
|
|
1762
1790
|
x509 = __toESM(require("@peculiar/x509"), 1);
|
|
1763
1791
|
CryptographyService = class {
|
|
1764
1792
|
fetcher;
|
|
@@ -1774,12 +1802,12 @@ var init_cryptography_service = __esm({
|
|
|
1774
1802
|
// ---------------------------------------------------------------------------
|
|
1775
1803
|
/** Encrypt with AES-256-CBC (PKCS7 padding is automatic in Node). */
|
|
1776
1804
|
encryptAES256(content, key, iv) {
|
|
1777
|
-
const cipher =
|
|
1805
|
+
const cipher = crypto2.createCipheriv("aes-256-cbc", key, iv);
|
|
1778
1806
|
return new Uint8Array(Buffer.concat([cipher.update(content), cipher.final()]));
|
|
1779
1807
|
}
|
|
1780
1808
|
/** Decrypt with AES-256-CBC. */
|
|
1781
1809
|
decryptAES256(content, key, iv) {
|
|
1782
|
-
const decipher =
|
|
1810
|
+
const decipher = crypto2.createDecipheriv("aes-256-cbc", key, iv);
|
|
1783
1811
|
return new Uint8Array(Buffer.concat([decipher.update(content), decipher.final()]));
|
|
1784
1812
|
}
|
|
1785
1813
|
// ---------------------------------------------------------------------------
|
|
@@ -1790,14 +1818,14 @@ var init_cryptography_service = __esm({
|
|
|
1790
1818
|
* SymmetricKeyEncryption certificate's RSA public key (RSA-OAEP SHA-256).
|
|
1791
1819
|
*/
|
|
1792
1820
|
getEncryptionData() {
|
|
1793
|
-
const key =
|
|
1794
|
-
const iv =
|
|
1821
|
+
const key = crypto2.randomBytes(32);
|
|
1822
|
+
const iv = crypto2.randomBytes(16);
|
|
1795
1823
|
const certPem = this.fetcher.getSymmetricKeyEncryptionPem();
|
|
1796
|
-
const encryptedKey =
|
|
1824
|
+
const encryptedKey = crypto2.publicEncrypt(
|
|
1797
1825
|
{
|
|
1798
1826
|
key: certPem,
|
|
1799
1827
|
oaepHash: "sha256",
|
|
1800
|
-
padding:
|
|
1828
|
+
padding: crypto2.constants.RSA_PKCS1_OAEP_PADDING
|
|
1801
1829
|
},
|
|
1802
1830
|
key
|
|
1803
1831
|
);
|
|
@@ -1831,7 +1859,7 @@ var init_cryptography_service = __esm({
|
|
|
1831
1859
|
const timestampMs = new Date(challengeTimestamp).getTime();
|
|
1832
1860
|
const plaintext = Buffer.from(`${token}|${timestampMs}`, "utf-8");
|
|
1833
1861
|
const certPem = this.fetcher.getKsefTokenEncryptionPem();
|
|
1834
|
-
const cert = new
|
|
1862
|
+
const cert = new crypto2.X509Certificate(certPem);
|
|
1835
1863
|
const publicKey = cert.publicKey;
|
|
1836
1864
|
if (publicKey.asymmetricKeyType === "rsa") {
|
|
1837
1865
|
return this.encryptRsaOaep(certPem, plaintext);
|
|
@@ -1846,7 +1874,7 @@ var init_cryptography_service = __esm({
|
|
|
1846
1874
|
// ---------------------------------------------------------------------------
|
|
1847
1875
|
/** Compute SHA-256 hash (base64) and byte length. */
|
|
1848
1876
|
getFileMetadata(file) {
|
|
1849
|
-
const hash =
|
|
1877
|
+
const hash = crypto2.createHash("sha256").update(file).digest("base64");
|
|
1850
1878
|
return { hashSHA: hash, fileSize: file.length };
|
|
1851
1879
|
}
|
|
1852
1880
|
// ---------------------------------------------------------------------------
|
|
@@ -1861,7 +1889,7 @@ var init_cryptography_service = __esm({
|
|
|
1861
1889
|
publicExponent: new Uint8Array([1, 0, 1]),
|
|
1862
1890
|
modulusLength: 2048
|
|
1863
1891
|
};
|
|
1864
|
-
const keys = await
|
|
1892
|
+
const keys = await crypto2.webcrypto.subtle.generateKey(
|
|
1865
1893
|
algorithm,
|
|
1866
1894
|
true,
|
|
1867
1895
|
["sign", "verify"]
|
|
@@ -1872,7 +1900,7 @@ var init_cryptography_service = __esm({
|
|
|
1872
1900
|
signingAlgorithm: algorithm
|
|
1873
1901
|
});
|
|
1874
1902
|
const csrDer = new Uint8Array(csr.rawData);
|
|
1875
|
-
const pkcs8 = await
|
|
1903
|
+
const pkcs8 = await crypto2.webcrypto.subtle.exportKey("pkcs8", keys.privateKey);
|
|
1876
1904
|
const privateKeyPem = pemEncode(new Uint8Array(pkcs8), "PRIVATE KEY");
|
|
1877
1905
|
return { csrDer, privateKeyPem };
|
|
1878
1906
|
}
|
|
@@ -1883,7 +1911,7 @@ var init_cryptography_service = __esm({
|
|
|
1883
1911
|
name: "ECDSA",
|
|
1884
1912
|
namedCurve: "P-256"
|
|
1885
1913
|
};
|
|
1886
|
-
const keys = await
|
|
1914
|
+
const keys = await crypto2.webcrypto.subtle.generateKey(
|
|
1887
1915
|
algorithm,
|
|
1888
1916
|
true,
|
|
1889
1917
|
["sign", "verify"]
|
|
@@ -1894,7 +1922,7 @@ var init_cryptography_service = __esm({
|
|
|
1894
1922
|
signingAlgorithm: { name: "ECDSA", hash: "SHA-256" }
|
|
1895
1923
|
});
|
|
1896
1924
|
const csrDer = new Uint8Array(csr.rawData);
|
|
1897
|
-
const pkcs8 = await
|
|
1925
|
+
const pkcs8 = await crypto2.webcrypto.subtle.exportKey("pkcs8", keys.privateKey);
|
|
1898
1926
|
const privateKeyPem = pemEncode(new Uint8Array(pkcs8), "PRIVATE KEY");
|
|
1899
1927
|
return { csrDer, privateKeyPem };
|
|
1900
1928
|
}
|
|
@@ -1903,7 +1931,7 @@ var init_cryptography_service = __esm({
|
|
|
1903
1931
|
// ---------------------------------------------------------------------------
|
|
1904
1932
|
/** Parse a PEM-encoded private key into a Node.js KeyObject. */
|
|
1905
1933
|
parsePrivateKey(pem) {
|
|
1906
|
-
return
|
|
1934
|
+
return crypto2.createPrivateKey(pem);
|
|
1907
1935
|
}
|
|
1908
1936
|
// ---------------------------------------------------------------------------
|
|
1909
1937
|
// Private helpers
|
|
@@ -1911,11 +1939,11 @@ var init_cryptography_service = __esm({
|
|
|
1911
1939
|
/** RSA-OAEP SHA-256 encryption. */
|
|
1912
1940
|
encryptRsaOaep(certPem, plaintext) {
|
|
1913
1941
|
return new Uint8Array(
|
|
1914
|
-
|
|
1942
|
+
crypto2.publicEncrypt(
|
|
1915
1943
|
{
|
|
1916
1944
|
key: certPem,
|
|
1917
1945
|
oaepHash: "sha256",
|
|
1918
|
-
padding:
|
|
1946
|
+
padding: crypto2.constants.RSA_PKCS1_OAEP_PADDING
|
|
1919
1947
|
},
|
|
1920
1948
|
plaintext
|
|
1921
1949
|
)
|
|
@@ -1932,15 +1960,15 @@ var init_cryptography_service = __esm({
|
|
|
1932
1960
|
* (Java-compatible — GCM appends the 16-byte tag to the ciphertext).
|
|
1933
1961
|
*/
|
|
1934
1962
|
encryptEcdhAesGcm(receiverPublicKey, plaintext) {
|
|
1935
|
-
const { privateKey: ephPrivKey, publicKey: ephPubKey } =
|
|
1963
|
+
const { privateKey: ephPrivKey, publicKey: ephPubKey } = crypto2.generateKeyPairSync("ec", {
|
|
1936
1964
|
namedCurve: "prime256v1"
|
|
1937
1965
|
});
|
|
1938
|
-
const sharedSecret =
|
|
1966
|
+
const sharedSecret = crypto2.diffieHellman({
|
|
1939
1967
|
privateKey: ephPrivKey,
|
|
1940
1968
|
publicKey: receiverPublicKey
|
|
1941
1969
|
});
|
|
1942
|
-
const nonce =
|
|
1943
|
-
const cipher =
|
|
1970
|
+
const nonce = crypto2.randomBytes(12);
|
|
1971
|
+
const cipher = crypto2.createCipheriv("aes-256-gcm", sharedSecret, nonce);
|
|
1944
1972
|
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
1945
1973
|
const tag = cipher.getAuthTag();
|
|
1946
1974
|
const ephemeralSpki = ephPubKey.export({ type: "spki", format: "der" });
|
|
@@ -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
|
}
|
|
@@ -6623,11 +6651,11 @@ function wrapBase64(base64) {
|
|
|
6623
6651
|
}
|
|
6624
6652
|
return lines.join("\n");
|
|
6625
6653
|
}
|
|
6626
|
-
var
|
|
6654
|
+
var crypto3, import_xml_crypto, import_xmldom, XADES_NS, DS_NS, SIGNED_PROPERTIES_TYPE, SHA256_DIGEST_METHOD, EXC_C14N_ALGORITHM, ENVELOPED_SIGNATURE_TRANSFORM, RSA_SHA256_SIGNATURE, ECDSA_SHA256_SIGNATURE, CLOCK_SKEW_BUFFER_MS, SIGNATURE_ID, SIGNED_PROPERTIES_ID, SignatureService;
|
|
6627
6655
|
var init_signature_service = __esm({
|
|
6628
6656
|
"src/crypto/signature-service.ts"() {
|
|
6629
6657
|
"use strict";
|
|
6630
|
-
|
|
6658
|
+
crypto3 = __toESM(require("crypto"), 1);
|
|
6631
6659
|
import_xml_crypto = require("xml-crypto");
|
|
6632
6660
|
import_xmldom = __toESM(require_lib(), 1);
|
|
6633
6661
|
XADES_NS = "http://uri.etsi.org/01903/v1.3.2#";
|
|
@@ -6656,11 +6684,11 @@ var init_signature_service = __esm({
|
|
|
6656
6684
|
}
|
|
6657
6685
|
const certDer = extractDerFromPem(certPem);
|
|
6658
6686
|
const certBase64 = certDer.toString("base64");
|
|
6659
|
-
const certDigest =
|
|
6660
|
-
const x5093 = new
|
|
6687
|
+
const certDigest = crypto3.createHash("sha256").update(certDer).digest("base64");
|
|
6688
|
+
const x5093 = new crypto3.X509Certificate(certPem);
|
|
6661
6689
|
const issuerName = normalizeIssuerDn(x5093.issuer);
|
|
6662
6690
|
const serialNumber = hexSerialToDecimal(x5093.serialNumber);
|
|
6663
|
-
const privateKey =
|
|
6691
|
+
const privateKey = crypto3.createPrivateKey(privateKeyPem);
|
|
6664
6692
|
const isEc = privateKey.asymmetricKeyType === "ec";
|
|
6665
6693
|
const signatureAlgorithm = isEc ? ECDSA_SHA256_SIGNATURE : RSA_SHA256_SIGNATURE;
|
|
6666
6694
|
const signingTime = new Date(Date.now() + CLOCK_SKEW_BUFFER_MS).toISOString();
|
|
@@ -6935,7 +6963,7 @@ var init_client = __esm({
|
|
|
6935
6963
|
this.lighthouse = new LighthouseService(this.options);
|
|
6936
6964
|
this.limits = new LimitsService(restClient);
|
|
6937
6965
|
this.peppol = new PeppolService(restClient);
|
|
6938
|
-
this.testData = new TestDataService(restClient);
|
|
6966
|
+
this.testData = new TestDataService(restClient, this.options.environmentName);
|
|
6939
6967
|
this.qr = new VerificationLinkService(this.options.baseQrUrl);
|
|
6940
6968
|
}
|
|
6941
6969
|
async loginWithToken(token, nip) {
|
|
@@ -6997,7 +7025,11 @@ __export(index_exports, {
|
|
|
6997
7025
|
AuthService: () => AuthService,
|
|
6998
7026
|
AuthTokenRequestBuilder: () => AuthTokenRequestBuilder,
|
|
6999
7027
|
AuthorizationPermissionGrantBuilder: () => AuthorizationPermissionGrantBuilder,
|
|
7028
|
+
BATCH_MAX_PARTS: () => BATCH_MAX_PARTS,
|
|
7029
|
+
BATCH_MAX_PART_SIZE: () => BATCH_MAX_PART_SIZE,
|
|
7030
|
+
BATCH_MAX_TOTAL_SIZE: () => BATCH_MAX_TOTAL_SIZE,
|
|
7000
7031
|
Base64String: () => Base64String,
|
|
7032
|
+
BatchFileBuilder: () => BatchFileBuilder,
|
|
7001
7033
|
BatchSessionService: () => BatchSessionService,
|
|
7002
7034
|
CERTIFICATE_NAME_MAX_LENGTH: () => CERTIFICATE_NAME_MAX_LENGTH,
|
|
7003
7035
|
CERTIFICATE_NAME_MIN_LENGTH: () => CERTIFICATE_NAME_MIN_LENGTH,
|
|
@@ -7590,18 +7622,86 @@ var AuthorizationPermissionGrantBuilder = class {
|
|
|
7590
7622
|
}
|
|
7591
7623
|
};
|
|
7592
7624
|
|
|
7625
|
+
// src/builders/batch-file.ts
|
|
7626
|
+
var crypto = __toESM(require("crypto"), 1);
|
|
7627
|
+
init_ksef_validation_error();
|
|
7628
|
+
var BATCH_MAX_PART_SIZE = 1e8;
|
|
7629
|
+
var BATCH_MAX_TOTAL_SIZE = 5e9;
|
|
7630
|
+
var BATCH_MAX_PARTS = 50;
|
|
7631
|
+
var BatchFileBuilder = class {
|
|
7632
|
+
/**
|
|
7633
|
+
* Build batch file metadata and encrypted parts from a raw ZIP.
|
|
7634
|
+
*
|
|
7635
|
+
* @param zipBytes - Unencrypted ZIP data
|
|
7636
|
+
* @param encryptFn - AES-256-CBC encryption function (called per part)
|
|
7637
|
+
* @param options - Optional configuration
|
|
7638
|
+
*/
|
|
7639
|
+
static build(zipBytes, encryptFn, options) {
|
|
7640
|
+
const maxPartSize = options?.maxPartSize ?? BATCH_MAX_PART_SIZE;
|
|
7641
|
+
if (maxPartSize <= 0) {
|
|
7642
|
+
throw new KSeFValidationError("maxPartSize must be a positive number");
|
|
7643
|
+
}
|
|
7644
|
+
if (zipBytes.length === 0) {
|
|
7645
|
+
throw new KSeFValidationError("ZIP data must not be empty");
|
|
7646
|
+
}
|
|
7647
|
+
if (zipBytes.length > BATCH_MAX_TOTAL_SIZE) {
|
|
7648
|
+
throw new KSeFValidationError(
|
|
7649
|
+
`ZIP size ${zipBytes.length} exceeds maximum of ${BATCH_MAX_TOTAL_SIZE} bytes (5 GB)`
|
|
7650
|
+
);
|
|
7651
|
+
}
|
|
7652
|
+
const rawParts = splitBuffer(zipBytes, maxPartSize);
|
|
7653
|
+
if (rawParts.length > BATCH_MAX_PARTS) {
|
|
7654
|
+
throw new KSeFValidationError(
|
|
7655
|
+
`Data requires ${rawParts.length} parts, exceeding maximum of ${BATCH_MAX_PARTS}`
|
|
7656
|
+
);
|
|
7657
|
+
}
|
|
7658
|
+
const zipHash = sha256Base64(zipBytes);
|
|
7659
|
+
const encryptedParts = [];
|
|
7660
|
+
const fileParts = rawParts.map((raw, i) => {
|
|
7661
|
+
const encrypted = encryptFn(raw);
|
|
7662
|
+
encryptedParts.push(encrypted);
|
|
7663
|
+
return {
|
|
7664
|
+
ordinalNumber: i + 1,
|
|
7665
|
+
fileSize: encrypted.length,
|
|
7666
|
+
fileHash: sha256Base64(encrypted)
|
|
7667
|
+
};
|
|
7668
|
+
});
|
|
7669
|
+
return {
|
|
7670
|
+
batchFile: {
|
|
7671
|
+
fileSize: zipBytes.length,
|
|
7672
|
+
fileHash: zipHash,
|
|
7673
|
+
fileParts
|
|
7674
|
+
},
|
|
7675
|
+
encryptedParts
|
|
7676
|
+
};
|
|
7677
|
+
}
|
|
7678
|
+
};
|
|
7679
|
+
function splitBuffer(data, maxPartSize) {
|
|
7680
|
+
if (data.length <= maxPartSize) {
|
|
7681
|
+
return [data];
|
|
7682
|
+
}
|
|
7683
|
+
const parts = [];
|
|
7684
|
+
for (let offset = 0; offset < data.length; offset += maxPartSize) {
|
|
7685
|
+
parts.push(data.subarray(offset, Math.min(offset + maxPartSize, data.length)));
|
|
7686
|
+
}
|
|
7687
|
+
return parts;
|
|
7688
|
+
}
|
|
7689
|
+
function sha256Base64(data) {
|
|
7690
|
+
return crypto.createHash("sha256").update(data).digest("base64");
|
|
7691
|
+
}
|
|
7692
|
+
|
|
7593
7693
|
// src/crypto/index.ts
|
|
7594
7694
|
init_certificate_fetcher();
|
|
7595
7695
|
init_cryptography_service();
|
|
7596
7696
|
init_signature_service();
|
|
7597
7697
|
|
|
7598
7698
|
// src/crypto/certificate-service.ts
|
|
7599
|
-
var
|
|
7699
|
+
var crypto4 = __toESM(require("crypto"), 1);
|
|
7600
7700
|
var x5092 = __toESM(require("@peculiar/x509"), 1);
|
|
7601
7701
|
var CertificateService = class {
|
|
7602
7702
|
static getSha256Fingerprint(certPem) {
|
|
7603
7703
|
const der = extractDerFromPem2(certPem);
|
|
7604
|
-
return
|
|
7704
|
+
return crypto4.createHash("sha256").update(der).digest("hex").toUpperCase();
|
|
7605
7705
|
}
|
|
7606
7706
|
static async generatePersonalCertificate(givenName, surname, serialNumber, commonName, method = "RSA") {
|
|
7607
7707
|
const nameParts = [];
|
|
@@ -7624,7 +7724,7 @@ var CertificateService = class {
|
|
|
7624
7724
|
}
|
|
7625
7725
|
};
|
|
7626
7726
|
async function generateSelfSigned(subject, method) {
|
|
7627
|
-
x5092.cryptoProvider.set(
|
|
7727
|
+
x5092.cryptoProvider.set(crypto4.webcrypto);
|
|
7628
7728
|
let algorithm;
|
|
7629
7729
|
let signingAlgorithm;
|
|
7630
7730
|
if (method === "ECDSA") {
|
|
@@ -7639,7 +7739,7 @@ async function generateSelfSigned(subject, method) {
|
|
|
7639
7739
|
};
|
|
7640
7740
|
signingAlgorithm = algorithm;
|
|
7641
7741
|
}
|
|
7642
|
-
const keys = await
|
|
7742
|
+
const keys = await crypto4.webcrypto.subtle.generateKey(
|
|
7643
7743
|
algorithm,
|
|
7644
7744
|
true,
|
|
7645
7745
|
["sign", "verify"]
|
|
@@ -7656,9 +7756,9 @@ async function generateSelfSigned(subject, method) {
|
|
|
7656
7756
|
serialNumber: Date.now().toString(16)
|
|
7657
7757
|
});
|
|
7658
7758
|
const certPem = cert.toString("pem");
|
|
7659
|
-
const pkcs8 = await
|
|
7759
|
+
const pkcs8 = await crypto4.webcrypto.subtle.exportKey("pkcs8", keys.privateKey);
|
|
7660
7760
|
const privateKeyPem = pemEncode2(new Uint8Array(pkcs8), "PRIVATE KEY");
|
|
7661
|
-
const fingerprint =
|
|
7761
|
+
const fingerprint = crypto4.createHash("sha256").update(Buffer.from(cert.rawData)).digest("hex").toUpperCase();
|
|
7662
7762
|
return { certificatePem: certPem, privateKeyPem, fingerprint };
|
|
7663
7763
|
}
|
|
7664
7764
|
function extractDerFromPem2(pem) {
|
|
@@ -7792,7 +7892,7 @@ async function openOnlineSession(client, options) {
|
|
|
7792
7892
|
async waitForUpo(pollOpts) {
|
|
7793
7893
|
const result = await pollUntil(
|
|
7794
7894
|
() => client.sessionStatus.getSessionStatus(sessionRef),
|
|
7795
|
-
(s) => s.status.code
|
|
7895
|
+
(s) => s.status.code === 200 || s.status.code >= 400,
|
|
7796
7896
|
{ ...pollOpts, description: `UPO for session ${sessionRef}` }
|
|
7797
7897
|
);
|
|
7798
7898
|
if (result.status.code !== 200) {
|
|
@@ -7818,31 +7918,36 @@ async function openSendAndClose(client, invoices, options) {
|
|
|
7818
7918
|
|
|
7819
7919
|
// src/workflows/batch-session-workflow.ts
|
|
7820
7920
|
var DEFAULT_FORM_CODE2 = { systemCode: "FA", schemaVersion: "3", value: "FA (3)" };
|
|
7821
|
-
async function uploadBatch(client,
|
|
7921
|
+
async function uploadBatch(client, zipData, options) {
|
|
7822
7922
|
await client.crypto.init();
|
|
7823
7923
|
const encData = client.crypto.getEncryptionData();
|
|
7824
7924
|
const formCode = options?.formCode ?? DEFAULT_FORM_CODE2;
|
|
7825
|
-
const
|
|
7826
|
-
|
|
7827
|
-
|
|
7925
|
+
const encryptFn = (part) => client.crypto.encryptAES256(part, encData.cipherKey, encData.cipherIv);
|
|
7926
|
+
const { batchFile, encryptedParts } = BatchFileBuilder.build(zipData, encryptFn, {
|
|
7927
|
+
maxPartSize: options?.maxPartSize
|
|
7828
7928
|
});
|
|
7829
7929
|
const openResp = await client.batchSession.openSession(
|
|
7830
7930
|
{
|
|
7831
7931
|
formCode,
|
|
7832
7932
|
encryption: encData.encryptionInfo,
|
|
7833
|
-
batchFile
|
|
7933
|
+
batchFile,
|
|
7934
|
+
offlineMode: options?.offlineMode
|
|
7834
7935
|
},
|
|
7835
7936
|
options?.upoVersion
|
|
7836
7937
|
);
|
|
7837
|
-
const sendingParts =
|
|
7838
|
-
|
|
7839
|
-
|
|
7840
|
-
|
|
7938
|
+
const sendingParts = encryptedParts.map((part, i) => ({
|
|
7939
|
+
data: part.buffer.slice(part.byteOffset, part.byteOffset + part.byteLength),
|
|
7940
|
+
metadata: {
|
|
7941
|
+
hashSHA: batchFile.fileParts[i].fileHash,
|
|
7942
|
+
fileSize: batchFile.fileParts[i].fileSize
|
|
7943
|
+
},
|
|
7944
|
+
ordinalNumber: i + 1
|
|
7945
|
+
}));
|
|
7841
7946
|
await client.batchSession.sendParts(openResp, sendingParts);
|
|
7842
7947
|
await client.batchSession.closeSession(openResp.referenceNumber);
|
|
7843
7948
|
const result = await pollUntil(
|
|
7844
7949
|
() => client.sessionStatus.getSessionStatus(openResp.referenceNumber),
|
|
7845
|
-
(s) => s.status.code
|
|
7950
|
+
(s) => s.status.code === 200 || s.status.code >= 400,
|
|
7846
7951
|
{ ...options?.pollOptions, description: `UPO for batch ${openResp.referenceNumber}` }
|
|
7847
7952
|
);
|
|
7848
7953
|
if (result.status.code !== 200) {
|
|
@@ -7860,7 +7965,7 @@ async function uploadBatch(client, zipParts, totalFileSize, totalFileHash, optio
|
|
|
7860
7965
|
}
|
|
7861
7966
|
|
|
7862
7967
|
// src/workflows/invoice-export-workflow.ts
|
|
7863
|
-
async function
|
|
7968
|
+
async function doExport(client, filters, options) {
|
|
7864
7969
|
await client.crypto.init();
|
|
7865
7970
|
const encData = client.crypto.getEncryptionData();
|
|
7866
7971
|
const opResp = await client.invoices.exportInvoices({
|
|
@@ -7870,7 +7975,7 @@ async function exportInvoices(client, filters, options) {
|
|
|
7870
7975
|
});
|
|
7871
7976
|
const result = await pollUntil(
|
|
7872
7977
|
() => client.invoices.getInvoiceExportStatus(opResp.referenceNumber),
|
|
7873
|
-
(s) => s.status.code
|
|
7978
|
+
(s) => s.status.code === 200 || s.status.code >= 400,
|
|
7874
7979
|
{ ...options?.pollOptions, description: `export ${opResp.referenceNumber}` }
|
|
7875
7980
|
);
|
|
7876
7981
|
if (result.status.code !== 200) {
|
|
@@ -7880,23 +7985,29 @@ async function exportInvoices(client, filters, options) {
|
|
|
7880
7985
|
throw new Error("Export completed but no package available");
|
|
7881
7986
|
}
|
|
7882
7987
|
return {
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
|
|
7886
|
-
|
|
7887
|
-
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
|
|
7891
|
-
|
|
7892
|
-
|
|
7893
|
-
|
|
7894
|
-
|
|
7988
|
+
encData,
|
|
7989
|
+
result: {
|
|
7990
|
+
parts: result.package.parts.map((p) => ({
|
|
7991
|
+
ordinalNumber: p.ordinalNumber,
|
|
7992
|
+
url: p.url,
|
|
7993
|
+
method: p.method,
|
|
7994
|
+
partSize: p.partSize,
|
|
7995
|
+
encryptedPartSize: p.encryptedPartSize,
|
|
7996
|
+
encryptedPartHash: p.encryptedPartHash,
|
|
7997
|
+
expirationDate: p.expirationDate
|
|
7998
|
+
})),
|
|
7999
|
+
invoiceCount: result.package.invoiceCount,
|
|
8000
|
+
isTruncated: result.package.isTruncated,
|
|
8001
|
+
permanentStorageHwmDate: result.package.permanentStorageHwmDate
|
|
8002
|
+
}
|
|
7895
8003
|
};
|
|
7896
8004
|
}
|
|
8005
|
+
async function exportInvoices(client, filters, options) {
|
|
8006
|
+
const { result } = await doExport(client, filters, options);
|
|
8007
|
+
return result;
|
|
8008
|
+
}
|
|
7897
8009
|
async function exportAndDownload(client, filters, options) {
|
|
7898
|
-
const encData = client
|
|
7899
|
-
const exportResult = await exportInvoices(client, filters, options);
|
|
8010
|
+
const { result: exportResult, encData } = await doExport(client, filters, options);
|
|
7900
8011
|
const download = options?.transport ?? fetch;
|
|
7901
8012
|
const decryptedParts = [];
|
|
7902
8013
|
for (const part of exportResult.parts) {
|
|
@@ -7990,7 +8101,11 @@ init_client();
|
|
|
7990
8101
|
AuthService,
|
|
7991
8102
|
AuthTokenRequestBuilder,
|
|
7992
8103
|
AuthorizationPermissionGrantBuilder,
|
|
8104
|
+
BATCH_MAX_PARTS,
|
|
8105
|
+
BATCH_MAX_PART_SIZE,
|
|
8106
|
+
BATCH_MAX_TOTAL_SIZE,
|
|
7993
8107
|
Base64String,
|
|
8108
|
+
BatchFileBuilder,
|
|
7994
8109
|
BatchSessionService,
|
|
7995
8110
|
CERTIFICATE_NAME_MAX_LENGTH,
|
|
7996
8111
|
CERTIFICATE_NAME_MIN_LENGTH,
|