@gerege-systems/eid-mongolia-sdk 0.15.0 → 0.15.2

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/dist/index.cjs CHANGED
@@ -52,12 +52,14 @@ __export(index_exports, {
52
52
  buildDeviceLink: () => buildDeviceLink,
53
53
  buildRegisterBody: () => buildRegisterBody,
54
54
  createEidLogin: () => createEidLogin,
55
+ defaultRateLimit: () => defaultRateLimit,
55
56
  deviceLink: () => deviceLink,
56
57
  deviceLinkInput: () => deviceLinkInput,
57
58
  forwardedClientIp: () => forwardedClientIp,
58
59
  interactionsToBase64: () => interactionsToBase64,
59
60
  isMobileUserAgent: () => isMobileUserAgent,
60
61
  memoryLoginStore: () => memoryLoginStore,
62
+ ocspRevocationChecker: () => ocspRevocationChecker,
61
63
  openOrShowQR: () => openOrShowQR,
62
64
  parseExpiresAt: () => parseExpiresAt,
63
65
  parseRetryAfter: () => parseRetryAfter,
@@ -223,6 +225,13 @@ var Http = class {
223
225
  post(path, body, timeoutMs) {
224
226
  return this.json("POST", path, JSON.stringify(body), "application/json", timeoutMs);
225
227
  }
228
+ /** {@link post} + HTTP статус (201 / 200-г ялгах: `POST /pdf/signatures`). */
229
+ async postWithStatus(path, body, timeoutMs) {
230
+ const op = `POST ${maskPath(path)}`;
231
+ const res = await this.send("POST", path, JSON.stringify(body), "application/json", timeoutMs);
232
+ const text = new TextDecoder().decode(await readLimited(res, MAX_JSON_BYTES, op));
233
+ return { status: res.status, body: text ? JSON.parse(text) : {} };
234
+ }
226
235
  get(path, timeoutMs) {
227
236
  return this.json("GET", path, void 0, void 0, timeoutMs);
228
237
  }
@@ -536,12 +545,32 @@ function registrationFromCompleted(done, extra) {
536
545
  if (extra.medium) out.medium = extra.medium;
537
546
  if (extra.sessionID) out.sessionID = extra.sessionID;
538
547
  if (done.hasPage && done.pageSha256) out.pageSha256 = done.pageSha256;
539
- if (done.priorCmsSha256.length) out.priorCmsSha256 = done.priorCmsSha256;
540
- if (extra.priorRevisionSha256?.length) out.priorRevisionSha256 = extra.priorRevisionSha256;
548
+ if (extra.priorRevisionSha256?.length) {
549
+ if (done.priorCmsSha256.length) out.priorCmsSha256 = done.priorCmsSha256;
550
+ out.priorRevisionSha256 = extra.priorRevisionSha256;
551
+ } else if (done.priorCmsSha256.length) {
552
+ out.priorCmsSha256 = done.priorCmsSha256;
553
+ const rev = done.priorRevisionSha256 ?? [];
554
+ if (rev.length === done.priorCmsSha256.length) {
555
+ out.priorSignatures = done.priorCmsSha256.map((c, i) => ({ cmsSha256: c, revisionSha256: rev[i] }));
556
+ }
557
+ }
541
558
  if (extra.onBehalfOf) out.onBehalfOf = extra.onBehalfOf;
542
559
  if (extra.signerEtsi) out.signerEtsi = extra.signerEtsi;
543
560
  return out;
544
561
  }
562
+ function priorSplits(n) {
563
+ const out = [];
564
+ const seen = /* @__PURE__ */ new Set();
565
+ for (let k = 1; k <= n; k++) {
566
+ seen.add((1 << k) - 1);
567
+ out.push(Array.from({ length: n }, (_, i) => i < k));
568
+ }
569
+ if (n <= 4) {
570
+ for (let m = 1; m < 1 << n; m++) if (!seen.has(m)) out.push(Array.from({ length: n }, (_, i) => (m & 1 << i) !== 0));
571
+ }
572
+ return out;
573
+ }
545
574
  var HEX64 = /^[0-9a-f]{64}$/;
546
575
  var MAX_CMS_BYTES = 28672;
547
576
  function buildRegisterBody(input) {
@@ -695,7 +724,7 @@ var SignApi = class {
695
724
  * (base64 → байт) `complete(state, signature)`-д.
696
725
  */
697
726
  async pdfDigest(input) {
698
- const digest = dtbsBase64(input.dtbs);
727
+ const digest2 = dtbsBase64(input.dtbs);
699
728
  const fileName = input.fileName?.trim() ?? "";
700
729
  if (!fileName || Array.from(fileName).length > PDF_MAX_FILE_NAME) {
701
730
  throw new ValidationError(`pdfDigest: fileName \u0437\u0430\u0430\u0432\u0430\u043B, \u2264 ${PDF_MAX_FILE_NAME} \u0442\u044D\u043C\u0434\u044D\u0433\u0442`);
@@ -713,7 +742,7 @@ var SignApi = class {
713
742
  certificateLevel: input.certificateLevel ?? this.defaults.certificateLevel,
714
743
  signatureProtocol: "RAW_DIGEST_SIGNATURE",
715
744
  signatureProtocolParameters: {
716
- digest,
745
+ digest: digest2,
717
746
  signatureAlgorithm: "sha256WithRSAEncryption",
718
747
  signatureAlgorithmParameters: { hashAlgorithm: "SHA-256" }
719
748
  },
@@ -733,7 +762,7 @@ var SignApi = class {
733
762
  }
734
763
  dl = { sessionToken: String(r.sessionToken), sessionSecret: String(r.sessionSecret), deviceLinkBase: String(r.deviceLinkBase) };
735
764
  }
736
- return { sessionId: String(r.sessionID), vc: vc != null ? String(vc) : null, digest, interactions, deviceLink: dl, receivedAt };
765
+ return { sessionId: String(r.sessionID), vc: vc != null ? String(vc) : null, digest: digest2, interactions, deviceLink: dl, receivedAt };
737
766
  }
738
767
  /**
739
768
  * `POST /pdf/signatures` — `pades.complete()`-ийн дараа CMS-ийг CA-д бүртгэнэ (`/verify/{docID}`, иргэний түүх). PDF
@@ -743,16 +772,38 @@ var SignApi = class {
743
772
  * `/verify` «бүртгэлгүй» гэнэ.
744
773
  */
745
774
  async registerSignature(input) {
746
- return this.registerBody(buildRegisterBody(input));
775
+ const body = buildRegisterBody(input);
776
+ const prior = input.priorSignatures ?? [];
777
+ if (input.priorRevisionSha256?.length || prior.length === 0 || prior.length !== input.revIndex - 1) return this.registerBody(body);
778
+ try {
779
+ return await this.registerBody(body);
780
+ } catch (first) {
781
+ if (!(first instanceof ApiError && first.code === "PRIOR_MISMATCH")) throw first;
782
+ for (const asRevision of priorSplits(prior.length)) {
783
+ const next = {
784
+ ...input,
785
+ priorSignatures: void 0,
786
+ priorCmsSha256: prior.filter((_, i) => !asRevision[i]).map((p) => p.cmsSha256),
787
+ priorRevisionSha256: prior.filter((_, i) => asRevision[i]).map((p) => p.revisionSha256)
788
+ };
789
+ try {
790
+ return await this.registerBody(buildRegisterBody(next));
791
+ } catch (e) {
792
+ if (!(e instanceof ApiError && e.code === "PRIOR_MISMATCH")) throw e;
793
+ }
794
+ }
795
+ throw first;
796
+ }
747
797
  }
748
798
  async registerBody(body) {
749
- const raw = await this.http.post(routePath(RP_ROUTES.pdfSignatures), body);
799
+ const { status, body: raw } = await this.http.postWithStatus(routePath(RP_ROUTES.pdfSignatures), body);
750
800
  const r = rec2(raw);
751
801
  return {
752
802
  docID: String(r.docID ?? body.docID),
753
803
  revIndex: Number(r.revIndex ?? 0),
754
804
  registeredAt: typeof r.registeredAt === "string" ? r.registeredAt : "",
755
805
  verifyUrl: String(r.verifyUrl ?? ""),
806
+ created: status === 201,
756
807
  raw
757
808
  };
758
809
  }
@@ -1112,11 +1163,11 @@ function parseSubject(cert) {
1112
1163
  if (atv.tag !== 48) throw new ValidationError("subject: AttributeTypeAndValue SEQUENCE \u0431\u0438\u0448");
1113
1164
  const oidT = tlv(der, atv.start, atv.end);
1114
1165
  const valT = tlv(der, oidT.end, atv.end);
1115
- const oid = oidOf(der, oidT);
1166
+ const oid2 = oidOf(der, oidT);
1116
1167
  const value = stringOf(der, valT);
1117
- if (value !== void 0 && !(oid in out.attributes)) {
1118
- out.attributes[oid] = value;
1119
- const key = OIDS[oid];
1168
+ if (value !== void 0 && !(oid2 in out.attributes)) {
1169
+ out.attributes[oid2] = value;
1170
+ const key = OIDS[oid2];
1120
1171
  if (key) out[key] = value;
1121
1172
  }
1122
1173
  ap = atv.end;
@@ -1127,8 +1178,8 @@ function parseSubject(cert) {
1127
1178
  out.name = full || out.commonName || null;
1128
1179
  return out;
1129
1180
  }
1130
- function certExtension(der, oid) {
1131
- return certExtensions(der).find((e) => e.oid === oid)?.value;
1181
+ function certExtension(der, oid2) {
1182
+ return certExtensions(der).find((e) => e.oid === oid2)?.value;
1132
1183
  }
1133
1184
  function certExtensions(der) {
1134
1185
  const out = [];
@@ -1140,9 +1191,9 @@ function certExtensions(der) {
1140
1191
  for (let pos = f.end; pos < tbs.end; ) {
1141
1192
  const t = tlv(der, pos, tbs.end);
1142
1193
  if (t.tag === 163) {
1143
- const seq = tlv(der, t.start, t.end);
1144
- for (let ep = seq.start; ep < seq.end; ) {
1145
- const ext = tlv(der, ep, seq.end);
1194
+ const seq2 = tlv(der, t.start, t.end);
1195
+ for (let ep = seq2.start; ep < seq2.end; ) {
1196
+ const ext = tlv(der, ep, seq2.end);
1146
1197
  const id = tlv(der, ext.start, ext.end);
1147
1198
  let v = tlv(der, id.end, ext.end);
1148
1199
  let critical = false;
@@ -1431,10 +1482,10 @@ var ResponseValidator = class {
1431
1482
  `\u0413\u044D\u0440\u0447\u0438\u043B\u0433\u044D\u044D certificate-choice-\u043E\u043E\u0440 \u0441\u043E\u043D\u0433\u043E\u0441\u043E\u043D\u0442\u043E\u0439 \u0442\u0430\u0430\u0440\u0430\u0445\u0433\u04AF\u0439 (serial ${leaf.serialNumber} \u2260 ${o.expectedCertificate.serialNumber})`
1432
1483
  );
1433
1484
  }
1434
- const digest = Buffer.from(digestB64, "base64");
1485
+ const digest2 = Buffer.from(digestB64, "base64");
1435
1486
  const { alg, hash } = this.algorithmOf(result, leaf, o.expectedAlgorithm ?? null, hashAlgorithm);
1436
- if (digest.length !== hashLen(hash)) throw new ValidationError("digest \u0443\u0440\u0442 hashAlgorithm-\u0442\u0430\u0439 \u0442\u0430\u0430\u0440\u0430\u0445\u0433\u04AF\u0439");
1437
- if (!verifyPrehashedSignature(digest, result.signatureValueB64, leaf.publicKey, alg, hash)) {
1487
+ if (digest2.length !== hashLen(hash)) throw new ValidationError("digest \u0443\u0440\u0442 hashAlgorithm-\u0442\u0430\u0439 \u0442\u0430\u0430\u0440\u0430\u0445\u0433\u04AF\u0439");
1488
+ if (!verifyPrehashedSignature(digest2, result.signatureValueB64, leaf.publicKey, alg, hash)) {
1438
1489
  throw new ValidationError("\u0413\u0430\u0440\u044B\u043D \u04AF\u0441\u044D\u0433 \u04E9\u0433\u0441\u04E9\u043D digest-\u0442\u044D\u0439 \u0442\u0430\u0430\u0440\u0441\u0430\u043D\u0433\u04AF\u0439");
1439
1490
  }
1440
1491
  return {
@@ -1640,13 +1691,20 @@ var ResponseValidator = class {
1640
1691
  * "skipped" (hook алга). "revoked", мөн hard-fail горимд "unknown" → ValidationError; hook-ийн алдаа дамжина.
1641
1692
  */
1642
1693
  async checkRevocationStatus(cert) {
1643
- if (!this.revocation) return "skipped";
1644
- const status = await this.revocation(cert, this.findIssuer(cert));
1694
+ return this.checkRevocationWith(cert, this.revocation, this.revocationMode);
1695
+ }
1696
+ /**
1697
+ * {@link checkRevocationStatus}-тэй ижил, гэхдээ TrustConfig-ийн биш өгсөн checker ба горимоор (issuer-ийг trust
1698
+ * pool-оос олно). checker алга бол "skipped"; горим анхдагч "hard-fail".
1699
+ */
1700
+ async checkRevocationWith(cert, checker, mode = "hard-fail") {
1701
+ if (!checker) return "skipped";
1702
+ const status = await checker(cert, this.findIssuer(cert));
1645
1703
  if (status === "good") return "good";
1646
1704
  if (status === "revoked") {
1647
1705
  throw new ValidationError("\u0413\u044D\u0440\u0447\u0438\u043B\u0433\u044D\u044D \u0446\u0443\u0446\u043B\u0430\u0433\u0434\u0441\u0430\u043D (revoked)");
1648
1706
  }
1649
- if (this.revocationMode === "hard-fail") {
1707
+ if (mode === "hard-fail") {
1650
1708
  throw new ValidationError("\u0413\u044D\u0440\u0447\u0438\u043B\u0433\u044D\u044D\u043D\u0438\u0439 revocation \u0442\u04E9\u043B\u04E9\u0432 \u0442\u043E\u0433\u0442\u043E\u043E\u0433\u0434\u0441\u043E\u043D\u0433\u04AF\u0439 (hard-fail)");
1651
1709
  }
1652
1710
  return "unchecked";
@@ -1675,9 +1733,9 @@ function verifyPayloadSignature(payload, sigB64, key, alg, hash) {
1675
1733
  if (alg === "ecdsa-with-SHA256") return (0, import_node_crypto4.verify)(h, payload, { key, dsaEncoding: "der" }, sig);
1676
1734
  return (0, import_node_crypto4.verify)(h, payload, { key, padding: import_node_crypto4.constants.RSA_PKCS1_PADDING }, sig);
1677
1735
  }
1678
- function verifyPrehashedSignature(digest, sigB64, key, alg, hash) {
1736
+ function verifyPrehashedSignature(digest2, sigB64, key, alg, hash) {
1679
1737
  const sig = Buffer.from(sigB64, "base64");
1680
- if (alg === "ecdsa-with-SHA256") return ecdsaP256VerifyPrehashed(digest, sig, key);
1738
+ if (alg === "ecdsa-with-SHA256") return ecdsaP256VerifyPrehashed(digest2, sig, key);
1681
1739
  const modBits = key.asymmetricKeyDetails?.modulusLength ?? 0;
1682
1740
  if (!modBits || sig.length !== Math.ceil(modBits / 8)) return false;
1683
1741
  let em;
@@ -1686,10 +1744,10 @@ function verifyPrehashedSignature(digest, sigB64, key, alg, hash) {
1686
1744
  } catch {
1687
1745
  return false;
1688
1746
  }
1689
- if (alg === "rsassa-pss") return emsaPssVerify(digest, em, modBits - 1, hash);
1747
+ if (alg === "rsassa-pss") return emsaPssVerify(digest2, em, modBits - 1, hash);
1690
1748
  const prefix = DIGEST_INFO[hash];
1691
1749
  if (!prefix) return false;
1692
- const t = Buffer.concat([prefix, digest]);
1750
+ const t = Buffer.concat([prefix, digest2]);
1693
1751
  const expected = Buffer.concat([Buffer.from([0, 1]), Buffer.alloc(em.length - t.length - 3, 255), Buffer.from([0]), t]);
1694
1752
  return em.length === expected.length && em.equals(expected);
1695
1753
  }
@@ -1740,7 +1798,7 @@ function derInts(sig) {
1740
1798
  }
1741
1799
  return i === sig.length ? [out[0], out[1]] : null;
1742
1800
  }
1743
- function ecdsaP256VerifyPrehashed(digest, sig, key) {
1801
+ function ecdsaP256VerifyPrehashed(digest2, sig, key) {
1744
1802
  if (key.asymmetricKeyDetails?.namedCurve !== "prime256v1") return false;
1745
1803
  const jwk = key.export({ format: "jwk" });
1746
1804
  if (!jwk.x || !jwk.y) return false;
@@ -1750,7 +1808,7 @@ function ecdsaP256VerifyPrehashed(digest, sig, key) {
1750
1808
  const [r, sv] = rs;
1751
1809
  const { n } = P256;
1752
1810
  if (r <= 0n || r >= n || sv <= 0n || sv >= n) return false;
1753
- const z = BigInt("0x" + digest.subarray(0, 32).toString("hex"));
1811
+ const z = BigInt("0x" + digest2.subarray(0, 32).toString("hex"));
1754
1812
  const w = inv(sv, n);
1755
1813
  const R = ptAdd(ptMul(mod(z * w, n), [P256.gx, P256.gy]), ptMul(mod(r * w, n), Q));
1756
1814
  return R !== null && mod(R[0], n) === r;
@@ -1803,10 +1861,10 @@ function keyUsageBits(cert) {
1803
1861
  function extKeyUsage(cert) {
1804
1862
  const v = certExtension(cert.raw, "2.5.29.37");
1805
1863
  if (!v) return [];
1806
- const seq = tlv(v, 0, v.length);
1864
+ const seq2 = tlv(v, 0, v.length);
1807
1865
  const out = [];
1808
- for (let p = seq.start; p < seq.end; ) {
1809
- const t = tlv(v, p, seq.end);
1866
+ for (let p = seq2.start; p < seq2.end; ) {
1867
+ const t = tlv(v, p, seq2.end);
1810
1868
  out.push(oidOf(v, t));
1811
1869
  p = t.end;
1812
1870
  }
@@ -1821,9 +1879,9 @@ function subjectKeyId(cert) {
1821
1879
  function authorityKeyId(cert) {
1822
1880
  const v = certExtension(cert.raw, "2.5.29.35");
1823
1881
  if (!v) return void 0;
1824
- const seq = tlv(v, 0, v.length);
1825
- if (seq.start >= seq.end) return void 0;
1826
- const k = tlv(v, seq.start, seq.end);
1882
+ const seq2 = tlv(v, 0, v.length);
1883
+ if (seq2.start >= seq2.end) return void 0;
1884
+ const k = tlv(v, seq2.start, seq2.end);
1827
1885
  return k.tag === 128 && k.end > k.start ? Buffer.from(v.subarray(k.start, k.end)).toString("hex") : void 0;
1828
1886
  }
1829
1887
  function isCa(cert) {
@@ -1889,9 +1947,9 @@ function caReason(ca, below, now, usage) {
1889
1947
  function basicConstraintsPathLen(cert) {
1890
1948
  const v = certExtension(cert.raw, "2.5.29.19");
1891
1949
  if (!v) return void 0;
1892
- const seq = tlv(v, 0, v.length);
1893
- for (let p = seq.start; p < seq.end; ) {
1894
- const t = tlv(v, p, seq.end);
1950
+ const seq2 = tlv(v, 0, v.length);
1951
+ for (let p = seq2.start; p < seq2.end; ) {
1952
+ const t = tlv(v, p, seq2.end);
1895
1953
  if (t.tag === 2) {
1896
1954
  if (t.end - t.start > 4 || (v[t.start] & 128) !== 0) throw new ValidationError("basicConstraints: pathLen \u0431\u0443\u0440\u0443\u0443");
1897
1955
  let n = 0;
@@ -1962,6 +2020,614 @@ var EidClient = class {
1962
2020
  }
1963
2021
  };
1964
2022
 
2023
+ // src/ocsp.ts
2024
+ var import_node_crypto5 = require("crypto");
2025
+
2026
+ // src/pades/bytes.ts
2027
+ var enc = new TextEncoder();
2028
+ function concat(parts) {
2029
+ let n = 0;
2030
+ for (const p of parts) n += p.length;
2031
+ const out = new Uint8Array(n);
2032
+ let o = 0;
2033
+ for (const p of parts) {
2034
+ out.set(p, o);
2035
+ o += p.length;
2036
+ }
2037
+ return out;
2038
+ }
2039
+ function equal(a, b) {
2040
+ if (a.length !== b.length) return false;
2041
+ for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
2042
+ return true;
2043
+ }
2044
+
2045
+ // src/pades/asn1.ts
2046
+ var Asn1Error = class extends Error {
2047
+ };
2048
+ var TAG = {
2049
+ BOOLEAN: 1,
2050
+ INTEGER: 2,
2051
+ BIT_STRING: 3,
2052
+ OCTET_STRING: 4,
2053
+ NULL: 5,
2054
+ OID: 6,
2055
+ ENUMERATED: 10,
2056
+ UTF8String: 12,
2057
+ SEQUENCE: 48,
2058
+ SET: 49,
2059
+ PrintableString: 19,
2060
+ IA5String: 22,
2061
+ UTCTime: 23,
2062
+ GeneralizedTime: 24
2063
+ };
2064
+ function readNode(b, off = 0) {
2065
+ if (off + 2 > b.length) throw new Asn1Error("asn1: \u0434\u0443\u0442\u0443\u0443");
2066
+ const tag = b[off];
2067
+ if ((tag & 31) === 31) throw new Asn1Error("asn1: \u043E\u043B\u043E\u043D \u0431\u0430\u0439\u0442 tag \u0434\u044D\u043C\u0436\u0438\u0433\u0434\u044D\u0445\u0433\u04AF\u0439");
2068
+ let len = b[off + 1];
2069
+ let p = off + 2;
2070
+ if (len & 128) {
2071
+ const n = len & 127;
2072
+ if (n === 0 || n > 4) throw new Asn1Error("asn1: \u0443\u0440\u0442 \u0431\u0443\u0440\u0443\u0443");
2073
+ if (p + n > b.length) throw new Asn1Error("asn1: \u0434\u0443\u0442\u0443\u0443");
2074
+ if (b[p] === 0) throw new Asn1Error("asn1: \u0443\u0440\u0442 minimal \u0431\u0438\u0448");
2075
+ len = 0;
2076
+ for (let i = 0; i < n; i++) len = len * 256 + b[p + i];
2077
+ if (len < 128) throw new Asn1Error("asn1: \u0443\u0440\u0442 minimal \u0431\u0438\u0448");
2078
+ p += n;
2079
+ }
2080
+ if (p + len > b.length) throw new Asn1Error("asn1: \u0434\u0443\u0442\u0443\u0443");
2081
+ return { tag, raw: b.subarray(off, p + len), value: b.subarray(p, p + len) };
2082
+ }
2083
+ function parseOne(b) {
2084
+ const n = readNode(b, 0);
2085
+ if (n.raw.length !== b.length) throw new Asn1Error("asn1: \u0438\u043B\u04AF\u04AF \u04E9\u0433\u04E9\u0433\u0434\u04E9\u043B");
2086
+ return n;
2087
+ }
2088
+ function children(n) {
2089
+ const v = n instanceof Uint8Array ? n : n.value;
2090
+ const out = [];
2091
+ for (let p = 0; p < v.length; ) {
2092
+ const c = readNode(v, p);
2093
+ out.push(c);
2094
+ p += c.raw.length;
2095
+ }
2096
+ return out;
2097
+ }
2098
+ function expect(n, tag, what) {
2099
+ if (!n || n.tag !== tag) throw new Asn1Error(`asn1: ${what} \u0445\u04AF\u043B\u044D\u044D\u0441\u044D\u043D`);
2100
+ return n;
2101
+ }
2102
+ function lenBytes(n) {
2103
+ if (n < 128) return Uint8Array.of(n);
2104
+ const out = [];
2105
+ for (let x = n; x > 0; x = Math.floor(x / 256)) out.unshift(x & 255);
2106
+ return Uint8Array.from([128 | out.length, ...out]);
2107
+ }
2108
+ function tlv2(tag, ...content) {
2109
+ const v = concat(content);
2110
+ return concat([Uint8Array.of(tag), lenBytes(v.length), v]);
2111
+ }
2112
+ var seq = (...c) => tlv2(TAG.SEQUENCE, ...c);
2113
+ var octet = (b) => tlv2(TAG.OCTET_STRING, b);
2114
+ var nullDer = () => Uint8Array.of(5, 0);
2115
+ function oid(s) {
2116
+ const parts = s.split(".").map((x) => BigInt(x));
2117
+ const body = [];
2118
+ const enc2 = (v) => {
2119
+ const tmp = [Number(v & 0x7fn)];
2120
+ for (v >>= 7n; v > 0n; v >>= 7n) tmp.unshift(Number(v & 0x7fn) | 128);
2121
+ body.push(...tmp);
2122
+ };
2123
+ enc2(parts[0] * 40n + parts[1]);
2124
+ for (const p of parts.slice(2)) enc2(p);
2125
+ return tlv2(TAG.OID, Uint8Array.from(body));
2126
+ }
2127
+ function oidString(v) {
2128
+ const out = [];
2129
+ let cur = 0n;
2130
+ for (const b of v) {
2131
+ cur = cur << 7n | BigInt(b & 127);
2132
+ if (!(b & 128)) {
2133
+ out.push(cur);
2134
+ cur = 0n;
2135
+ }
2136
+ }
2137
+ if (out.length === 0) return "";
2138
+ const first = out[0];
2139
+ const a = first < 40n ? 0n : first < 80n ? 1n : 2n;
2140
+ return [a, first - a * 40n, ...out.slice(1)].join(".");
2141
+ }
2142
+ function bigFromBytes(b) {
2143
+ let v = 0n;
2144
+ for (const x of b) v = v << 8n | BigInt(x);
2145
+ return v;
2146
+ }
2147
+ function intValue(v) {
2148
+ if (v.length === 0) throw new Asn1Error("asn1: \u0445\u043E\u043E\u0441\u043E\u043D INTEGER");
2149
+ let x = bigFromBytes(v);
2150
+ if (v[0] & 128) x -= 1n << BigInt(v.length * 8);
2151
+ return x;
2152
+ }
2153
+ function parseTime(n) {
2154
+ const s = String.fromCharCode(...n.value);
2155
+ let m;
2156
+ if (n.tag === TAG.UTCTime) {
2157
+ m = /^(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})?(Z|[+-]\d{4})$/.exec(s);
2158
+ if (!m) throw new Asn1Error("asn1: UTCTime \u0431\u0443\u0440\u0443\u0443");
2159
+ let y = Number(m[1]);
2160
+ y += y < 50 ? 2e3 : 1900;
2161
+ return mkDate(y, m[2], m[3], m[4], m[5], m[6] ?? "00", "", m[7]);
2162
+ }
2163
+ if (n.tag === TAG.GeneralizedTime) {
2164
+ m = /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\.\d+)?(Z|[+-]\d{4})$/.exec(s);
2165
+ if (!m) throw new Asn1Error("asn1: GeneralizedTime \u0431\u0443\u0440\u0443\u0443");
2166
+ return mkDate(Number(m[1]), m[2], m[3], m[4], m[5], m[6], m[7] ?? "", m[8]);
2167
+ }
2168
+ throw new Asn1Error("asn1: \u0446\u0430\u0433 \u0445\u04AF\u043B\u044D\u044D\u0441\u044D\u043D");
2169
+ }
2170
+ function parsePreciseTime(n) {
2171
+ const date = parseTime(n);
2172
+ const m = /\.(\d+)/.exec(String.fromCharCode(...n.value));
2173
+ const nanos = m ? Number((m[1] + "000000000").slice(0, 9)) : 0;
2174
+ return { date, nanos };
2175
+ }
2176
+ function mkDate(y, mo, d, h, mi, s, frac, z) {
2177
+ let t = Date.UTC(y, Number(mo) - 1, Number(d), Number(h), Number(mi), Number(s));
2178
+ if (frac) t += Math.floor(Number("0" + frac) * 1e3);
2179
+ if (z !== "Z") {
2180
+ const off = (Number(z.slice(1, 3)) * 60 + Number(z.slice(3, 5))) * 6e4;
2181
+ t += z[0] === "+" ? -off : off;
2182
+ }
2183
+ return new Date(t);
2184
+ }
2185
+
2186
+ // src/pades/crypto.ts
2187
+ var subtlePromise;
2188
+ var nodeImport = (m) => import(
2189
+ /* @vite-ignore */
2190
+ /* webpackIgnore: true */
2191
+ m
2192
+ );
2193
+ async function webcrypto() {
2194
+ const g = globalThis.crypto;
2195
+ if (g?.subtle) return g;
2196
+ const m = await nodeImport("node:crypto");
2197
+ if (!m.webcrypto) throw new Error("Web Crypto \u0430\u043B\u0433\u0430");
2198
+ return m.webcrypto;
2199
+ }
2200
+ function subtle() {
2201
+ subtlePromise ??= webcrypto().then((c) => c.subtle);
2202
+ return subtlePromise;
2203
+ }
2204
+ async function sha1(b) {
2205
+ return new Uint8Array(await (await subtle()).digest("SHA-1", b));
2206
+ }
2207
+
2208
+ // src/pades/x509.ts
2209
+ var OID = {
2210
+ rsaEncryption: "1.2.840.113549.1.1.1",
2211
+ rsaPSS: "1.2.840.113549.1.1.10",
2212
+ sha256WithRSA: "1.2.840.113549.1.1.11",
2213
+ sha384WithRSA: "1.2.840.113549.1.1.12",
2214
+ sha512WithRSA: "1.2.840.113549.1.1.13",
2215
+ ecPublicKey: "1.2.840.10045.2.1",
2216
+ ecdsaSHA256: "1.2.840.10045.4.3.2",
2217
+ ecdsaSHA384: "1.2.840.10045.4.3.3",
2218
+ ecdsaSHA512: "1.2.840.10045.4.3.4",
2219
+ p256: "1.2.840.10045.3.1.7",
2220
+ p384: "1.3.132.0.34",
2221
+ p521: "1.3.132.0.35",
2222
+ sha1: "1.3.14.3.2.26",
2223
+ sha256: "2.16.840.1.101.3.4.2.1",
2224
+ sha384: "2.16.840.1.101.3.4.2.2",
2225
+ sha512: "2.16.840.1.101.3.4.2.3",
2226
+ commonName: "2.5.4.3",
2227
+ surname: "2.5.4.4",
2228
+ givenName: "2.5.4.42",
2229
+ extKeyUsage: "2.5.29.37",
2230
+ keyUsage: "2.5.29.15",
2231
+ basicConstraints: "2.5.29.19",
2232
+ crlDP: "2.5.29.31",
2233
+ aia: "1.3.6.1.5.5.7.1.1",
2234
+ ocspMethod: "1.3.6.1.5.5.7.48.1",
2235
+ kpTimeStamping: "1.3.6.1.5.5.7.3.8",
2236
+ kpOCSPSigning: "1.3.6.1.5.5.7.3.9",
2237
+ kpAny: "2.5.29.37.0"
2238
+ };
2239
+ var CertError = class extends Error {
2240
+ };
2241
+ function bitString(n) {
2242
+ expect(n, TAG.BIT_STRING, "BIT STRING");
2243
+ if (n.value.length === 0) throw new Asn1Error("BIT STRING \u0445\u043E\u043E\u0441\u043E\u043D");
2244
+ return n.value.subarray(1);
2245
+ }
2246
+ function decodeDirString(n) {
2247
+ if (n.tag === 30) {
2248
+ let s = "";
2249
+ for (let i = 0; i + 1 < n.value.length; i += 2) s += String.fromCharCode(n.value[i] << 8 | n.value[i + 1]);
2250
+ return s;
2251
+ }
2252
+ if (n.tag === TAG.UTF8String) return new TextDecoder().decode(n.value);
2253
+ return String.fromCharCode(...n.value);
2254
+ }
2255
+ function nameAttrs(name) {
2256
+ const out = [];
2257
+ for (const rdn of children(name)) {
2258
+ for (const atv of children(rdn)) {
2259
+ const [t, v] = children(atv);
2260
+ if (!t || !v) continue;
2261
+ out.push([oidString(t.value), decodeDirString(v)]);
2262
+ }
2263
+ }
2264
+ return out;
2265
+ }
2266
+ function parseCertificate(der) {
2267
+ try {
2268
+ const top = parseOne(der);
2269
+ expect(top, TAG.SEQUENCE, "Certificate");
2270
+ const [tbsN, sigAlg, sigN] = children(top);
2271
+ const tbs = expect(tbsN, TAG.SEQUENCE, "TBSCertificate");
2272
+ const f = children(tbs);
2273
+ let i = 0;
2274
+ let version = 1;
2275
+ if (f[0]?.tag === 160) {
2276
+ const v = expect(children(f[0])[0], TAG.INTEGER, "version");
2277
+ version = v.value[0] + 1;
2278
+ i++;
2279
+ }
2280
+ const serial = expect(f[i++], TAG.INTEGER, "serial").value;
2281
+ i++;
2282
+ const issuer = expect(f[i++], TAG.SEQUENCE, "issuer");
2283
+ const validity = children(expect(f[i++], TAG.SEQUENCE, "validity"));
2284
+ const subject = expect(f[i++], TAG.SEQUENCE, "subject");
2285
+ const spki = expect(f[i++], TAG.SEQUENCE, "SPKI");
2286
+ const [algN, pkN] = children(spki);
2287
+ const algParts = children(expect(algN, TAG.SEQUENCE, "AlgorithmIdentifier"));
2288
+ const keyAlg = oidString(expect(algParts[0], TAG.OID, "alg").value);
2289
+ const curve = keyAlg === OID.ecPublicKey && algParts[1]?.tag === TAG.OID ? oidString(algParts[1].value) : void 0;
2290
+ const extensions = [];
2291
+ for (; i < f.length; i++) {
2292
+ if (f[i].tag !== 163) continue;
2293
+ for (const e of children(expect(children(f[i])[0], TAG.SEQUENCE, "extensions"))) {
2294
+ const p = children(e);
2295
+ const o = oidString(expect(p[0], TAG.OID, "ext oid").value);
2296
+ let critical = false;
2297
+ let val = p[1];
2298
+ if (val?.tag === TAG.BOOLEAN) {
2299
+ critical = val.value[0] !== 0;
2300
+ val = p[2];
2301
+ }
2302
+ extensions.push({ oid: o, critical, value: expect(val, TAG.OCTET_STRING, "ext value").value });
2303
+ }
2304
+ }
2305
+ const subj = nameAttrs(subject);
2306
+ const iss = nameAttrs(issuer);
2307
+ const last = (a, o) => a.filter(([k]) => k === o).map(([, v]) => v).pop() ?? "";
2308
+ const cert = {
2309
+ raw: top.raw,
2310
+ tbs: tbs.raw,
2311
+ version,
2312
+ serial,
2313
+ sigAlg: expect(sigAlg, TAG.SEQUENCE, "sigAlg"),
2314
+ signature: bitString(sigN),
2315
+ rawIssuer: issuer.raw,
2316
+ rawSubject: subject.raw,
2317
+ spki: spki.raw,
2318
+ keyAlg,
2319
+ curve,
2320
+ publicKey: bitString(pkN),
2321
+ notBefore: parseTime(validity[0]),
2322
+ notAfter: parseTime(validity[1]),
2323
+ extensions,
2324
+ subjectCN: last(subj, OID.commonName),
2325
+ issuerCN: last(iss, OID.commonName),
2326
+ // Go SignerDisplayName: Subject.Names-ийн давталтын сүүлийн утга.
2327
+ givenName: last(subj, OID.givenName),
2328
+ surname: last(subj, OID.surname),
2329
+ ocspServers: [],
2330
+ crlDPs: [],
2331
+ isCA: false,
2332
+ basicConstraintsValid: false,
2333
+ keyUsage: 0,
2334
+ extKeyUsage: []
2335
+ };
2336
+ for (const e of extensions) parseExtension(cert, e);
2337
+ return cert;
2338
+ } catch (e) {
2339
+ throw new CertError(`\u0433\u044D\u0440\u0447\u0438\u043B\u0433\u044D\u044D \u0437\u0430\u0434\u0430\u0440\u0441\u0430\u043D\u0433\u04AF\u0439: ${e instanceof Error ? e.message : String(e)}`);
2340
+ }
2341
+ }
2342
+ function parseExtension(c, e) {
2343
+ const n = parseOne(e.value);
2344
+ switch (e.oid) {
2345
+ case OID.basicConstraints: {
2346
+ c.basicConstraintsValid = true;
2347
+ const p = children(n);
2348
+ c.isCA = p[0]?.tag === TAG.BOOLEAN && p[0].value[0] !== 0;
2349
+ break;
2350
+ }
2351
+ case OID.keyUsage: {
2352
+ const bs = n.value;
2353
+ let ku = 0;
2354
+ for (let i = 1; i < bs.length; i++) {
2355
+ for (let b = 0; b < 8; b++) if (bs[i] & 128 >> b) ku |= 1 << (i - 1) * 8 + b;
2356
+ }
2357
+ c.keyUsage = ku;
2358
+ break;
2359
+ }
2360
+ case OID.extKeyUsage:
2361
+ c.extKeyUsage = children(n).map((x) => oidString(x.value));
2362
+ break;
2363
+ case OID.aia:
2364
+ for (const ad of children(n)) {
2365
+ const [m, loc] = children(ad);
2366
+ if (m && loc && oidString(m.value) === OID.ocspMethod && loc.tag === 134) c.ocspServers.push(String.fromCharCode(...loc.value));
2367
+ }
2368
+ break;
2369
+ case OID.crlDP:
2370
+ for (const dp of children(n)) {
2371
+ for (const f of children(dp)) {
2372
+ if (f.tag !== 160) continue;
2373
+ for (const fn of children(f)) {
2374
+ if (fn.tag !== 160) continue;
2375
+ for (const gn of children(fn)) if (gn.tag === 134) c.crlDPs.push(String.fromCharCode(...gn.value));
2376
+ }
2377
+ }
2378
+ }
2379
+ break;
2380
+ }
2381
+ }
2382
+ var HASH_BY_OID = {
2383
+ [OID.sha1]: "SHA-1",
2384
+ [OID.sha256]: "SHA-256",
2385
+ [OID.sha384]: "SHA-384",
2386
+ [OID.sha512]: "SHA-512"
2387
+ };
2388
+ function schemeFor(alg) {
2389
+ const p = children(alg);
2390
+ const o = oidString(expect(p[0], TAG.OID, "sigAlg").value);
2391
+ switch (o) {
2392
+ case "1.2.840.113549.1.1.5":
2393
+ return { kind: "rsa", hash: "SHA-1" };
2394
+ case OID.sha256WithRSA:
2395
+ return { kind: "rsa", hash: "SHA-256" };
2396
+ case OID.sha384WithRSA:
2397
+ return { kind: "rsa", hash: "SHA-384" };
2398
+ case OID.sha512WithRSA:
2399
+ return { kind: "rsa", hash: "SHA-512" };
2400
+ case OID.ecdsaSHA256:
2401
+ return { kind: "ecdsa", hash: "SHA-256" };
2402
+ case OID.ecdsaSHA384:
2403
+ return { kind: "ecdsa", hash: "SHA-384" };
2404
+ case OID.ecdsaSHA512:
2405
+ return { kind: "ecdsa", hash: "SHA-512" };
2406
+ case OID.rsaPSS: {
2407
+ let hash = "SHA-1";
2408
+ let salt = 20;
2409
+ for (const f of p[1] ? children(p[1]) : []) {
2410
+ if (f.tag === 160) hash = HASH_BY_OID[oidString(children(children(f)[0])[0].value)] ?? hash;
2411
+ if (f.tag === 162) salt = Number(children(f)[0].value[0]);
2412
+ }
2413
+ return { kind: "pss", hash, saltLength: salt };
2414
+ }
2415
+ }
2416
+ throw new CertError(`\u0433\u0430\u0440\u044B\u043D \u04AF\u0441\u0433\u0438\u0439\u043D \u0430\u043B\u0433\u043E\u0440\u0438\u0442\u043C \u0434\u044D\u043C\u0436\u0438\u0433\u0434\u044D\u0445\u0433\u04AF\u0439: ${o}`);
2417
+ }
2418
+ var CURVES = {
2419
+ [OID.p256]: { name: "P-256", size: 32 },
2420
+ [OID.p384]: { name: "P-384", size: 48 },
2421
+ [OID.p521]: { name: "P-521", size: 66 }
2422
+ };
2423
+ function ecdsaDerToRaw(der, size) {
2424
+ const [r, s] = children(parseOne(der));
2425
+ const out = new Uint8Array(2 * size);
2426
+ const put = (v, at) => {
2427
+ let x = v;
2428
+ while (x.length > 0 && x[0] === 0) x = x.subarray(1);
2429
+ if (x.length > size) throw new CertError("ECDSA \u0443\u0442\u0433\u0430 \u0445\u044D\u0442 \u0443\u0440\u0442");
2430
+ out.set(x, at + size - x.length);
2431
+ };
2432
+ put(expect(r, TAG.INTEGER, "r").value, 0);
2433
+ put(expect(s, TAG.INTEGER, "s").value, size);
2434
+ return out;
2435
+ }
2436
+ async function verifySignature(pub, alg, data, sig) {
2437
+ const sch = schemeFor(alg);
2438
+ return verifyWith(pub, sch, data, sig);
2439
+ }
2440
+ async function verifyWith(pub, sch, data, sig) {
2441
+ const s = await subtle();
2442
+ try {
2443
+ if (sch.kind === "ecdsa") {
2444
+ if (pub.keyAlg !== OID.ecPublicKey) return false;
2445
+ const c = CURVES[pub.curve ?? ""];
2446
+ if (!c) return false;
2447
+ const key2 = await s.importKey("spki", pub.spki, { name: "ECDSA", namedCurve: c.name }, false, ["verify"]);
2448
+ return await s.verify({ name: "ECDSA", hash: sch.hash }, key2, ecdsaDerToRaw(sig, c.size), data);
2449
+ }
2450
+ if (pub.keyAlg !== OID.rsaEncryption) return false;
2451
+ if (sch.kind === "pss") {
2452
+ const key2 = await s.importKey("spki", pub.spki, { name: "RSA-PSS", hash: sch.hash }, false, ["verify"]);
2453
+ return await s.verify({ name: "RSA-PSS", saltLength: sch.saltLength ?? 32 }, key2, sig, data);
2454
+ }
2455
+ const key = await s.importKey("spki", pub.spki, { name: "RSASSA-PKCS1-v1_5", hash: sch.hash }, false, ["verify"]);
2456
+ return await s.verify({ name: "RSASSA-PKCS1-v1_5" }, key, sig, data);
2457
+ } catch {
2458
+ return false;
2459
+ }
2460
+ }
2461
+ function checkSignature(parent, alg, signed, sig) {
2462
+ return verifySignature(parent, alg, signed, sig);
2463
+ }
2464
+ var HANDLED = /* @__PURE__ */ new Set([
2465
+ OID.keyUsage,
2466
+ OID.extKeyUsage,
2467
+ OID.basicConstraints,
2468
+ "2.5.29.17",
2469
+ // SAN
2470
+ "2.5.29.30",
2471
+ // name constraints
2472
+ "2.5.29.32",
2473
+ // policies
2474
+ OID.crlDP,
2475
+ OID.aia,
2476
+ "2.5.29.14",
2477
+ "2.5.29.35"
2478
+ ]);
2479
+
2480
+ // src/pades/cms.ts
2481
+ var HASHES2 = {
2482
+ [OID.sha1]: "SHA-1",
2483
+ [OID.sha256]: "SHA-256",
2484
+ [OID.sha384]: "SHA-384",
2485
+ [OID.sha512]: "SHA-512"
2486
+ };
2487
+
2488
+ // src/pades/ltv.ts
2489
+ var MAX_TSA_SKEW_MS = 10 * 6e4;
2490
+ async function ocspRequest(c, issuer) {
2491
+ const keyHash = await sha1(issuer.publicKey);
2492
+ const nameHash = await sha1(issuer.rawSubject);
2493
+ const certID = seq(seq(oid(OID.sha1), nullDer()), octet(nameHash), octet(keyHash), Uint8Array.of(TAG.INTEGER, ...lenOf(c.serial.length), ...c.serial));
2494
+ return seq(seq(seq(seq(certID))));
2495
+ }
2496
+ function lenOf(n) {
2497
+ if (n < 128) return [n];
2498
+ const out = [];
2499
+ for (let x = n; x > 0; x = Math.floor(x / 256)) out.unshift(x & 255);
2500
+ return [128 | out.length, ...out];
2501
+ }
2502
+ var OID_OCSP_BASIC = "1.3.6.1.5.5.7.48.1.1";
2503
+ async function parseOCSPForCert(der, c, issuer) {
2504
+ const top = children(expect(parseOne(der), TAG.SEQUENCE, "OCSPResponse"));
2505
+ if (expect(top[0], TAG.ENUMERATED, "status").value[0] !== 0) throw new Error("OCSP response status");
2506
+ const rb = children(expect(children(expect(top[1], 160, "responseBytes"))[0], TAG.SEQUENCE, "ResponseBytes"));
2507
+ if (oidString(expect(rb[0], TAG.OID, "responseType").value) !== OID_OCSP_BASIC) throw new Error("bad OCSP response type");
2508
+ const basic = children(expect(parseOne(expect(rb[1], TAG.OCTET_STRING, "response").value), TAG.SEQUENCE, "BasicOCSPResponse"));
2509
+ const tbs = expect(basic[0], TAG.SEQUENCE, "tbsResponseData");
2510
+ const sigAlg = expect(basic[1], TAG.SEQUENCE, "sigAlg");
2511
+ const sigBits = expect(basic[2], TAG.BIT_STRING, "signature").value.subarray(1);
2512
+ const tf = children(tbs);
2513
+ let i = 0;
2514
+ if (tf[0]?.tag === 160) i++;
2515
+ const rid = tf[i++];
2516
+ if (rid.tag !== 161 && rid.tag !== 162) throw new Error("invalid responder id tag");
2517
+ i++;
2518
+ const responses = children(expect(tf[i], TAG.SEQUENCE, "responses"));
2519
+ if (responses.length === 0) throw new Error("OCSP response contains bad number of responses");
2520
+ const serial = intValue(c.serial);
2521
+ let single;
2522
+ for (const r of responses) {
2523
+ const f = children(r);
2524
+ const cid2 = children(f[0]);
2525
+ if (intValue(expect(cid2[3], TAG.INTEGER, "serial").value) === serial) {
2526
+ single = f;
2527
+ break;
2528
+ }
2529
+ }
2530
+ if (!single) throw new Error("no response matching the supplied certificate");
2531
+ let certificate;
2532
+ if (basic[3]?.tag === 160) {
2533
+ const certs = children(expect(children(basic[3])[0], TAG.SEQUENCE, "certs"));
2534
+ if (certs[0]) certificate = parseCertificate(certs[0].raw);
2535
+ }
2536
+ if (certificate) {
2537
+ if (!await verifySignature(certificate, sigAlg, tbs.raw, sigBits)) throw new Error("bad signature on embedded certificate");
2538
+ if (!await checkSignature(issuer, certificate.sigAlg, certificate.tbs, certificate.signature)) throw new Error("bad OCSP signature");
2539
+ } else if (!await verifySignature(issuer, sigAlg, tbs.raw, sigBits)) {
2540
+ throw new Error("bad OCSP signature");
2541
+ }
2542
+ const cid = children(single[0]);
2543
+ const hashAlg = oidString(children(cid[0])[0].value);
2544
+ if (![OID.sha1, OID.sha256, OID.sha384, OID.sha512].includes(hashAlg)) throw new Error("unsupported issuer hash algorithm");
2545
+ const st = single[1];
2546
+ const status = st.tag === 128 ? "good" : st.tag === 161 ? "revoked" : st.tag === 130 ? "unknown" : void 0;
2547
+ if (!status) throw new Error("OCSP certStatus");
2548
+ const thisUpdate = parsePreciseTime(expect(single[2], TAG.GeneralizedTime, "thisUpdate"));
2549
+ let nextUpdate;
2550
+ for (const x of single.slice(3)) {
2551
+ if (x.tag === 160) nextUpdate = parsePreciseTime(children(x)[0]).date;
2552
+ if (x.tag === 161) {
2553
+ for (const ext of children(children(x)[0])) {
2554
+ const e = children(ext);
2555
+ if (e[1]?.tag === TAG.BOOLEAN && e[1].value[0] !== 0) throw new Error("unsupported critical extension");
2556
+ }
2557
+ }
2558
+ }
2559
+ return { status, thisUpdate, nextUpdate, certificate };
2560
+ }
2561
+
2562
+ // src/ocsp.ts
2563
+ var CACHE_TTL_MS = 5 * 6e4;
2564
+ var CACHE_MAX = 1024;
2565
+ var MAX_BYTES = 16 << 10;
2566
+ var CLOCK_SKEW_MS = 5 * 6e4;
2567
+ var MAX_AGE_MS = 48 * 36e5;
2568
+ function ocspRevocationChecker(opts = {}) {
2569
+ const doFetch = opts.fetchImpl ?? globalThis.fetch;
2570
+ const timeoutMs = opts.timeoutMs ?? 2e3;
2571
+ const totalMs = Math.max(timeoutMs, 3e3);
2572
+ const now = opts.now ?? Date.now;
2573
+ const cache = /* @__PURE__ */ new Map();
2574
+ async function ask(leaf, issuer) {
2575
+ const body = await ocspRequest(leaf, issuer);
2576
+ const deadline = Date.now() + totalMs;
2577
+ for (const raw of leaf.ocspServers) {
2578
+ const left = deadline - Date.now();
2579
+ if (left <= 0) break;
2580
+ try {
2581
+ const u = new URL(raw);
2582
+ if (u.protocol !== "http:" && u.protocol !== "https:") continue;
2583
+ const res = await doFetch(u.toString(), {
2584
+ method: "POST",
2585
+ headers: { "Content-Type": "application/ocsp-request", Accept: "application/ocsp-response" },
2586
+ body,
2587
+ redirect: "manual",
2588
+ signal: AbortSignal.timeout(Math.min(timeoutMs, left))
2589
+ });
2590
+ if (res.status !== 200) continue;
2591
+ const der = new Uint8Array(await res.arrayBuffer());
2592
+ if (der.length > MAX_BYTES) continue;
2593
+ const resp = await parseOCSPForCert(der, leaf, issuer);
2594
+ const t = now();
2595
+ const rc = resp.certificate;
2596
+ if (rc && !equal(rc.raw, issuer.raw)) {
2597
+ if (!rc.extKeyUsage.includes(OID.kpOCSPSigning)) continue;
2598
+ if (t < rc.notBefore.getTime() || t > rc.notAfter.getTime()) continue;
2599
+ }
2600
+ const tu = resp.thisUpdate.date.getTime();
2601
+ if (tu > t + CLOCK_SKEW_MS || tu < t - MAX_AGE_MS) continue;
2602
+ if (resp.nextUpdate && resp.nextUpdate.getTime() < t) continue;
2603
+ return resp.status === "good" ? "good" : "revoked";
2604
+ } catch {
2605
+ }
2606
+ }
2607
+ return void 0;
2608
+ }
2609
+ return async (cert, issuer) => {
2610
+ if (!issuer) return "unknown";
2611
+ let leaf, iss;
2612
+ try {
2613
+ leaf = parseCertificate(new Uint8Array(cert.raw));
2614
+ iss = parseCertificate(new Uint8Array(issuer.raw));
2615
+ } catch {
2616
+ return "unknown";
2617
+ }
2618
+ const key = (0, import_node_crypto5.createHash)("sha256").update(issuer.raw).digest("hex").slice(0, 16) + ":" + cert.serialNumber;
2619
+ const exp = cache.get(key);
2620
+ if (exp !== void 0 && now() < exp) return "good";
2621
+ const status = await ask(leaf, iss);
2622
+ if (!status) return "unknown";
2623
+ if (status === "good") {
2624
+ if (cache.size >= CACHE_MAX) cache.clear();
2625
+ cache.set(key, now() + CACHE_TTL_MS);
2626
+ }
2627
+ return status;
2628
+ };
2629
+ }
2630
+
1965
2631
  // src/devicelink.ts
1966
2632
  var SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
1967
2633
  var VC_RE = /^[0-9]{5}$/;
@@ -2005,7 +2671,7 @@ function openOrShowQR(session, opts) {
2005
2671
  }
2006
2672
 
2007
2673
  // src/devicelinkv3.ts
2008
- var import_node_crypto5 = require("crypto");
2674
+ var import_node_crypto6 = require("crypto");
2009
2675
  var TYPES = ["QR", "Web2App", "App2App"];
2010
2676
  var PROTOCOL = { auth: "ACSP_V2", sign: "RAW_DIGEST_SIGNATURE", cert: "" };
2011
2677
  var TOKEN_RE = /^[A-Za-z0-9_-]+$/;
@@ -2062,7 +2728,7 @@ function buildDeviceLink(p) {
2062
2728
  callback,
2063
2729
  unprotected
2064
2730
  ].join("|");
2065
- const authCode = (0, import_node_crypto5.createHmac)("sha256", Buffer.from(p.sessionSecret, "base64")).update(payload, "utf8").digest("base64url");
2731
+ const authCode = (0, import_node_crypto6.createHmac)("sha256", Buffer.from(p.sessionSecret, "base64")).update(payload, "utf8").digest("base64url");
2066
2732
  return `${unprotected}&authCode=${authCode}`;
2067
2733
  }
2068
2734
  function deviceLinkInput(s, deviceLinkType, lang) {
@@ -2106,7 +2772,7 @@ function qrDeviceLinkTicker(input, onLink, opts) {
2106
2772
  }
2107
2773
 
2108
2774
  // src/login.ts
2109
- var import_node_crypto6 = require("crypto");
2775
+ var import_node_crypto7 = require("crypto");
2110
2776
  function memoryLoginStore() {
2111
2777
  const m = /* @__PURE__ */ new Map();
2112
2778
  return {
@@ -2131,6 +2797,51 @@ function memoryLoginStore() {
2131
2797
  }
2132
2798
  };
2133
2799
  }
2800
+ var defaultRateLimit = Object.freeze({
2801
+ push: Object.freeze({ limit: 3, windowMs: 6e4 })
2802
+ });
2803
+ var RATE_KINDS = ["start", "push"];
2804
+ function windowLimiter(limit, windowMs) {
2805
+ const hits = /* @__PURE__ */ new Map();
2806
+ return (key) => {
2807
+ const now = Date.now();
2808
+ const h = (hits.get(key) ?? []).filter((t) => now - t < windowMs);
2809
+ if (hits.size > 1e4) hits.clear();
2810
+ if (h.length >= limit) {
2811
+ hits.set(key, h);
2812
+ return false;
2813
+ }
2814
+ h.push(now);
2815
+ hits.set(key, h);
2816
+ return true;
2817
+ };
2818
+ }
2819
+ function buildRateLimit(opt) {
2820
+ const extra = typeof opt === "function" ? opt : void 0;
2821
+ const user = opt && typeof opt === "object" ? opt : {};
2822
+ for (const k of Object.keys(user)) {
2823
+ if (!RATE_KINDS.includes(k)) throw new Error(`createEidLogin: rateLimit.${k} \u2014 \u0437\u04E9\u0432\u0445\u04E9\u043D start | push`);
2824
+ }
2825
+ const merged = { ...defaultRateLimit, ...user };
2826
+ const perKind = /* @__PURE__ */ new Map();
2827
+ for (const k of RATE_KINDS) {
2828
+ const r = merged[k];
2829
+ if (r === void 0 || r === false) continue;
2830
+ if (typeof r === "function") {
2831
+ perKind.set(k, r);
2832
+ continue;
2833
+ }
2834
+ if (!(Number.isInteger(r.limit) && r.limit > 0 && r.windowMs > 0)) {
2835
+ throw new Error(`createEidLogin: rateLimit.${k} \u2014 limit (\u0431\u04AF\u0445\u044D\u043B > 0), windowMs (> 0)`);
2836
+ }
2837
+ perKind.set(k, windowLimiter(r.limit, r.windowMs));
2838
+ }
2839
+ return async (key) => {
2840
+ const fn = perKind.get(key.slice(0, key.indexOf(":")));
2841
+ if (fn && !await fn(key)) return false;
2842
+ return extra ? extra(key) : true;
2843
+ };
2844
+ }
2134
2845
  var CALLBACK_PATH = "/auth/eid/callback";
2135
2846
  function forwardedClientIp(headers, trustProxy) {
2136
2847
  if (trustProxy === false || trustProxy === 0) return void 0;
@@ -2187,13 +2898,43 @@ function readCookie(h, name) {
2187
2898
  }
2188
2899
  return "";
2189
2900
  }
2190
- var sha256hex = (s) => (0, import_node_crypto6.createHash)("sha256").update(s).digest("hex");
2901
+ var sha256hex = (s) => (0, import_node_crypto7.createHash)("sha256").update(s).digest("hex");
2191
2902
  function safeEqualHex(a, b) {
2192
2903
  const x = Buffer.from(a, "hex");
2193
2904
  const y = Buffer.from(b, "hex");
2194
- return x.length === y.length && x.length > 0 && (0, import_node_crypto6.timingSafeEqual)(x, y);
2905
+ return x.length === y.length && x.length > 0 && (0, import_node_crypto7.timingSafeEqual)(x, y);
2906
+ }
2907
+ function sleep(ms2, signal) {
2908
+ return new Promise((resolve) => {
2909
+ if (ms2 <= 0 || signal?.aborted) return resolve();
2910
+ const done = () => {
2911
+ clearTimeout(t);
2912
+ signal?.removeEventListener("abort", done);
2913
+ resolve();
2914
+ };
2915
+ const t = setTimeout(done, ms2);
2916
+ signal?.addEventListener("abort", done, { once: true });
2917
+ });
2918
+ }
2919
+ function isRefusal(e) {
2920
+ if (!(e instanceof ApiError) || e.status < 400 || e.status >= 500 || e.status === 401 || e.status === 403 || e.status === 429) {
2921
+ return false;
2922
+ }
2923
+ try {
2924
+ JSON.parse(e.body);
2925
+ return true;
2926
+ } catch {
2927
+ return false;
2928
+ }
2195
2929
  }
2196
- function toIdentity(sessionId, r, v, flowType) {
2930
+ var RevocationFailure = class extends ValidationError {
2931
+ constructor(message, revoked) {
2932
+ super(message);
2933
+ this.revoked = revoked;
2934
+ }
2935
+ revoked;
2936
+ };
2937
+ function toIdentity(sessionId, r, v, flowType, revocation) {
2197
2938
  const s = v.parsedSubject;
2198
2939
  const etsi = s.serialNumber ?? "";
2199
2940
  const m = /^PNOMN-([0-9]+)$/.exec(etsi);
@@ -2209,7 +2950,8 @@ function toIdentity(sessionId, r, v, flowType) {
2209
2950
  certificateLevel: v.certificateLevel,
2210
2951
  certificateDerB64: r.certificateDerB64 ?? "",
2211
2952
  flowType,
2212
- person: personMatchesCertificate(r.person, s) ? r.person ?? null : null
2953
+ person: personMatchesCertificate(r.person, s) ? r.person ?? null : null,
2954
+ revocation
2213
2955
  };
2214
2956
  }
2215
2957
  function createEidLogin(opts) {
@@ -2230,17 +2972,29 @@ function createEidLogin(opts) {
2230
2972
  const successRedirect = opts.successRedirect ?? "/";
2231
2973
  const failureRedirect = opts.failureRedirect ?? "/";
2232
2974
  const onError = opts.onError ?? ((e) => console.error("eid-login:", e instanceof Error ? e.message : e));
2233
- const pushHits = /* @__PURE__ */ new Map();
2234
- const rateLimit = opts.rateLimit ?? ((key) => {
2235
- if (!key.startsWith("push:")) return true;
2236
- const now = Date.now();
2237
- const hits = (pushHits.get(key) ?? []).filter((t) => now - t < 6e4);
2238
- if (pushHits.size > 1e4) pushHits.clear();
2239
- if (hits.length >= 3) return false;
2240
- hits.push(now);
2241
- pushHits.set(key, hits);
2242
- return true;
2243
- });
2975
+ const rateLimit = buildRateLimit(opts.rateLimit);
2976
+ const decoyOn = opts.decoy !== false;
2977
+ const pushFloorMs = opts.pushFloorMs ?? 1e3;
2978
+ const revocation = opts.revocation === false ? void 0 : opts.revocation ?? ocspRevocationChecker();
2979
+ const revocationMode = opts.revocationMode ?? "soft-fail";
2980
+ const auditKey = opts.auditKey ?? (0, import_node_crypto7.randomBytes)(32);
2981
+ const pushKey = (idCode) => (0, import_node_crypto7.createHmac)("sha256", auditKey).update(`eid-push-audit:${idCode}`).digest("hex").slice(0, 32);
2982
+ async function emit(kind, sessionId, meta, ctx2) {
2983
+ if (!opts.onEvent) return;
2984
+ try {
2985
+ await opts.onEvent({ kind, sessionId, meta });
2986
+ } catch (e) {
2987
+ onError(e, ctx2);
2988
+ }
2989
+ }
2990
+ function endEvent(tx, endResult, ctx2) {
2991
+ const kind = endResult?.startsWith("USER_REFUSED") ? "refused" : endResult === "TIMEOUT" ? "expired" : "failed";
2992
+ return emit(kind, tx.sessionId, { mode: tx.mode, endResult: endResult ?? "UNKNOWN" }, ctx2);
2993
+ }
2994
+ function unverified(tx, e, ctx2) {
2995
+ const reason = e instanceof RevocationFailure ? e.revoked ? "revoked" : "revocation_unavailable" : "validation";
2996
+ return emit("unverified", tx.sessionId, { mode: tx.mode, reason }, ctx2);
2997
+ }
2244
2998
  const displayText = (opts.displayText ?? `${client.rpName}-\u0434 \u043D\u044D\u0432\u0442\u0440\u044D\u0445`).slice(0, 60);
2245
2999
  const interactions = [{ type: "displayTextAndPIN", displayText60: displayText }];
2246
3000
  const json = (status2, body, extra = {}) => ({
@@ -2331,11 +3085,18 @@ function createEidLogin(opts) {
2331
3085
  });
2332
3086
  }
2333
3087
  }
2334
- const binding = (0, import_node_crypto6.randomBytes)(32).toString("base64url");
3088
+ return { ...await save(tx), appLink };
3089
+ }
3090
+ async function save(tx) {
3091
+ const binding = (0, import_node_crypto7.randomBytes)(32).toString("base64url");
2335
3092
  const full = { ...tx, bindingHash: sha256hex(binding), expiresAt: Date.now() + ttl };
2336
3093
  await store.set(full.sessionId, full, ttl);
2337
3094
  const setCookie = `${cookieName}=${full.sessionId}.${binding}; ${cookieAttrs(Math.ceil(ttl / 1e3))}`;
2338
- return { tx: full, setCookie, appLink };
3095
+ return { tx: full, setCookie, appLink: void 0 };
3096
+ }
3097
+ function startDecoy() {
3098
+ const acsp = void 0;
3099
+ return save({ sessionId: (0, import_node_crypto7.randomUUID)(), mode: "push", vc: String((0, import_node_crypto7.randomInt)(1e5)).padStart(5, "0"), acsp, decoy: true });
2339
3100
  }
2340
3101
  async function start(req) {
2341
3102
  const url = new URL(req.url, "http://x");
@@ -2361,22 +3122,40 @@ function createEidLogin(opts) {
2361
3122
  const mode = body.mode;
2362
3123
  if (mode !== "qr" && mode !== "push" && mode !== "web2app") return json(400, { error: "invalid_mode" });
2363
3124
  const lang = body.lang === "en" ? "eng" : "mon";
2364
- const ctx = { request: req, mode };
3125
+ const ctx2 = { request: req, mode };
2365
3126
  if (mode === "web2app" && !opts.callbackUrl) return json(400, { error: "web2app_not_configured" });
2366
3127
  const idCode = typeof body.idCode === "string" ? body.idCode.replace(/\s+/g, "").toUpperCase() : "";
2367
3128
  if (mode === "push" && !ID_RE.test(idCode)) return json(400, { error: "invalid_id" });
2368
- const limited = () => json(429, { error: "rate_limited" }, { "Retry-After": "60" });
3129
+ const limited = async () => {
3130
+ if (mode === "push") await emit("push_limited", null, { mode, pushKey: pushKey(idCode) }, ctx2);
3131
+ return json(429, { error: "rate_limited" }, { "Retry-After": "60" });
3132
+ };
2369
3133
  const ip = req.ip || (opts.trustProxy ? forwardedClientIp(req.headers, opts.trustProxy) : void 0);
2370
3134
  if (ip && !await rateLimit(`start:${ip}`)) return limited();
2371
3135
  if (mode === "push" && !await rateLimit(`push:${idCode}`)) return limited();
3136
+ const began = Date.now();
2372
3137
  let r;
3138
+ let err;
3139
+ let decoy = false;
2373
3140
  try {
2374
3141
  r = await begin(req, mode, idCode, lang);
2375
3142
  } catch (e) {
2376
- onError(e, ctx);
2377
- const status2 = e instanceof ApiError && e.status === 429 ? 429 : 502;
2378
- return json(status2, { error: status2 === 429 ? "rate_limited" : "eid_unavailable" });
3143
+ err = e;
3144
+ }
3145
+ if (err !== void 0 && mode === "push" && decoyOn && isRefusal(err)) {
3146
+ const ae = err;
3147
+ onError(new Error(`eid-login: eID push-\u0438\u0439\u0433 \u0442\u0430\u0442\u0433\u0430\u043B\u0437\u0430\u0432 (${ae.status}${ae.code ? ` ${ae.code}` : ""}); decoy session-\u043E\u043E\u0440 \u0445\u0430\u0440\u0438\u0443\u043B\u0430\u0432`), ctx2);
3148
+ err = void 0;
3149
+ r = await startDecoy();
3150
+ decoy = true;
3151
+ }
3152
+ if (mode === "push" && pushFloorMs > 0) await sleep(began + pushFloorMs - Date.now(), req.signal);
3153
+ if (err !== void 0 || !r) {
3154
+ onError(err, ctx2);
3155
+ if (err instanceof ApiError && err.status === 429) return limited();
3156
+ return json(502, { error: "eid_unavailable" });
2379
3157
  }
3158
+ if (mode === "push") await emit("push_sent", r.tx.sessionId, { mode, pushKey: pushKey(idCode), decoy }, ctx2);
2380
3159
  if (mode === "web2app") {
2381
3160
  return { status: 302, headers: { Location: r.appLink, "Cache-Control": "no-store", "Referrer-Policy": "no-referrer", "Set-Cookie": r.setCookie }, body: "" };
2382
3161
  }
@@ -2388,30 +3167,49 @@ function createEidLogin(opts) {
2388
3167
  }
2389
3168
  async function finish(req, tx, r, flow, verifier) {
2390
3169
  const v = client.validator.validateAuth(r, tx.acsp, { expectedFlowType: flow, userChallengeVerifier: verifier });
3170
+ const ctx2 = { request: req, mode: tx.mode };
3171
+ let rev;
3172
+ let status2;
3173
+ const checker = revocation && (async (c, i) => status2 = await revocation(c, i));
3174
+ try {
3175
+ rev = await client.validator.checkRevocationWith(v.certificate, checker, revocationMode);
3176
+ } catch (e) {
3177
+ throw new RevocationFailure(`revocation: ${e instanceof Error ? e.message : String(e)}`, status2 === "revoked");
3178
+ }
3179
+ if (rev === "unchecked") onError(new Error("eid-login: OCSP \u0445\u0430\u0440\u0438\u0443\u0433\u04AF\u0439 \u2014 \u0446\u0443\u0446\u043B\u0430\u043B\u0442 \u0448\u0430\u043B\u0433\u0430\u043B\u0433\u04AF\u0439 \u0437\u04E9\u0432\u0448\u04E9\u04E9\u0440\u04E9\u0432 (soft-fail)"), ctx2);
2391
3180
  if (!await store.delete(tx.sessionId)) return void 0;
2392
- const out = await opts.onSuccess(toIdentity(tx.sessionId, r, v, flow), { request: req, mode: tx.mode }) ?? {};
3181
+ const out = await opts.onSuccess(toIdentity(tx.sessionId, r, v, flow, rev), ctx2) ?? {};
3182
+ await emit("success", tx.sessionId, { mode: tx.mode, flow, revocation: rev }, ctx2);
2393
3183
  return out;
2394
3184
  }
2395
3185
  async function status(req) {
2396
3186
  if (req.method !== "GET") return json(405, { error: "method_not_allowed" });
2397
3187
  const tx = await loadTx(req);
2398
3188
  if (!tx) return json(200, { state: "EXPIRED" }, { "Set-Cookie": clearCookie });
2399
- const ctx = { request: req, mode: tx.mode };
3189
+ const ctx2 = { request: req, mode: tx.mode };
2400
3190
  let r;
2401
- try {
2402
- r = await client.session.poll(tx.sessionId, pollMs);
2403
- } catch (e) {
2404
- if (e instanceof ApiError && e.status === 404) {
2405
- await store.delete(tx.sessionId);
2406
- return json(200, { state: "EXPIRED" }, { "Set-Cookie": clearCookie });
3191
+ if (tx.decoy) {
3192
+ await sleep(pollMs, req.signal);
3193
+ r = { state: "RUNNING" };
3194
+ } else {
3195
+ try {
3196
+ r = await client.session.poll(tx.sessionId, pollMs);
3197
+ } catch (e) {
3198
+ if (e instanceof ApiError && e.status === 404) {
3199
+ await store.delete(tx.sessionId);
3200
+ await emit("expired", tx.sessionId, { mode: tx.mode }, ctx2);
3201
+ return json(200, { state: "EXPIRED" }, { "Set-Cookie": clearCookie });
3202
+ }
3203
+ onError(e, ctx2);
3204
+ return json(502, { error: "eid_unavailable" });
2407
3205
  }
2408
- onError(e, ctx);
2409
- return json(502, { error: "eid_unavailable" });
2410
3206
  }
2411
3207
  const expiresIn = Math.max(0, Math.ceil((tx.expiresAt - Date.now()) / 1e3));
2412
3208
  if (r.state !== "COMPLETE") return json(200, { state: "PENDING", qr: qrLink(tx), vc: tx.vc, expiresIn });
2413
3209
  if (r.endResult !== "OK") {
2414
3210
  await store.delete(tx.sessionId);
3211
+ await endEvent(tx, r.endResult, ctx2);
3212
+ if (tx.mode === "push" && r.endResult === "TIMEOUT") return json(200, { state: "EXPIRED" }, { "Set-Cookie": clearCookie });
2415
3213
  return json(200, { state: "FAILED", error: r.endResult ?? "UNKNOWN" }, { "Set-Cookie": clearCookie });
2416
3214
  }
2417
3215
  if (tx.mode === "web2app") return json(200, { state: "WAIT_CALLBACK" });
@@ -2420,9 +3218,10 @@ function createEidLogin(opts) {
2420
3218
  if (!out) return json(200, { state: "EXPIRED" }, { "Set-Cookie": clearCookie });
2421
3219
  return json(200, { state: "OK", redirect: out.redirect, data: out.data }, mergeHeaders({ "Set-Cookie": clearCookie }, out.headers));
2422
3220
  } catch (e) {
2423
- onError(e, ctx);
3221
+ onError(e, ctx2);
2424
3222
  if (!(e instanceof ValidationError || e instanceof SessionFailedError)) return json(500, { error: "internal" });
2425
3223
  await store.delete(tx.sessionId);
3224
+ await unverified(tx, e, ctx2);
2426
3225
  return json(200, { state: "FAILED", error: "VALIDATION" }, { "Set-Cookie": clearCookie });
2427
3226
  }
2428
3227
  }
@@ -2433,19 +3232,23 @@ function createEidLogin(opts) {
2433
3232
  const verifier = q.get("userChallengeVerifier") ?? "";
2434
3233
  const fail2 = (code) => redirect(failTo(code), { "Set-Cookie": clearCookie });
2435
3234
  const tx = await loadTx(req);
2436
- if (!tx || tx.sessionId !== sid || tx.mode !== "web2app") return fail2(tx ? "unbound" : "expired");
2437
- if (!verifier) return fail2("unbound");
2438
- const ctx = { request: req, mode: tx.mode };
3235
+ if (!tx) return fail2("expired");
3236
+ const ctx2 = { request: req, mode: tx.mode };
3237
+ if (tx.sessionId !== sid || tx.mode !== "web2app" || !verifier) {
3238
+ await emit("flow_refused", tx.sessionId, { mode: tx.mode, reason: "unbound" }, ctx2);
3239
+ return fail2("unbound");
3240
+ }
2439
3241
  let r;
2440
3242
  try {
2441
3243
  r = await client.session.poll(tx.sessionId, 1e4);
2442
3244
  } catch (e) {
2443
- onError(e, ctx);
3245
+ onError(e, ctx2);
2444
3246
  return fail2("eid_unavailable");
2445
3247
  }
2446
3248
  if (r.state !== "COMPLETE") return fail2("not_complete");
2447
3249
  if (r.endResult !== "OK") {
2448
3250
  await store.delete(tx.sessionId);
3251
+ await endEvent(tx, r.endResult, ctx2);
2449
3252
  return fail2(r.endResult ?? "UNKNOWN");
2450
3253
  }
2451
3254
  try {
@@ -2453,9 +3256,10 @@ function createEidLogin(opts) {
2453
3256
  if (!out) return fail2("expired");
2454
3257
  return redirect(out.redirect ?? successRedirect, mergeHeaders({ "Set-Cookie": clearCookie }, out.headers));
2455
3258
  } catch (e) {
2456
- onError(e, ctx);
3259
+ onError(e, ctx2);
2457
3260
  if (!(e instanceof ValidationError || e instanceof SessionFailedError)) return fail2("internal");
2458
3261
  await store.delete(tx.sessionId);
3262
+ await unverified(tx, e, ctx2);
2459
3263
  return fail2("VALIDATION");
2460
3264
  }
2461
3265
  }
@@ -2485,7 +3289,7 @@ function createEidLogin(opts) {
2485
3289
  mode: "qr"
2486
3290
  });
2487
3291
  }
2488
- const r = await handleRequest({ method: req.method, url: req.url, headers, body, ip });
3292
+ const r = await handleRequest({ method: req.method, url: req.url, headers, body, ip, signal: req.signal });
2489
3293
  const h = new Headers();
2490
3294
  for (const [k, v] of Object.entries(r.headers)) for (const x of [v].flat()) h.append(k, x);
2491
3295
  return new Response(r.status === 302 || r.status === 303 || r.body === "" ? null : r.body, { status: r.status, headers: h });
@@ -2526,12 +3330,14 @@ function createEidLogin(opts) {
2526
3330
  buildDeviceLink,
2527
3331
  buildRegisterBody,
2528
3332
  createEidLogin,
3333
+ defaultRateLimit,
2529
3334
  deviceLink,
2530
3335
  deviceLinkInput,
2531
3336
  forwardedClientIp,
2532
3337
  interactionsToBase64,
2533
3338
  isMobileUserAgent,
2534
3339
  memoryLoginStore,
3340
+ ocspRevocationChecker,
2535
3341
  openOrShowQR,
2536
3342
  parseExpiresAt,
2537
3343
  parseRetryAfter,