@gerege-systems/eid-mongolia-sdk 0.10.0 → 0.12.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 +25 -4
- package/dist/{browser-BWCDj8xO.d.cts → browser-B_xuB7Rt.d.cts} +24 -3
- package/dist/{browser-BWCDj8xO.d.ts → browser-B_xuB7Rt.d.ts} +24 -3
- package/dist/browser.d.cts +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +1 -1
- package/dist/{chunk-YDVPZMAL.js → chunk-QPJDZLHR.js} +10 -0
- package/dist/index.cjs +252 -30
- package/dist/index.d.cts +81 -6
- package/dist/index.d.ts +81 -6
- package/dist/index.js +243 -31
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { R as RpCredentials, C as CertificateLevel, I as Interaction, S as SignatureAlgorithm, H as HashAlgorithm, N as NotificationSession, D as DeviceLinkSession, a as SessionResult, P as PersonBlock, b as PdfSessionBlock, c as RepresentationsResponse, A as AcspContext, F as FlowType, E as EidError } from './browser-
|
|
2
|
-
export { d as ApiError, e as AuthenticationError, f as DeviceLinkError, g as DeviceLinkInput, h as EndResult, i as ForbiddenError, j as HttpErrorInit, k as NavigatorLike, l as NetworkError, O as ON_BEHALF_ERROR_CODES, m as OnBehalfErrorCode, n as OpenOrShowQROptions, o as OrgResult, p as PdfDocumentStatus, q as PdfSigner, r as RETRYABLE_ERROR_CODES, s as Representation, t as
|
|
1
|
+
import { R as RpCredentials, C as CertificateLevel, I as Interaction, S as SignatureAlgorithm, H as HashAlgorithm, N as NotificationSession, D as DeviceLinkSession, a as SessionResult, P as PersonBlock, b as PdfSessionBlock, c as RepresentationsResponse, A as AcspContext, F as FlowType, E as EidError } from './browser-B_xuB7Rt.js';
|
|
2
|
+
export { d as ApiError, e as AuthenticationError, f as DeviceLinkError, g as DeviceLinkInput, h as EndResult, i as ForbiddenError, j as HttpErrorInit, k as NavigatorLike, l as NetworkError, O as ON_BEHALF_ERROR_CODES, m as OnBehalfErrorCode, n as OpenOrShowQROptions, o as OrgResult, p as PdfDocumentStatus, q as PdfSigner, r as RETRYABLE_ERROR_CODES, s as Representation, t as ResponseTooLargeError, u as RetryableErrorCode, v as SessionFailedError, w as SessionState, x as SignatureAlgorithmParameters, y as SignatureProtocol, T as TokenCertSessionBlock, z as TokenCertStatus, V as ValidationError, B as deviceLink, G as isMobileUserAgent, J as openOrShowQR, K as parseRetryAfter } from './browser-B_xuB7Rt.js';
|
|
3
3
|
import { X509Certificate, KeyObject } from 'node:crypto';
|
|
4
4
|
|
|
5
5
|
interface HttpConfig {
|
|
@@ -17,6 +17,8 @@ interface HttpConfig {
|
|
|
17
17
|
dispatcher?: unknown;
|
|
18
18
|
/** Тест/custom орчинд fetch-ийг орлуулах (default — global fetch). */
|
|
19
19
|
fetchImpl?: typeof fetch;
|
|
20
|
+
/** `Accept-Language` header-ийн утга (ж: "en"); хоосон бол илгээхгүй. */
|
|
21
|
+
language?: string;
|
|
20
22
|
}
|
|
21
23
|
declare class Http {
|
|
22
24
|
private readonly cfg;
|
|
@@ -25,8 +27,8 @@ declare class Http {
|
|
|
25
27
|
get(path: string, timeoutMs?: number): Promise<unknown>;
|
|
26
28
|
/** multipart/form-data POST (Content-Type-ийг boundary-тай нь fetch тавина). JSON хариу. */
|
|
27
29
|
postMultipart(path: string, form: FormData, timeoutMs?: number): Promise<unknown>;
|
|
28
|
-
/** GET — хариуг байтаар (ж: гарын үсэгтэй PDF). */
|
|
29
|
-
getBytes(path: string, timeoutMs?: number): Promise<Uint8Array>;
|
|
30
|
+
/** GET — хариуг байтаар (ж: гарын үсэгтэй PDF), `maxBytes` хүртэл; хэтэрвэл {@link ResponseTooLargeError}. */
|
|
31
|
+
getBytes(path: string, timeoutMs?: number, maxBytes?: number): Promise<Uint8Array>;
|
|
30
32
|
private json;
|
|
31
33
|
private send;
|
|
32
34
|
}
|
|
@@ -153,7 +155,11 @@ interface PdfDefaults {
|
|
|
153
155
|
certificateLevel: CertificateLevel;
|
|
154
156
|
/** prepare / document дуудлагын хугацаа (мс); анхдагч {@link DEFAULT_PDF_TIMEOUT_MS}. */
|
|
155
157
|
timeoutMs?: number;
|
|
158
|
+
/** document / tokenDocument-ийн санах ойд унших дээд хэмжээ (байт); анхдагч {@link DEFAULT_PDF_MAX_BYTES}. */
|
|
159
|
+
maxBytes?: number;
|
|
156
160
|
}
|
|
161
|
+
/** Гарын үсэгтэй PDF татахад санах ойд уншиж болох анхдагч дээд хэмжээ (64 MiB) — `ClientConfig.pdfMaxBytes`. */
|
|
162
|
+
declare const DEFAULT_PDF_MAX_BYTES: number;
|
|
157
163
|
/**
|
|
158
164
|
* PAdES prepare / баримт татах нэг дуудлагын анхдагч хугацаа (мс). CA prepare нь ≤ 10 MiB уншиж, өмнөх гарын үсэг +
|
|
159
165
|
* LTV өгөгдөл шалгаад push эхлүүлдэг; баримт татахад угсралтыг ≤ 30с хүлээдэг (PADES_SIGNING §3.4). 80с нь хоёуланд
|
|
@@ -209,6 +215,35 @@ interface PdfPrepareSession {
|
|
|
209
215
|
/** SDK хариу хүлээн авсан мөч (ms epoch) — QR-ийн `receivedAt` ({@link buildDeviceLink}). */
|
|
210
216
|
receivedAt: number;
|
|
211
217
|
}
|
|
218
|
+
/** USB токены PAdES — POST /pdf/token/prepare-ийн оролт. */
|
|
219
|
+
interface PdfTokenPrepareInput {
|
|
220
|
+
/** Эх PDF (≤ 10 223 616 байт). */
|
|
221
|
+
pdf: Uint8Array;
|
|
222
|
+
/** Баримтын нэр (≤ 120 тэмдэгт, заавал). */
|
|
223
|
+
fileName: string;
|
|
224
|
+
/** Иргэний ETSI (`PNOMN-…`) — токены гэрчилгээний SERIALNUMBER-тэй таарна. */
|
|
225
|
+
signerEtsi: string;
|
|
226
|
+
/** Токены SIGN гэрчилгээ (DER): eID Mongolia Issuing CA-аас, ACTIVE токенд холбогдсон. */
|
|
227
|
+
certificate: Uint8Array;
|
|
228
|
+
/** Олон гарын үсэгтэй баримтын docID (заавал биш, UUID). */
|
|
229
|
+
docID?: string;
|
|
230
|
+
/** Байгууллагын токенд ЗААВАЛ тухайн байгууллага (`NTRMN-…`); хувийн токенд хоосон. Зөрвөл 403 TOKEN_ORG_MISMATCH. */
|
|
231
|
+
onBehalfOf?: string;
|
|
232
|
+
}
|
|
233
|
+
/** POST /pdf/token/prepare-ийн хариу. */
|
|
234
|
+
interface PdfTokenPrepareSession {
|
|
235
|
+
signingId: string;
|
|
236
|
+
docId: string;
|
|
237
|
+
/** Токеноор зурах 32 байт (SHA-256 DTBS): CKM_ECDSA (prehashed) → түүхий r||s (64 байт). */
|
|
238
|
+
hashToSign: Uint8Array;
|
|
239
|
+
hashAlgorithm: string;
|
|
240
|
+
signatureAlgorithm: string;
|
|
241
|
+
/** "RAW_RS". */
|
|
242
|
+
signatureFormat: string;
|
|
243
|
+
/** tokenFinalize-ийн эцсийн хугацаа (prepare-ээс 10 мин), ISO-8601. */
|
|
244
|
+
expiresAt: string;
|
|
245
|
+
raw: unknown;
|
|
246
|
+
}
|
|
212
247
|
declare class PdfApi {
|
|
213
248
|
private readonly http;
|
|
214
249
|
private readonly creds;
|
|
@@ -226,6 +261,28 @@ declare class PdfApi {
|
|
|
226
261
|
* дараа дахин татна (`retryable`).
|
|
227
262
|
*/
|
|
228
263
|
document(sessionId: string): Promise<Uint8Array>;
|
|
264
|
+
private get timeout();
|
|
265
|
+
private get maxBytes();
|
|
266
|
+
/**
|
|
267
|
+
* USB токены PAdES (CA docs/PADES_SIGNING.md §16.5, TOKEN_CERT.md) — session / утас оролцохгүй. POST /pdf/token/prepare
|
|
268
|
+
* (multipart: `request` JSON + `pdf`), SIGN эрх. Дараа нь токеноор `hashToSign`-ийг CKM_ECDSA (prehashed, P-256)-аар
|
|
269
|
+
* зурж {@link tokenFinalize}. Түр алдаа: `ApiError` 429 PDF_PREPARE_BUSY / RATE_LIMITED, 503 TSA_UNAVAILABLE /
|
|
270
|
+
* LTV_UNAVAILABLE / STATE_UNAVAILABLE (`retryable`). Гэрчилгээ токенд холбогдоогүй / цуцлагдсан → 409
|
|
271
|
+
* TOKEN_CERT_INVALID. Зам нь CA-д бий ч `/.well-known/eid`-д хараахан алга (гэрээний тест WARN).
|
|
272
|
+
*/
|
|
273
|
+
tokenPrepare(input: PdfTokenPrepareInput): Promise<PdfTokenPrepareSession>;
|
|
274
|
+
/**
|
|
275
|
+
* POST /pdf/token/{signingID}/finalize `{signature: base64 түүхий r||s}` — `signature` 64 байт (P-256 r||s, DER БИШ).
|
|
276
|
+
* Амжвал READY баримтын блок (`outSha256` — {@link tokenDocument}-оор татсан файлтай тулга). READY-ээс хойш идэмпотент.
|
|
277
|
+
* Алдаа: 400 SIGNATURE_INVALID (3 удаа → FAILED), 409 DOCUMENT_FAILED, 410 DOCUMENT_EXPIRED, 503 DOCUMENT_PENDING /
|
|
278
|
+
* TSA_UNAVAILABLE / LTV_UNAVAILABLE — ижил гарын үсгийг `retryAfterMs`-ийн дараа дахин илгээнэ.
|
|
279
|
+
*/
|
|
280
|
+
tokenFinalize(signingId: string, signature: Uint8Array): Promise<PdfSessionBlock>;
|
|
281
|
+
/**
|
|
282
|
+
* GET /pdf/token/{signingID}/document — гарын үсэгтэй PDF (зөвхөн үүсгэсэн RP, expiresAt хүртэл), `pdfMaxBytes`
|
|
283
|
+
* хүртэл. SHA-256-ийг {@link tokenFinalize}-ийн `outSha256`-тай заавал тулга.
|
|
284
|
+
*/
|
|
285
|
+
tokenDocument(signingId: string): Promise<Uint8Array>;
|
|
229
286
|
/**
|
|
230
287
|
* {@link document} + тулгалт: татсан байтын SHA-256 нь session poll-ийн `pdf.outSha256`-тай тэнцүү байх ёстой.
|
|
231
288
|
* `expected` — poll-ийн `result.pdf` блок (`documentStatus` READY + `outSha256` заавал) эсвэл SHA-256 hex.
|
|
@@ -696,7 +753,15 @@ declare class ResponseValidator {
|
|
|
696
753
|
private checkIssuer;
|
|
697
754
|
private checkValidity;
|
|
698
755
|
private checkLevel;
|
|
699
|
-
/**
|
|
756
|
+
/**
|
|
757
|
+
* RFC 5280 замын шалгалт (Go SDK-ийн `x509.Certificate.Verify`-тэй ижил дүрэм): leaf-ээс trust anchor хүртэлх
|
|
758
|
+
* замыг intermediates/anchors-оос (backtracking-тай) угсарна. Issuer бүр: subject = child.issuer, AKI/SKI таарах,
|
|
759
|
+
* гарын үсэг, CA (basicConstraints CA:TRUE), KeyUsage тавьсан бол keyCertSign, **pathLenConstraint** (доорх
|
|
760
|
+
* завсрын CA-ийн тоо), хүчинтэй хугацаа, EKU тавьсан бол `usage` / anyExtendedKeyUsage агуулах. Leaf болон CA
|
|
761
|
+
* бүрийн үл таних **critical extension** → татгалзана. **Name constraints**-ийг SDK үнэлдэггүй — гинжинд байвал
|
|
762
|
+
* fail-closed (CA-ийн бодит гинж 01–04-т алга). Цаг = now, leaf-ийн хүчинтэй хугацаанд хавчсан (`clockSkewMs`-ийн
|
|
763
|
+
* хүрээнд; leaf-ийн хугацааг checkValidity шалгасан). certificatePolicies шалгахгүй (Go-той ижил).
|
|
764
|
+
*/
|
|
700
765
|
private verifyChain;
|
|
701
766
|
/** leaf-ийн шууд issuer-ийг trust pool-оос буцаана (revocation шалгагчид issuer хэрэгтэй). */
|
|
702
767
|
private findIssuer;
|
|
@@ -734,10 +799,20 @@ interface ClientConfig {
|
|
|
734
799
|
timeoutMs?: number;
|
|
735
800
|
/** PAdES prepare / баримт татах дуудлагын хугацаа (мс). Анхдагч 80000 ({@link DEFAULT_PDF_TIMEOUT_MS}). */
|
|
736
801
|
pdfTimeoutMs?: number;
|
|
802
|
+
/**
|
|
803
|
+
* `pdf.document` / `pdf.tokenDocument`-ийн санах ойд унших дээд хэмжээ (байт). Анхдагч 64 MiB
|
|
804
|
+
* ({@link DEFAULT_PDF_MAX_BYTES}); хэтэрвэл `ResponseTooLargeError`.
|
|
805
|
+
*/
|
|
806
|
+
pdfMaxBytes?: number;
|
|
737
807
|
/** undici Dispatcher (mTLS client cert). */
|
|
738
808
|
dispatcher?: unknown;
|
|
739
809
|
/** fetch орлуулагч (тест). */
|
|
740
810
|
fetchImpl?: typeof fetch;
|
|
811
|
+
/**
|
|
812
|
+
* Хүнд харуулах текстийн хэл (`roleLabel` г.м.) — дуудлага бүрд `Accept-Language` болж илгээгдэнэ (`"mn"` | `"en"`).
|
|
813
|
+
* Анхдагч: илгээхгүй (сервер mn).
|
|
814
|
+
*/
|
|
815
|
+
language?: string;
|
|
741
816
|
/** Trust anchor (Root CA) — validator-д. Production-д ЗААВАЛ. */
|
|
742
817
|
trust?: TrustConfig;
|
|
743
818
|
}
|
|
@@ -989,4 +1064,4 @@ declare class EidOidcClient {
|
|
|
989
1064
|
/** PKCE S256: `BASE64URL(SHA-256(ASCII(code_verifier)))` (RFC 7636 §4.2). */
|
|
990
1065
|
declare function pkceChallenge(codeVerifier: string): Promise<string>;
|
|
991
1066
|
|
|
992
|
-
export { AcspContext, type AcspV2Params, type ActivityCounts, type ActivityItem, type ActivityQuery, AuthApi, type AuthDefaults, type AuthOptions, type BuildDeviceLinkInput, CITIZEN_ISSUING_CA_SKI, type CertCounts, type CertSubject, CertificateLevel, type ClientConfig, type CreateAuthorizationOptions, DEFAULT_BASE_URL, DEFAULT_PDF_TIMEOUT_MS, DeviceLinkSession, type DeviceLinkSessionType, type DeviceLinkType, EID_ACR_ADVANCED, EID_ACR_QUALIFIED, EID_OIDC_ISSUER, type EidAuthorization, type EidCallbackChecks, type EidCallbackResult, EidClient, EidError, type EidIdTokenClaims, EidOidcClient, type EidOidcClientConfig, type EidOidcDiscovery, EidOidcError, type EidOidcErrorCode, FlowType, HashAlgorithm, Http, type HttpConfig, Interaction, NotificationSession, OrganizationApi, PdfApi, type PdfDefaults, type PdfPrepareInput, type PdfPrepareSession, PdfSessionBlock, type PdfSignerRef, type PersonActivity, PersonApi, PersonBlock, type PersonCertificate, type PersonCertificates, type PersonChild, type PersonChildren, type PersonDevice, type PersonDevices, type PersonSummary, type QrDeviceLinkTickerOptions, RepresentationsResponse, ResponseValidator, type RevocationChecker, type RevocationOutcome, type RevocationStatus, RpCredentials, SessionApi, SessionResult, SignApi, type SignDefaults, type SignOptions, SignatureAlgorithm, TokenApi, type TokenAuthChallenge, type TokenAuthResult, type TokenCertInput, type TokenCertItem, type TokenCertResult, type TokenCertStart, type TokenIdentity, type TokenLimit, type TokenOrganization, type TrustConfig, type ValidateAuthOptions, type ValidateSignOptions, type VerifiedIdentity, type VerifiedSignature, acspV2Digest, buildAcspV2Payload, buildDeviceLink, interactionsToBase64, parseSessionResult, parseSubject, personMatchesCertificate, pkceChallenge, qrDeviceLinkTicker, randomChallenge, resolveBaseUrl, sha256Base64, tokenAuthDigest, tokenLimitOf, userChallengeOf, verifyPayloadSignature, verifyPrehashedSignature, verifyTokenCertificates };
|
|
1067
|
+
export { AcspContext, type AcspV2Params, type ActivityCounts, type ActivityItem, type ActivityQuery, AuthApi, type AuthDefaults, type AuthOptions, type BuildDeviceLinkInput, CITIZEN_ISSUING_CA_SKI, type CertCounts, type CertSubject, CertificateLevel, type ClientConfig, type CreateAuthorizationOptions, DEFAULT_BASE_URL, DEFAULT_PDF_MAX_BYTES, DEFAULT_PDF_TIMEOUT_MS, DeviceLinkSession, type DeviceLinkSessionType, type DeviceLinkType, EID_ACR_ADVANCED, EID_ACR_QUALIFIED, EID_OIDC_ISSUER, type EidAuthorization, type EidCallbackChecks, type EidCallbackResult, EidClient, EidError, type EidIdTokenClaims, EidOidcClient, type EidOidcClientConfig, type EidOidcDiscovery, EidOidcError, type EidOidcErrorCode, FlowType, HashAlgorithm, Http, type HttpConfig, Interaction, NotificationSession, OrganizationApi, PdfApi, type PdfDefaults, type PdfPrepareInput, type PdfPrepareSession, PdfSessionBlock, type PdfSignerRef, type PdfTokenPrepareInput, type PdfTokenPrepareSession, type PersonActivity, PersonApi, PersonBlock, type PersonCertificate, type PersonCertificates, type PersonChild, type PersonChildren, type PersonDevice, type PersonDevices, type PersonSummary, type QrDeviceLinkTickerOptions, RepresentationsResponse, ResponseValidator, type RevocationChecker, type RevocationOutcome, type RevocationStatus, RpCredentials, SessionApi, SessionResult, SignApi, type SignDefaults, type SignOptions, SignatureAlgorithm, TokenApi, type TokenAuthChallenge, type TokenAuthResult, type TokenCertInput, type TokenCertItem, type TokenCertResult, type TokenCertStart, type TokenIdentity, type TokenLimit, type TokenOrganization, type TrustConfig, type ValidateAuthOptions, type ValidateSignOptions, type VerifiedIdentity, type VerifiedSignature, acspV2Digest, buildAcspV2Payload, buildDeviceLink, interactionsToBase64, parseSessionResult, parseSubject, personMatchesCertificate, pkceChallenge, qrDeviceLinkTicker, randomChallenge, resolveBaseUrl, sha256Base64, tokenAuthDigest, tokenLimitOf, userChallengeOf, verifyPayloadSignature, verifyPrehashedSignature, verifyTokenCertificates };
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
NetworkError,
|
|
8
8
|
ON_BEHALF_ERROR_CODES,
|
|
9
9
|
RETRYABLE_ERROR_CODES,
|
|
10
|
+
ResponseTooLargeError,
|
|
10
11
|
SessionFailedError,
|
|
11
12
|
ValidationError,
|
|
12
13
|
deviceLink,
|
|
@@ -14,10 +15,11 @@ import {
|
|
|
14
15
|
maskPath,
|
|
15
16
|
openOrShowQR,
|
|
16
17
|
parseRetryAfter
|
|
17
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-QPJDZLHR.js";
|
|
18
19
|
|
|
19
20
|
// src/http.ts
|
|
20
21
|
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
22
|
+
var MAX_JSON_BYTES = 4 << 20;
|
|
21
23
|
var Http = class {
|
|
22
24
|
constructor(cfg) {
|
|
23
25
|
this.cfg = cfg;
|
|
@@ -33,14 +35,14 @@ var Http = class {
|
|
|
33
35
|
postMultipart(path, form, timeoutMs) {
|
|
34
36
|
return this.json("POST", path, form, void 0, timeoutMs);
|
|
35
37
|
}
|
|
36
|
-
/** GET — хариуг байтаар (ж: гарын үсэгтэй PDF). */
|
|
37
|
-
async getBytes(path, timeoutMs) {
|
|
38
|
+
/** GET — хариуг байтаар (ж: гарын үсэгтэй PDF), `maxBytes` хүртэл; хэтэрвэл {@link ResponseTooLargeError}. */
|
|
39
|
+
async getBytes(path, timeoutMs, maxBytes = 64 << 20) {
|
|
38
40
|
const res = await this.send("GET", path, void 0, void 0, timeoutMs);
|
|
39
|
-
return
|
|
41
|
+
return readLimited(res, maxBytes, `GET ${maskPath(path)}`);
|
|
40
42
|
}
|
|
41
43
|
async json(method, path, body, contentType, timeoutMs) {
|
|
42
44
|
const res = await this.send(method, path, body, contentType, timeoutMs);
|
|
43
|
-
const text = await res
|
|
45
|
+
const text = new TextDecoder().decode(await readLimited(res, MAX_JSON_BYTES, `${method} ${maskPath(path)}`));
|
|
44
46
|
return text ? JSON.parse(text) : {};
|
|
45
47
|
}
|
|
46
48
|
async send(method, path, body, contentType, timeoutMs) {
|
|
@@ -50,7 +52,8 @@ var Http = class {
|
|
|
50
52
|
method,
|
|
51
53
|
headers: {
|
|
52
54
|
Authorization: `Bearer ${this.cfg.apiSecret}`,
|
|
53
|
-
...contentType ? { "Content-Type": contentType } : {}
|
|
55
|
+
...contentType ? { "Content-Type": contentType } : {},
|
|
56
|
+
...this.cfg.language ? { "Accept-Language": this.cfg.language } : {}
|
|
54
57
|
},
|
|
55
58
|
body,
|
|
56
59
|
signal: AbortSignal.timeout(timeoutMs ?? this.cfg.timeoutMs ?? DEFAULT_TIMEOUT_MS)
|
|
@@ -85,6 +88,34 @@ var Http = class {
|
|
|
85
88
|
throw new ApiError(res.status, text, code, { headers, retryAfterMs });
|
|
86
89
|
}
|
|
87
90
|
};
|
|
91
|
+
async function readLimited(res, limit, op) {
|
|
92
|
+
const declared = Number(res.headers.get("content-length") ?? NaN);
|
|
93
|
+
if (declared > limit) {
|
|
94
|
+
await res.body?.cancel().catch(() => void 0);
|
|
95
|
+
throw new ResponseTooLargeError(op, limit);
|
|
96
|
+
}
|
|
97
|
+
if (!res.body) return new Uint8Array(0);
|
|
98
|
+
const reader = res.body.getReader();
|
|
99
|
+
const chunks = [];
|
|
100
|
+
let total = 0;
|
|
101
|
+
for (; ; ) {
|
|
102
|
+
const { done, value } = await reader.read();
|
|
103
|
+
if (done) break;
|
|
104
|
+
total += value.byteLength;
|
|
105
|
+
if (total > limit) {
|
|
106
|
+
await reader.cancel().catch(() => void 0);
|
|
107
|
+
throw new ResponseTooLargeError(op, limit);
|
|
108
|
+
}
|
|
109
|
+
chunks.push(value);
|
|
110
|
+
}
|
|
111
|
+
const out = new Uint8Array(total);
|
|
112
|
+
let off = 0;
|
|
113
|
+
for (const c of chunks) {
|
|
114
|
+
out.set(c, off);
|
|
115
|
+
off += c.byteLength;
|
|
116
|
+
}
|
|
117
|
+
return out;
|
|
118
|
+
}
|
|
88
119
|
function errorBody(text) {
|
|
89
120
|
try {
|
|
90
121
|
const v = JSON.parse(text);
|
|
@@ -121,7 +152,10 @@ var RP_ROUTES = {
|
|
|
121
152
|
};
|
|
122
153
|
var RP_ROUTES_UNDISCOVERED = {
|
|
123
154
|
tokenAuthChallenge: { method: "POST", path: "/token/auth/challenge" },
|
|
124
|
-
tokenAuthVerify: { method: "POST", path: "/token/auth/verify" }
|
|
155
|
+
tokenAuthVerify: { method: "POST", path: "/token/auth/verify" },
|
|
156
|
+
pdfTokenPrepare: { method: "POST", path: "/pdf/token/prepare" },
|
|
157
|
+
pdfTokenFinalize: { method: "POST", path: "/pdf/token/{signingID}/finalize" },
|
|
158
|
+
pdfTokenDocument: { method: "GET", path: "/pdf/token/{signingID}/document" }
|
|
125
159
|
};
|
|
126
160
|
function routePath(route, ...args) {
|
|
127
161
|
let i = 0;
|
|
@@ -429,10 +463,12 @@ function parseOrg(raw) {
|
|
|
429
463
|
const o = asRecord(raw);
|
|
430
464
|
const etsi = str(o.orgEtsi);
|
|
431
465
|
if (!etsi) return null;
|
|
466
|
+
const roleLabel = str(o.roleLabel);
|
|
432
467
|
return {
|
|
433
468
|
orgEtsi: etsi,
|
|
434
469
|
orgName: str(o.orgName),
|
|
435
470
|
role: str(o.role),
|
|
471
|
+
...roleLabel ? { roleLabel } : {},
|
|
436
472
|
rightType: str(o.rightType)
|
|
437
473
|
};
|
|
438
474
|
}
|
|
@@ -469,6 +505,7 @@ var SessionApi = class {
|
|
|
469
505
|
|
|
470
506
|
// src/pdf.ts
|
|
471
507
|
import { createHash as createHash2 } from "crypto";
|
|
508
|
+
var DEFAULT_PDF_MAX_BYTES = 64 << 20;
|
|
472
509
|
var DEFAULT_PDF_TIMEOUT_MS = 8e4;
|
|
473
510
|
function rec3(v) {
|
|
474
511
|
return v && typeof v === "object" ? v : {};
|
|
@@ -501,7 +538,7 @@ var PdfApi = class {
|
|
|
501
538
|
const form = new FormData();
|
|
502
539
|
form.append("request", new Blob([JSON.stringify(request)], { type: "application/json" }));
|
|
503
540
|
form.append("pdf", new Blob([input.pdf], { type: "application/pdf" }), input.fileName);
|
|
504
|
-
const r = rec3(await this.http.postMultipart(routePath(RP_ROUTES.pdfPrepare), form, this.
|
|
541
|
+
const r = rec3(await this.http.postMultipart(routePath(RP_ROUTES.pdfPrepare), form, this.timeout));
|
|
505
542
|
const receivedAt = Date.now();
|
|
506
543
|
const vc = rec3(r.vc).value;
|
|
507
544
|
const dl = rec3(r.deviceLink);
|
|
@@ -528,7 +565,75 @@ var PdfApi = class {
|
|
|
528
565
|
* дараа дахин татна (`retryable`).
|
|
529
566
|
*/
|
|
530
567
|
document(sessionId) {
|
|
531
|
-
return this.http.getBytes(routePath(RP_ROUTES.pdfDocument, sessionId), this.
|
|
568
|
+
return this.http.getBytes(routePath(RP_ROUTES.pdfDocument, sessionId), this.timeout, this.maxBytes);
|
|
569
|
+
}
|
|
570
|
+
get timeout() {
|
|
571
|
+
return this.defaults.timeoutMs ?? DEFAULT_PDF_TIMEOUT_MS;
|
|
572
|
+
}
|
|
573
|
+
get maxBytes() {
|
|
574
|
+
return this.defaults.maxBytes ?? DEFAULT_PDF_MAX_BYTES;
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* USB токены PAdES (CA docs/PADES_SIGNING.md §16.5, TOKEN_CERT.md) — session / утас оролцохгүй. POST /pdf/token/prepare
|
|
578
|
+
* (multipart: `request` JSON + `pdf`), SIGN эрх. Дараа нь токеноор `hashToSign`-ийг CKM_ECDSA (prehashed, P-256)-аар
|
|
579
|
+
* зурж {@link tokenFinalize}. Түр алдаа: `ApiError` 429 PDF_PREPARE_BUSY / RATE_LIMITED, 503 TSA_UNAVAILABLE /
|
|
580
|
+
* LTV_UNAVAILABLE / STATE_UNAVAILABLE (`retryable`). Гэрчилгээ токенд холбогдоогүй / цуцлагдсан → 409
|
|
581
|
+
* TOKEN_CERT_INVALID. Зам нь CA-д бий ч `/.well-known/eid`-д хараахан алга (гэрээний тест WARN).
|
|
582
|
+
*/
|
|
583
|
+
async tokenPrepare(input) {
|
|
584
|
+
if (!input.pdf?.length || !input.certificate?.length || !input.signerEtsi?.trim() || !input.fileName?.trim()) {
|
|
585
|
+
throw new Error("eid: pdf token: pdf, certificate, signerEtsi, fileName \u0448\u0430\u0430\u0440\u0434\u043B\u0430\u0433\u0430\u0442\u0430\u0439");
|
|
586
|
+
}
|
|
587
|
+
const request = {
|
|
588
|
+
relyingPartyUUID: this.creds.rpUUID,
|
|
589
|
+
relyingPartyName: this.creds.rpName,
|
|
590
|
+
signer: { etsi: input.signerEtsi.trim() },
|
|
591
|
+
certificate: Buffer.from(input.certificate).toString("base64"),
|
|
592
|
+
fileName: input.fileName
|
|
593
|
+
};
|
|
594
|
+
if (input.docID?.trim()) request.docID = input.docID.trim();
|
|
595
|
+
if (input.onBehalfOf?.trim()) request.onBehalfOf = input.onBehalfOf.trim();
|
|
596
|
+
const form = new FormData();
|
|
597
|
+
form.append("request", new Blob([JSON.stringify(request)], { type: "application/json" }));
|
|
598
|
+
form.append("pdf", new Blob([input.pdf], { type: "application/pdf" }), input.fileName);
|
|
599
|
+
const raw = await this.http.postMultipart(routePath(RP_ROUTES_UNDISCOVERED.pdfTokenPrepare), form, this.timeout);
|
|
600
|
+
const r = rec3(raw);
|
|
601
|
+
const hashToSign = new Uint8Array(Buffer.from(String(r.hashToSign ?? ""), "base64"));
|
|
602
|
+
if (!r.signingID || hashToSign.length !== 32) {
|
|
603
|
+
throw new ValidationError("pdf token prepare: signingID / hashToSign (32 \u0431\u0430\u0439\u0442) \u0431\u0443\u0440\u0443\u0443");
|
|
604
|
+
}
|
|
605
|
+
return {
|
|
606
|
+
signingId: String(r.signingID),
|
|
607
|
+
docId: String(r.docID ?? ""),
|
|
608
|
+
hashToSign,
|
|
609
|
+
hashAlgorithm: String(r.hashAlgorithm ?? ""),
|
|
610
|
+
signatureAlgorithm: String(r.signatureAlgorithm ?? ""),
|
|
611
|
+
signatureFormat: String(r.signatureFormat ?? ""),
|
|
612
|
+
expiresAt: String(r.expiresAt ?? ""),
|
|
613
|
+
raw
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* POST /pdf/token/{signingID}/finalize `{signature: base64 түүхий r||s}` — `signature` 64 байт (P-256 r||s, DER БИШ).
|
|
618
|
+
* Амжвал READY баримтын блок (`outSha256` — {@link tokenDocument}-оор татсан файлтай тулга). READY-ээс хойш идэмпотент.
|
|
619
|
+
* Алдаа: 400 SIGNATURE_INVALID (3 удаа → FAILED), 409 DOCUMENT_FAILED, 410 DOCUMENT_EXPIRED, 503 DOCUMENT_PENDING /
|
|
620
|
+
* TSA_UNAVAILABLE / LTV_UNAVAILABLE — ижил гарын үсгийг `retryAfterMs`-ийн дараа дахин илгээнэ.
|
|
621
|
+
*/
|
|
622
|
+
async tokenFinalize(signingId, signature) {
|
|
623
|
+
if (signature?.length !== 64) throw new Error("eid: pdf token: signature \u043D\u044C \u0442\u04AF\u04AF\u0445\u0438\u0439 r||s 64 \u0431\u0430\u0439\u0442 \u0431\u0430\u0439\u0445 \u0451\u0441\u0442\u043E\u0439 (P-256, DER \u0431\u0438\u0448)");
|
|
624
|
+
const r = await this.http.post(
|
|
625
|
+
routePath(RP_ROUTES_UNDISCOVERED.pdfTokenFinalize, signingId),
|
|
626
|
+
{ signature: Buffer.from(signature).toString("base64") },
|
|
627
|
+
this.timeout
|
|
628
|
+
);
|
|
629
|
+
return r;
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* GET /pdf/token/{signingID}/document — гарын үсэгтэй PDF (зөвхөн үүсгэсэн RP, expiresAt хүртэл), `pdfMaxBytes`
|
|
633
|
+
* хүртэл. SHA-256-ийг {@link tokenFinalize}-ийн `outSha256`-тай заавал тулга.
|
|
634
|
+
*/
|
|
635
|
+
tokenDocument(signingId) {
|
|
636
|
+
return this.http.getBytes(routePath(RP_ROUTES_UNDISCOVERED.pdfTokenDocument, signingId), this.timeout, this.maxBytes);
|
|
532
637
|
}
|
|
533
638
|
/**
|
|
534
639
|
* {@link document} + тулгалт: татсан байтын SHA-256 нь session poll-ийн `pdf.outSha256`-тай тэнцүү байх ёстой.
|
|
@@ -562,7 +667,7 @@ var OrganizationApi = class {
|
|
|
562
667
|
async getRepresentations(personEtsi) {
|
|
563
668
|
const raw = await this.http.get(routePath(RP_ROUTES.orgRepresentations, personEtsi));
|
|
564
669
|
const list = Array.isArray(raw.representations) ? raw.representations : [];
|
|
565
|
-
return { personEtsi: String(raw.personEtsi ?? personEtsi), representations: list };
|
|
670
|
+
return { personEtsi: String(raw.personEtsi ?? personEtsi), representations: list, raw };
|
|
566
671
|
}
|
|
567
672
|
};
|
|
568
673
|
|
|
@@ -714,6 +819,10 @@ function parseSubject(cert) {
|
|
|
714
819
|
return out;
|
|
715
820
|
}
|
|
716
821
|
function certExtension(der, oid) {
|
|
822
|
+
return certExtensions(der).find((e) => e.oid === oid)?.value;
|
|
823
|
+
}
|
|
824
|
+
function certExtensions(der) {
|
|
825
|
+
const out = [];
|
|
717
826
|
const top = tlv(der, 0, der.length);
|
|
718
827
|
const tbs = tlv(der, top.start, top.end);
|
|
719
828
|
let f = tlv(der, tbs.start, tbs.end);
|
|
@@ -727,16 +836,20 @@ function certExtension(der, oid) {
|
|
|
727
836
|
const ext = tlv(der, ep, seq.end);
|
|
728
837
|
const id = tlv(der, ext.start, ext.end);
|
|
729
838
|
let v = tlv(der, id.end, ext.end);
|
|
730
|
-
|
|
839
|
+
let critical = false;
|
|
840
|
+
if (v.tag === 1) {
|
|
841
|
+
critical = v.end > v.start && der[v.start] !== 0;
|
|
842
|
+
v = tlv(der, v.end, ext.end);
|
|
843
|
+
}
|
|
731
844
|
if (v.tag !== 4) throw new ValidationError("extension: extnValue OCTET STRING \u0431\u0438\u0448");
|
|
732
|
-
|
|
845
|
+
out.push({ oid: oidOf(der, id), critical, value: der.subarray(v.start, v.end) });
|
|
733
846
|
ep = ext.end;
|
|
734
847
|
}
|
|
735
|
-
return
|
|
848
|
+
return out;
|
|
736
849
|
}
|
|
737
850
|
pos = t.end;
|
|
738
851
|
}
|
|
739
|
-
return
|
|
852
|
+
return out;
|
|
740
853
|
}
|
|
741
854
|
|
|
742
855
|
// src/token.ts
|
|
@@ -1086,7 +1199,7 @@ var ResponseValidator = class {
|
|
|
1086
1199
|
);
|
|
1087
1200
|
}
|
|
1088
1201
|
} else {
|
|
1089
|
-
this.verifyChain(leaf);
|
|
1202
|
+
this.verifyChain(leaf, protocol === "ACSP_V2" ? EKU_CLIENT_AUTH : EKU_EMAIL_PROTECTION);
|
|
1090
1203
|
}
|
|
1091
1204
|
this.checkIssuer(leaf);
|
|
1092
1205
|
return leaf;
|
|
@@ -1130,21 +1243,40 @@ var ResponseValidator = class {
|
|
|
1130
1243
|
const need = rank[this.requiredLevel] ?? 2;
|
|
1131
1244
|
if (got < need) throw new ValidationError(`\u0413\u044D\u0440\u0447\u0438\u043B\u0433\u044D\u044D\u043D\u0438\u0439 \u0442\u04AF\u0432\u0448\u0438\u043D \u0445\u04AF\u0440\u044D\u043B\u0446\u044D\u0445\u0433\u04AF\u0439: ${level} < ${this.requiredLevel}`);
|
|
1132
1245
|
}
|
|
1133
|
-
/**
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1246
|
+
/**
|
|
1247
|
+
* RFC 5280 замын шалгалт (Go SDK-ийн `x509.Certificate.Verify`-тэй ижил дүрэм): leaf-ээс trust anchor хүртэлх
|
|
1248
|
+
* замыг intermediates/anchors-оос (backtracking-тай) угсарна. Issuer бүр: subject = child.issuer, AKI/SKI таарах,
|
|
1249
|
+
* гарын үсэг, CA (basicConstraints CA:TRUE), KeyUsage тавьсан бол keyCertSign, **pathLenConstraint** (доорх
|
|
1250
|
+
* завсрын CA-ийн тоо), хүчинтэй хугацаа, EKU тавьсан бол `usage` / anyExtendedKeyUsage агуулах. Leaf болон CA
|
|
1251
|
+
* бүрийн үл таних **critical extension** → татгалзана. **Name constraints**-ийг SDK үнэлдэггүй — гинжинд байвал
|
|
1252
|
+
* fail-closed (CA-ийн бодит гинж 01–04-т алга). Цаг = now, leaf-ийн хүчинтэй хугацаанд хавчсан (`clockSkewMs`-ийн
|
|
1253
|
+
* хүрээнд; leaf-ийн хугацааг checkValidity шалгасан). certificatePolicies шалгахгүй (Go-той ижил).
|
|
1254
|
+
*/
|
|
1255
|
+
verifyChain(leaf, usage) {
|
|
1256
|
+
const now = Math.min(Math.max(Date.now(), Date.parse(leaf.validFrom)), Date.parse(leaf.validTo));
|
|
1257
|
+
const leafReason = criticalReason(leaf) ?? ekuReason(leaf, usage);
|
|
1258
|
+
if (leafReason) throw new ValidationError(`\u0413\u044D\u0440\u0447\u0438\u043B\u0433\u044D\u044D\u043D\u0438\u0439 \u0433\u0438\u043D\u0436 \u0445\u04AF\u0447\u0438\u043D\u0433\u04AF\u0439: ${leafReason}`);
|
|
1259
|
+
let reason;
|
|
1260
|
+
const extend = (cur, cas) => {
|
|
1261
|
+
if (cas.length >= 8) return false;
|
|
1262
|
+
for (const [cand, isAnchor] of [
|
|
1263
|
+
...this.anchors.map((c) => [c, true]),
|
|
1264
|
+
...this.intermediates.map((c) => [c, false])
|
|
1265
|
+
]) {
|
|
1266
|
+
if (cas.includes(cand) || !signedBy(cur, cand)) continue;
|
|
1267
|
+
const bad = caReason(cand, cas.length, now, usage);
|
|
1268
|
+
if (bad) {
|
|
1269
|
+
reason ??= bad;
|
|
1270
|
+
continue;
|
|
1271
|
+
}
|
|
1272
|
+
if (isAnchor || extend(cand, [...cas, cand])) return true;
|
|
1140
1273
|
}
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
throw new ValidationError("\u0413\u044D\u0440\u0447\u0438\u043B\u0433\u044D\u044D\u043D\u0438\u0439 \u0438\u0442\u0433\u044D\u043B\u0446\u043B\u0438\u0439\u043D \u0433\u0438\u043D\u0436 trust anchor (Root CA) \u0445\u04AF\u0440\u0441\u044D\u043D\u0433\u04AF\u0439");
|
|
1274
|
+
return false;
|
|
1275
|
+
};
|
|
1276
|
+
if (extend(leaf, [])) return;
|
|
1277
|
+
throw new ValidationError(
|
|
1278
|
+
reason ? `\u0413\u044D\u0440\u0447\u0438\u043B\u0433\u044D\u044D\u043D\u0438\u0439 \u0433\u0438\u043D\u0436 \u0445\u04AF\u0447\u0438\u043D\u0433\u04AF\u0439: ${reason}` : "\u0413\u044D\u0440\u0447\u0438\u043B\u0433\u044D\u044D\u043D\u0438\u0439 \u0438\u0442\u0433\u044D\u043B\u0446\u043B\u0438\u0439\u043D \u0433\u0438\u043D\u0436 trust anchor (Root CA) \u0445\u04AF\u0440\u0441\u044D\u043D\u0433\u04AF\u0439"
|
|
1279
|
+
);
|
|
1148
1280
|
}
|
|
1149
1281
|
/** leaf-ийн шууд issuer-ийг trust pool-оос буцаана (revocation шалгагчид issuer хэрэгтэй). */
|
|
1150
1282
|
findIssuer(leaf) {
|
|
@@ -1355,6 +1487,79 @@ function authorityKeyId(cert) {
|
|
|
1355
1487
|
function isCa(cert) {
|
|
1356
1488
|
return cert.ca === true;
|
|
1357
1489
|
}
|
|
1490
|
+
var EKU_ANY = "2.5.29.37.0";
|
|
1491
|
+
var EKU_CLIENT_AUTH = "1.3.6.1.5.5.7.3.2";
|
|
1492
|
+
var EKU_EMAIL_PROTECTION = "1.3.6.1.5.5.7.3.4";
|
|
1493
|
+
var OID_NAME_CONSTRAINTS = "2.5.29.30";
|
|
1494
|
+
var HANDLED_CRITICAL = /* @__PURE__ */ new Set([
|
|
1495
|
+
"2.5.29.14",
|
|
1496
|
+
// subjectKeyIdentifier
|
|
1497
|
+
"2.5.29.15",
|
|
1498
|
+
// keyUsage
|
|
1499
|
+
"2.5.29.17",
|
|
1500
|
+
// subjectAltName
|
|
1501
|
+
"2.5.29.19",
|
|
1502
|
+
// basicConstraints
|
|
1503
|
+
"2.5.29.30",
|
|
1504
|
+
// nameConstraints (CA-д — caReason fail-closed)
|
|
1505
|
+
"2.5.29.31",
|
|
1506
|
+
// cRLDistributionPoints
|
|
1507
|
+
"2.5.29.32",
|
|
1508
|
+
// certificatePolicies
|
|
1509
|
+
"2.5.29.35",
|
|
1510
|
+
// authorityKeyIdentifier
|
|
1511
|
+
"2.5.29.37",
|
|
1512
|
+
// extKeyUsage
|
|
1513
|
+
"1.3.6.1.5.5.7.1.1"
|
|
1514
|
+
// authorityInfoAccess
|
|
1515
|
+
]);
|
|
1516
|
+
function signedBy(child, cand) {
|
|
1517
|
+
if (child.issuer !== cand.subject) return false;
|
|
1518
|
+
const aki = authorityKeyId(child);
|
|
1519
|
+
const ski = subjectKeyId(cand);
|
|
1520
|
+
if (aki && ski && aki !== ski) return false;
|
|
1521
|
+
try {
|
|
1522
|
+
return child.verify(cand.publicKey);
|
|
1523
|
+
} catch {
|
|
1524
|
+
return false;
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
function criticalReason(cert) {
|
|
1528
|
+
return certExtensions(cert.raw).some((e) => e.critical && !HANDLED_CRITICAL.has(e.oid)) ? "\u04AF\u043B \u0442\u0430\u043D\u0438\u0445 critical extension" : void 0;
|
|
1529
|
+
}
|
|
1530
|
+
function ekuReason(cert, usage) {
|
|
1531
|
+
const eku = extKeyUsage(cert);
|
|
1532
|
+
return eku.length && !eku.includes(usage) && !eku.includes(EKU_ANY) ? "\u0433\u044D\u0440\u0447\u0438\u043B\u0433\u044D\u044D\u043D\u0438\u0439 ExtKeyUsage \u044D\u043D\u044D \u04AF\u0439\u043B\u0434\u044D\u043B\u0434 \u0442\u043E\u0445\u0438\u0440\u043E\u0445\u0433\u04AF\u0439 (\u0433\u0438\u043D\u0436\u0438\u0439\u043D EKU)" : void 0;
|
|
1533
|
+
}
|
|
1534
|
+
function caReason(ca, below, now, usage) {
|
|
1535
|
+
if (!isCa(ca)) return "\u0437\u0430\u0432\u0441\u0440\u044B\u043D \u0433\u044D\u0440\u0447\u0438\u043B\u0433\u044D\u044D CA \u0431\u0438\u0448 \u044D\u0441\u0432\u044D\u043B keyCertSign \u044D\u0440\u0445\u0433\u04AF\u0439";
|
|
1536
|
+
if (certExtension(ca.raw, "2.5.29.15") && !(keyUsageBits(ca) & 4)) return "CA-\u0438\u0439\u043D KeyUsage-\u0434 keyCertSign \u0430\u043B\u0433\u0430";
|
|
1537
|
+
const from = Date.parse(ca.validFrom);
|
|
1538
|
+
const to = Date.parse(ca.validTo);
|
|
1539
|
+
if (Number.isNaN(from) || Number.isNaN(to) || now < from || now > to) {
|
|
1540
|
+
return "\u0433\u0438\u043D\u0436\u0438\u0439\u043D \u0433\u044D\u0440\u0447\u0438\u043B\u0433\u044D\u044D\u043D\u0438\u0439 \u0445\u0443\u0433\u0430\u0446\u0430\u0430 \u0434\u0443\u0443\u0441\u0441\u0430\u043D \u044D\u0441\u0432\u044D\u043B \u0445\u04AF\u0447\u0438\u043D\u0442\u044D\u0439 \u0431\u043E\u043B\u043E\u043E\u0433\u04AF\u0439";
|
|
1541
|
+
}
|
|
1542
|
+
const pathLen = basicConstraintsPathLen(ca);
|
|
1543
|
+
if (pathLen !== void 0 && below > pathLen) return "pathLenConstraint \u0437\u04E9\u0440\u0447\u0441\u04E9\u043D (\u0437\u0430\u0432\u0441\u0440\u044B\u043D CA \u0445\u044D\u0442 \u043E\u043B\u043E\u043D)";
|
|
1544
|
+
if (certExtension(ca.raw, OID_NAME_CONSTRAINTS)) return "CA-\u0434 name constraints \u0431\u0430\u0439\u043D\u0430 (SDK \u04AF\u043D\u044D\u043B\u0434\u044D\u0433\u0433\u04AF\u0439 \u2014 fail-closed)";
|
|
1545
|
+
return criticalReason(ca) ?? ekuReason(ca, usage);
|
|
1546
|
+
}
|
|
1547
|
+
function basicConstraintsPathLen(cert) {
|
|
1548
|
+
const v = certExtension(cert.raw, "2.5.29.19");
|
|
1549
|
+
if (!v) return void 0;
|
|
1550
|
+
const seq = tlv(v, 0, v.length);
|
|
1551
|
+
for (let p = seq.start; p < seq.end; ) {
|
|
1552
|
+
const t = tlv(v, p, seq.end);
|
|
1553
|
+
if (t.tag === 2) {
|
|
1554
|
+
if (t.end - t.start > 4 || (v[t.start] & 128) !== 0) throw new ValidationError("basicConstraints: pathLen \u0431\u0443\u0440\u0443\u0443");
|
|
1555
|
+
let n = 0;
|
|
1556
|
+
for (let i = t.start; i < t.end; i++) n = n * 256 + v[i];
|
|
1557
|
+
return n;
|
|
1558
|
+
}
|
|
1559
|
+
p = t.end;
|
|
1560
|
+
}
|
|
1561
|
+
return void 0;
|
|
1562
|
+
}
|
|
1358
1563
|
|
|
1359
1564
|
// src/client.ts
|
|
1360
1565
|
var DEFAULT_BASE_URL = "https://rp.eidmongolia.mn";
|
|
@@ -1391,12 +1596,17 @@ var EidClient = class {
|
|
|
1391
1596
|
apiSecret: cfg.credentials.apiSecret,
|
|
1392
1597
|
timeoutMs: cfg.timeoutMs,
|
|
1393
1598
|
dispatcher: cfg.dispatcher,
|
|
1394
|
-
fetchImpl: cfg.fetchImpl
|
|
1599
|
+
fetchImpl: cfg.fetchImpl,
|
|
1600
|
+
language: cfg.language?.trim() || void 0
|
|
1395
1601
|
});
|
|
1396
1602
|
const level = cfg.defaultCertificateLevel ?? "QUALIFIED";
|
|
1397
1603
|
this.auth = new AuthApi(http, cfg.credentials, { certificateLevel: level });
|
|
1398
1604
|
this.sign = new SignApi(http, cfg.credentials, { certificateLevel: level });
|
|
1399
|
-
this.pdf = new PdfApi(http, cfg.credentials, {
|
|
1605
|
+
this.pdf = new PdfApi(http, cfg.credentials, {
|
|
1606
|
+
certificateLevel: level,
|
|
1607
|
+
timeoutMs: cfg.pdfTimeoutMs ?? DEFAULT_PDF_TIMEOUT_MS,
|
|
1608
|
+
maxBytes: cfg.pdfMaxBytes && cfg.pdfMaxBytes > 0 ? cfg.pdfMaxBytes : DEFAULT_PDF_MAX_BYTES
|
|
1609
|
+
});
|
|
1400
1610
|
this.organization = new OrganizationApi(http);
|
|
1401
1611
|
this.person = new PersonApi(http);
|
|
1402
1612
|
this.token = new TokenApi(http, cfg.credentials);
|
|
@@ -1757,6 +1967,7 @@ export {
|
|
|
1757
1967
|
AuthenticationError,
|
|
1758
1968
|
CITIZEN_ISSUING_CA_SKI,
|
|
1759
1969
|
DEFAULT_BASE_URL,
|
|
1970
|
+
DEFAULT_PDF_MAX_BYTES,
|
|
1760
1971
|
DEFAULT_PDF_TIMEOUT_MS,
|
|
1761
1972
|
DeviceLinkError,
|
|
1762
1973
|
EID_ACR_ADVANCED,
|
|
@@ -1774,6 +1985,7 @@ export {
|
|
|
1774
1985
|
PdfApi,
|
|
1775
1986
|
PersonApi,
|
|
1776
1987
|
RETRYABLE_ERROR_CODES,
|
|
1988
|
+
ResponseTooLargeError,
|
|
1777
1989
|
ResponseValidator,
|
|
1778
1990
|
SessionApi,
|
|
1779
1991
|
SessionFailedError,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gerege-systems/eid-mongolia-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "e-ID Mongolia Relying Party SDK — иргэнээр утсаар нь нэвтрэлт ба хууль ёсны цахим гарын үсэг (RP-API v3, Smart-ID нийцтэй).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"scripts": {
|
|
31
31
|
"build": "tsup src/index.ts src/browser.ts --format esm,cjs --dts --clean",
|
|
32
|
-
"test": "npm run build && node --test --experimental-strip-types test/sdk.test.ts test/oidc.test.ts test/portal-gaps.test.ts",
|
|
32
|
+
"test": "npm run build && node --test --experimental-strip-types test/sdk.test.ts test/oidc.test.ts test/portal-gaps.test.ts test/chain.test.ts",
|
|
33
33
|
"test:contract": "npm run build && node --experimental-strip-types test/contract.test.ts",
|
|
34
34
|
"lint": "tsc --noEmit"
|
|
35
35
|
},
|