@gerege-systems/eid-mongolia-sdk 0.6.1 → 0.7.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 +47 -2
- package/dist/{browser-BU9ShPWO.d.cts → browser-Db82DlYN.d.cts} +80 -3
- package/dist/{browser-BU9ShPWO.d.ts → browser-Db82DlYN.d.ts} +80 -3
- package/dist/browser.d.cts +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +1 -1
- package/dist/{chunk-Q5TQMCJC.js → chunk-NXDKQZIW.js} +18 -1
- package/dist/index.cjs +162 -10
- package/dist/index.d.cts +78 -4
- package/dist/index.d.ts +78 -4
- package/dist/index.js +144 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -67,6 +67,51 @@ const sig = eid.validator.validateSign(result, digest); // digest-ийн эср
|
|
|
67
67
|
console.log(sig.signatureValueB64, sig.subject);
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
+
## 3a. Байгууллагын нэрийн өмнөөс гарын үсэг (onBehalfOf)
|
|
71
|
+
|
|
72
|
+
Иргэн **өөрийн PIN2 гэрчилгээгээр** зурна; тухайн мөчид байгууллагыг төлөөлөх эрхтэйг eID **өөрийн бүртгэлээр**
|
|
73
|
+
шалгана (Эстонийн загвар). Энэ нь **хувь хүний квалификацтай гарын үсэг** — байгууллагын гэрчилгээ, тамга (e-Seal) биш.
|
|
74
|
+
e-Seal нь зөвхөн хүнгүй, автомат системийн баримтад. Урьдчилсан нөхцөл: байгууллага eID-д `ACTIVE` (захирал
|
|
75
|
+
аппаараа ХУР-аар холбоно), зурагч нь `ADMIN` эсвэл PIN2-оор баталгаажуулсан `MANAGER`, RP-д `SIGN` эрх.
|
|
76
|
+
Дэлгэрэнгүй: [developer.eidmongolia.mn](https://developer.eidmongolia.mn/).
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { ForbiddenError, ApiError, ON_BEHALF_ERROR_CODES } from "@gerege-systems/eid-mongolia-sdk";
|
|
80
|
+
|
|
81
|
+
// 1. Иргэн сүүлийн 24 цагт танай RP-ээр нэвтэрсэн байх ёстой.
|
|
82
|
+
const { representations } = await eid.organization.getRepresentations("PNOMN-12345678");
|
|
83
|
+
// → [{ orgEtsi: "NTRMN-6235972", orgName: "Гэрэгэ Системс ХХК", role: "ceo", rightType: "ADMIN", … }]
|
|
84
|
+
|
|
85
|
+
// 2. PDF (PAdES, CA угсарна) — санал болгох урсгал.
|
|
86
|
+
try {
|
|
87
|
+
const s = await eid.pdf.prepare({
|
|
88
|
+
pdf: pdfBytes, fileName: "Гэрээ №12.pdf",
|
|
89
|
+
signer: { etsi: "PNOMN-12345678" }, flow: "notification",
|
|
90
|
+
onBehalfOf: "NTRMN-6235972",
|
|
91
|
+
});
|
|
92
|
+
showToUser(s.vc);
|
|
93
|
+
const r = await eid.session.waitForResult(s.sessionId);
|
|
94
|
+
// MUST: endResult OK, pdf.documentStatus READY, pdf.signer.onBehalfOf = хүссэн байгууллага,
|
|
95
|
+
// татсан файлын SHA-256 = pdf.outSha256, validation.indication "valid", ltv true.
|
|
96
|
+
if (r.pdf?.documentStatus !== "READY" || r.pdf.signer?.onBehalfOf !== "NTRMN-6235972") throw new Error("…");
|
|
97
|
+
const signed = await eid.pdf.document(s.sessionId);
|
|
98
|
+
console.log(r.pdf.signer.claimedRole); // "Гүйцэтгэх захирал, Гэрэгэ Системс ХХК (NTRMN-6235972)"
|
|
99
|
+
} catch (e) {
|
|
100
|
+
if ((e instanceof ForbiddenError || e instanceof ApiError) && e.code) {
|
|
101
|
+
// REPRESENTATION_DENIED | REPRESENTATION_PENDING | REPRESENTATION_EXPIRED | ORG_NOT_ACTIVE |
|
|
102
|
+
// SIGNER_UNIDENTIFIED (403) · ORG_NOT_FOUND (404) · REPRESENTATION_REVOKED (403, document татах үед)
|
|
103
|
+
}
|
|
104
|
+
throw e;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Raw digest гарын үсэгт ч мөн: eid.sign.digestByEtsi(id, digest, interactions, { onBehalfOf: "NTRMN-6235972" })
|
|
108
|
+
// — CMS/PDF-ийг та угсардаг тул мэдүүлсэн үүргийг (signer-attributes-v2) өөрөө нэмнэ.
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Олон талт гэрээ: А байгууллагын гаралтыг өөрчлөлтгүй Б-ийн `prepare`-д (`docID`, өөр `onBehalfOf`) илгээнэ.
|
|
112
|
+
Session-ий `onBehalfOf` блок (`role`/`rightType`) нь хариу угсрах үеийн бүртгэл; `pdf.signer.onBehalfOf`/`claimedRole`
|
|
113
|
+
нь баримтад бичигдсэн утга.
|
|
114
|
+
|
|
70
115
|
## 4. QR ба ижил төхөөрөмж — device link v3
|
|
71
116
|
|
|
72
117
|
Иргэн өөр төхөөрөмжийн дэлгэц дээрх **QR**-ийг утсаараа уншина, эсвэл RP-ийн сайт/аппыг eID апптай **ижил
|
|
@@ -172,10 +217,10 @@ OK ирж болзошгүй. Иймд `ResponseValidator`:
|
|
|
172
217
|
| Алдаа | Утга |
|
|
173
218
|
|---|---|
|
|
174
219
|
| `AuthenticationError` | 401 — API secret буруу/байхгүй |
|
|
175
|
-
| `ForbiddenError` | 403 — IP allowlist / mTLS
|
|
220
|
+
| `ForbiddenError` | 403 — IP allowlist / mTLS / RP-ийн эрх; onBehalfOf татгалзвал `.code` (`OnBehalfErrorCode`) |
|
|
176
221
|
| `SessionFailedError` | endResult ≠ OK (TIMEOUT, USER_REFUSED…) — `.endResult`-оор салга |
|
|
177
222
|
| `ValidationError` | cert chain/signature/level шалгалт бүтэлгүйтсэн |
|
|
178
|
-
| `ApiError` | бусад HTTP алдаа (`.status`, `.body`) |
|
|
223
|
+
| `ApiError` | бусад HTTP алдаа (`.status`, `.body`, серверийн `.code` — ж: 404 `ORG_NOT_FOUND`) |
|
|
179
224
|
| `NetworkError` | timeout/сүлжээ |
|
|
180
225
|
| `DeviceLinkError` | device-link холбоос угсрах боломжгүй (`deviceLinkBase` https биш, token/secret/lang хэлбэр, төрөлд хэрэгтэй талбар дутуу) |
|
|
181
226
|
|
|
@@ -130,6 +130,61 @@ interface SessionResult {
|
|
|
130
130
|
* RP энэ талбарыг л итгэж уншина (клиентийн сонголтод биш). docs/ORG_LOGIN.md.
|
|
131
131
|
*/
|
|
132
132
|
onBehalfOf: OrgResult | null;
|
|
133
|
+
/**
|
|
134
|
+
* PAdES (`POST /pdf/sign/prepare`) session-ий `pdf` блок — PDF урсгал биш бол null (талбар алга = хуучин SDK-аар
|
|
135
|
+
* угсарсан объект). {@link PdfSessionBlock}.
|
|
136
|
+
*/
|
|
137
|
+
pdf?: PdfSessionBlock | null;
|
|
138
|
+
}
|
|
139
|
+
/** PDF баримтын төлөв: PENDING → READY (эсвэл FAILED / EXPIRED). */
|
|
140
|
+
type PdfDocumentStatus = "PENDING" | "READY" | "FAILED" | "EXPIRED";
|
|
141
|
+
/** PAdES гаралтын гарын үсэг зурагч. */
|
|
142
|
+
interface PdfSigner {
|
|
143
|
+
etsi: string;
|
|
144
|
+
certSerial: string;
|
|
145
|
+
/** Байгууллагын нэрийн өмнөөс бол байгууллагын ETSI (`NTRMN-…`) — баримтад бичигдсэн утга. */
|
|
146
|
+
onBehalfOf?: string;
|
|
147
|
+
/** CMS signer-attributes-v2-д бичигдсэн мэдүүлсэн үүрэг: «<албан тушаал>, <нэр> (NTRMN-…)». */
|
|
148
|
+
claimedRole?: string;
|
|
149
|
+
}
|
|
150
|
+
/** GET /session/{id}-ийн `pdf` объект (PAdES, CA угсарна). */
|
|
151
|
+
interface PdfSessionBlock {
|
|
152
|
+
docID: string;
|
|
153
|
+
documentStatus: PdfDocumentStatus | string;
|
|
154
|
+
/** FAILED үед — ж: `REPRESENTATION_REVOKED` (prepare-ээс хойш эрх хасагдсан, баримт үүсээгүй). */
|
|
155
|
+
errorCode?: string;
|
|
156
|
+
/** Гарын үсэгтэй PDF-ийн SHA-256 (hex) — татсан файлтай тулгана. */
|
|
157
|
+
outSha256?: string;
|
|
158
|
+
size?: number;
|
|
159
|
+
expiresAt?: string;
|
|
160
|
+
signatureLevel?: string;
|
|
161
|
+
signer?: PdfSigner;
|
|
162
|
+
validation?: {
|
|
163
|
+
indication: string;
|
|
164
|
+
ltv: boolean;
|
|
165
|
+
signatures: number;
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/** Иргэний төлөөлж чадах нэг байгууллага (GET /organization/representations/etsi/{personEtsi}). */
|
|
169
|
+
interface Representation {
|
|
170
|
+
/** `NTRMN-<бүртгэл>` — `onBehalfOf`-д өгөх утга. */
|
|
171
|
+
orgEtsi: string;
|
|
172
|
+
orgRegister: string;
|
|
173
|
+
orgName: string;
|
|
174
|
+
orgNameEn?: string;
|
|
175
|
+
/** Бүртгэлийн албан тушаал (ХУР-аас холбогдсонд `ceo` / `founder`, MANAGER-т ADMIN-ий бичсэн текст). */
|
|
176
|
+
role?: string;
|
|
177
|
+
rightType: "ADMIN" | "MANAGER" | string;
|
|
178
|
+
source: "REGISTRY" | "MANUAL" | string;
|
|
179
|
+
/** ISO 8601. */
|
|
180
|
+
validFrom: string;
|
|
181
|
+
/** ISO 8601; байхгүй = хугацаагүй. */
|
|
182
|
+
validTo?: string;
|
|
183
|
+
}
|
|
184
|
+
/** GET /organization/representations/etsi/{personEtsi} хариу. */
|
|
185
|
+
interface RepresentationsResponse {
|
|
186
|
+
personEtsi: string;
|
|
187
|
+
representations: Representation[];
|
|
133
188
|
}
|
|
134
189
|
/** Session-ий байгууллагын блок — байгууллага + тухайн иргэний эрх (бүртгэлээс real-time). */
|
|
135
190
|
interface OrgResult {
|
|
@@ -206,15 +261,37 @@ declare class EidError extends Error {
|
|
|
206
261
|
/** HTTP 401 — API secret буруу/байхгүй. Тохиргооны (RP secret) алдаа. */
|
|
207
262
|
declare class AuthenticationError extends EidError {
|
|
208
263
|
}
|
|
209
|
-
/**
|
|
264
|
+
/**
|
|
265
|
+
* HTTP 403 — IP allowlist/mTLS зөвшөөрөөгүй, RP-д эрх алга, эсвэл onBehalfOf-ийн төлөөлөл татгалзсан.
|
|
266
|
+
* Сервер `{"error","code"}` буцаасан бол `code` (ж: `REPRESENTATION_DENIED`) — салааллыг үүгээр хийнэ.
|
|
267
|
+
*/
|
|
210
268
|
declare class ForbiddenError extends EidError {
|
|
269
|
+
/** Серверийн тогтвортой алдааны код (`{"code"}`), байхгүй бол undefined. */
|
|
270
|
+
readonly code?: string | undefined;
|
|
271
|
+
constructor(message: string,
|
|
272
|
+
/** Серверийн тогтвортой алдааны код (`{"code"}`), байхгүй бол undefined. */
|
|
273
|
+
code?: string | undefined);
|
|
211
274
|
}
|
|
212
275
|
/** RP-API-аас ирсэн бусад HTTP алдаа (4xx/5xx). status ба хариуны биеийг агуулна. */
|
|
213
276
|
declare class ApiError extends EidError {
|
|
214
277
|
readonly status: number;
|
|
215
278
|
readonly body: string;
|
|
216
|
-
|
|
279
|
+
/** Серверийн тогтвортой алдааны код (`{"error","code"}`-ийн `code`), байхгүй бол undefined. */
|
|
280
|
+
readonly code?: string | undefined;
|
|
281
|
+
constructor(status: number, body: string,
|
|
282
|
+
/** Серверийн тогтвортой алдааны код (`{"error","code"}`-ийн `code`), байхгүй бол undefined. */
|
|
283
|
+
code?: string | undefined);
|
|
217
284
|
}
|
|
285
|
+
/**
|
|
286
|
+
* Байгууллагын нэрийн өмнөөс (`onBehalfOf`) урсгалын татгалзлын кодууд — `ForbiddenError.code` /
|
|
287
|
+
* `ApiError.code`-д ирнэ. 403: REPRESENTATION_DENIED (идэвхтэй төлөөлөгч биш), REPRESENTATION_PENDING (PIN2-оор
|
|
288
|
+
* баталгаажуулаагүй), REPRESENTATION_EXPIRED (хугацааны гадна), ORG_NOT_ACTIVE, SIGNER_UNIDENTIFIED (anonymous
|
|
289
|
+
* session); 404: ORG_NOT_FOUND; PDF баримт татахад 403 REPRESENTATION_REVOKED (prepare-ээс хойш эрх хасагдсан —
|
|
290
|
+
* баримт үүсээгүй).
|
|
291
|
+
*/
|
|
292
|
+
type OnBehalfErrorCode = "REPRESENTATION_DENIED" | "REPRESENTATION_PENDING" | "REPRESENTATION_EXPIRED" | "ORG_NOT_ACTIVE" | "SIGNER_UNIDENTIFIED" | "ORG_NOT_FOUND" | "REPRESENTATION_REVOKED";
|
|
293
|
+
/** {@link OnBehalfErrorCode}-ийн бүх утга (runtime шалгалтад). */
|
|
294
|
+
declare const ON_BEHALF_ERROR_CODES: readonly OnBehalfErrorCode[];
|
|
218
295
|
/** Сүлжээ/timeout — upstream хариу өгсөнгүй. */
|
|
219
296
|
declare class NetworkError extends EidError {
|
|
220
297
|
}
|
|
@@ -240,4 +317,4 @@ declare class ValidationError extends EidError {
|
|
|
240
317
|
declare class DeviceLinkError extends EidError {
|
|
241
318
|
}
|
|
242
319
|
|
|
243
|
-
export { type AcspContext as A, type CertificateLevel as C, type DeviceLinkSession as D, EidError as E, type FlowType as F, type HashAlgorithm as H, type Interaction as I, type NotificationSession as N, type
|
|
320
|
+
export { type AcspContext as A, type CertificateLevel as C, type DeviceLinkSession as D, EidError as E, type FlowType as F, type HashAlgorithm as H, type Interaction as I, type NotificationSession as N, ON_BEHALF_ERROR_CODES as O, type PdfDocumentStatus as P, type RpCredentials as R, type SignatureAlgorithm as S, ValidationError as V, type SessionResult as a, type RepresentationsResponse as b, ApiError as c, AuthenticationError as d, DeviceLinkError as e, type DeviceLinkInput as f, type EndResult as g, ForbiddenError as h, type NavigatorLike as i, NetworkError as j, type OnBehalfErrorCode as k, type OpenOrShowQROptions as l, type OrgResult as m, type PdfSessionBlock as n, type PdfSigner as o, type Representation as p, SessionFailedError as q, type SessionState as r, type SignatureAlgorithmParameters as s, type SignatureProtocol as t, deviceLink as u, isMobileUserAgent as v, openOrShowQR as w };
|
|
@@ -130,6 +130,61 @@ interface SessionResult {
|
|
|
130
130
|
* RP энэ талбарыг л итгэж уншина (клиентийн сонголтод биш). docs/ORG_LOGIN.md.
|
|
131
131
|
*/
|
|
132
132
|
onBehalfOf: OrgResult | null;
|
|
133
|
+
/**
|
|
134
|
+
* PAdES (`POST /pdf/sign/prepare`) session-ий `pdf` блок — PDF урсгал биш бол null (талбар алга = хуучин SDK-аар
|
|
135
|
+
* угсарсан объект). {@link PdfSessionBlock}.
|
|
136
|
+
*/
|
|
137
|
+
pdf?: PdfSessionBlock | null;
|
|
138
|
+
}
|
|
139
|
+
/** PDF баримтын төлөв: PENDING → READY (эсвэл FAILED / EXPIRED). */
|
|
140
|
+
type PdfDocumentStatus = "PENDING" | "READY" | "FAILED" | "EXPIRED";
|
|
141
|
+
/** PAdES гаралтын гарын үсэг зурагч. */
|
|
142
|
+
interface PdfSigner {
|
|
143
|
+
etsi: string;
|
|
144
|
+
certSerial: string;
|
|
145
|
+
/** Байгууллагын нэрийн өмнөөс бол байгууллагын ETSI (`NTRMN-…`) — баримтад бичигдсэн утга. */
|
|
146
|
+
onBehalfOf?: string;
|
|
147
|
+
/** CMS signer-attributes-v2-д бичигдсэн мэдүүлсэн үүрэг: «<албан тушаал>, <нэр> (NTRMN-…)». */
|
|
148
|
+
claimedRole?: string;
|
|
149
|
+
}
|
|
150
|
+
/** GET /session/{id}-ийн `pdf` объект (PAdES, CA угсарна). */
|
|
151
|
+
interface PdfSessionBlock {
|
|
152
|
+
docID: string;
|
|
153
|
+
documentStatus: PdfDocumentStatus | string;
|
|
154
|
+
/** FAILED үед — ж: `REPRESENTATION_REVOKED` (prepare-ээс хойш эрх хасагдсан, баримт үүсээгүй). */
|
|
155
|
+
errorCode?: string;
|
|
156
|
+
/** Гарын үсэгтэй PDF-ийн SHA-256 (hex) — татсан файлтай тулгана. */
|
|
157
|
+
outSha256?: string;
|
|
158
|
+
size?: number;
|
|
159
|
+
expiresAt?: string;
|
|
160
|
+
signatureLevel?: string;
|
|
161
|
+
signer?: PdfSigner;
|
|
162
|
+
validation?: {
|
|
163
|
+
indication: string;
|
|
164
|
+
ltv: boolean;
|
|
165
|
+
signatures: number;
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/** Иргэний төлөөлж чадах нэг байгууллага (GET /organization/representations/etsi/{personEtsi}). */
|
|
169
|
+
interface Representation {
|
|
170
|
+
/** `NTRMN-<бүртгэл>` — `onBehalfOf`-д өгөх утга. */
|
|
171
|
+
orgEtsi: string;
|
|
172
|
+
orgRegister: string;
|
|
173
|
+
orgName: string;
|
|
174
|
+
orgNameEn?: string;
|
|
175
|
+
/** Бүртгэлийн албан тушаал (ХУР-аас холбогдсонд `ceo` / `founder`, MANAGER-т ADMIN-ий бичсэн текст). */
|
|
176
|
+
role?: string;
|
|
177
|
+
rightType: "ADMIN" | "MANAGER" | string;
|
|
178
|
+
source: "REGISTRY" | "MANUAL" | string;
|
|
179
|
+
/** ISO 8601. */
|
|
180
|
+
validFrom: string;
|
|
181
|
+
/** ISO 8601; байхгүй = хугацаагүй. */
|
|
182
|
+
validTo?: string;
|
|
183
|
+
}
|
|
184
|
+
/** GET /organization/representations/etsi/{personEtsi} хариу. */
|
|
185
|
+
interface RepresentationsResponse {
|
|
186
|
+
personEtsi: string;
|
|
187
|
+
representations: Representation[];
|
|
133
188
|
}
|
|
134
189
|
/** Session-ий байгууллагын блок — байгууллага + тухайн иргэний эрх (бүртгэлээс real-time). */
|
|
135
190
|
interface OrgResult {
|
|
@@ -206,15 +261,37 @@ declare class EidError extends Error {
|
|
|
206
261
|
/** HTTP 401 — API secret буруу/байхгүй. Тохиргооны (RP secret) алдаа. */
|
|
207
262
|
declare class AuthenticationError extends EidError {
|
|
208
263
|
}
|
|
209
|
-
/**
|
|
264
|
+
/**
|
|
265
|
+
* HTTP 403 — IP allowlist/mTLS зөвшөөрөөгүй, RP-д эрх алга, эсвэл onBehalfOf-ийн төлөөлөл татгалзсан.
|
|
266
|
+
* Сервер `{"error","code"}` буцаасан бол `code` (ж: `REPRESENTATION_DENIED`) — салааллыг үүгээр хийнэ.
|
|
267
|
+
*/
|
|
210
268
|
declare class ForbiddenError extends EidError {
|
|
269
|
+
/** Серверийн тогтвортой алдааны код (`{"code"}`), байхгүй бол undefined. */
|
|
270
|
+
readonly code?: string | undefined;
|
|
271
|
+
constructor(message: string,
|
|
272
|
+
/** Серверийн тогтвортой алдааны код (`{"code"}`), байхгүй бол undefined. */
|
|
273
|
+
code?: string | undefined);
|
|
211
274
|
}
|
|
212
275
|
/** RP-API-аас ирсэн бусад HTTP алдаа (4xx/5xx). status ба хариуны биеийг агуулна. */
|
|
213
276
|
declare class ApiError extends EidError {
|
|
214
277
|
readonly status: number;
|
|
215
278
|
readonly body: string;
|
|
216
|
-
|
|
279
|
+
/** Серверийн тогтвортой алдааны код (`{"error","code"}`-ийн `code`), байхгүй бол undefined. */
|
|
280
|
+
readonly code?: string | undefined;
|
|
281
|
+
constructor(status: number, body: string,
|
|
282
|
+
/** Серверийн тогтвортой алдааны код (`{"error","code"}`-ийн `code`), байхгүй бол undefined. */
|
|
283
|
+
code?: string | undefined);
|
|
217
284
|
}
|
|
285
|
+
/**
|
|
286
|
+
* Байгууллагын нэрийн өмнөөс (`onBehalfOf`) урсгалын татгалзлын кодууд — `ForbiddenError.code` /
|
|
287
|
+
* `ApiError.code`-д ирнэ. 403: REPRESENTATION_DENIED (идэвхтэй төлөөлөгч биш), REPRESENTATION_PENDING (PIN2-оор
|
|
288
|
+
* баталгаажуулаагүй), REPRESENTATION_EXPIRED (хугацааны гадна), ORG_NOT_ACTIVE, SIGNER_UNIDENTIFIED (anonymous
|
|
289
|
+
* session); 404: ORG_NOT_FOUND; PDF баримт татахад 403 REPRESENTATION_REVOKED (prepare-ээс хойш эрх хасагдсан —
|
|
290
|
+
* баримт үүсээгүй).
|
|
291
|
+
*/
|
|
292
|
+
type OnBehalfErrorCode = "REPRESENTATION_DENIED" | "REPRESENTATION_PENDING" | "REPRESENTATION_EXPIRED" | "ORG_NOT_ACTIVE" | "SIGNER_UNIDENTIFIED" | "ORG_NOT_FOUND" | "REPRESENTATION_REVOKED";
|
|
293
|
+
/** {@link OnBehalfErrorCode}-ийн бүх утга (runtime шалгалтад). */
|
|
294
|
+
declare const ON_BEHALF_ERROR_CODES: readonly OnBehalfErrorCode[];
|
|
218
295
|
/** Сүлжээ/timeout — upstream хариу өгсөнгүй. */
|
|
219
296
|
declare class NetworkError extends EidError {
|
|
220
297
|
}
|
|
@@ -240,4 +317,4 @@ declare class ValidationError extends EidError {
|
|
|
240
317
|
declare class DeviceLinkError extends EidError {
|
|
241
318
|
}
|
|
242
319
|
|
|
243
|
-
export { type AcspContext as A, type CertificateLevel as C, type DeviceLinkSession as D, EidError as E, type FlowType as F, type HashAlgorithm as H, type Interaction as I, type NotificationSession as N, type
|
|
320
|
+
export { type AcspContext as A, type CertificateLevel as C, type DeviceLinkSession as D, EidError as E, type FlowType as F, type HashAlgorithm as H, type Interaction as I, type NotificationSession as N, ON_BEHALF_ERROR_CODES as O, type PdfDocumentStatus as P, type RpCredentials as R, type SignatureAlgorithm as S, ValidationError as V, type SessionResult as a, type RepresentationsResponse as b, ApiError as c, AuthenticationError as d, DeviceLinkError as e, type DeviceLinkInput as f, type EndResult as g, ForbiddenError as h, type NavigatorLike as i, NetworkError as j, type OnBehalfErrorCode as k, type OpenOrShowQROptions as l, type OrgResult as m, type PdfSessionBlock as n, type PdfSigner as o, type Representation as p, SessionFailedError as q, type SessionState as r, type SignatureAlgorithmParameters as s, type SignatureProtocol as t, deviceLink as u, isMobileUserAgent as v, openOrShowQR as w };
|
package/dist/browser.d.cts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { e as DeviceLinkError, f as DeviceLinkInput, D as DeviceLinkSession, E as EidError, i as NavigatorLike, l as OpenOrShowQROptions, u as deviceLink, v as isMobileUserAgent, w as openOrShowQR } from './browser-Db82DlYN.cjs';
|
package/dist/browser.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { e as DeviceLinkError, f as DeviceLinkInput, D as DeviceLinkSession, E as EidError, i as NavigatorLike, l as OpenOrShowQROptions, u as deviceLink, v as isMobileUserAgent, w as openOrShowQR } from './browser-Db82DlYN.js';
|
package/dist/browser.js
CHANGED
|
@@ -8,16 +8,32 @@ var EidError = class extends Error {
|
|
|
8
8
|
var AuthenticationError = class extends EidError {
|
|
9
9
|
};
|
|
10
10
|
var ForbiddenError = class extends EidError {
|
|
11
|
+
constructor(message, code) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.code = code;
|
|
14
|
+
}
|
|
15
|
+
code;
|
|
11
16
|
};
|
|
12
17
|
var ApiError = class extends EidError {
|
|
13
|
-
constructor(status, body) {
|
|
18
|
+
constructor(status, body, code) {
|
|
14
19
|
super(`RP-API ${status}: ${body}`);
|
|
15
20
|
this.status = status;
|
|
16
21
|
this.body = body;
|
|
22
|
+
this.code = code;
|
|
17
23
|
}
|
|
18
24
|
status;
|
|
19
25
|
body;
|
|
26
|
+
code;
|
|
20
27
|
};
|
|
28
|
+
var ON_BEHALF_ERROR_CODES = [
|
|
29
|
+
"REPRESENTATION_DENIED",
|
|
30
|
+
"REPRESENTATION_PENDING",
|
|
31
|
+
"REPRESENTATION_EXPIRED",
|
|
32
|
+
"ORG_NOT_ACTIVE",
|
|
33
|
+
"SIGNER_UNIDENTIFIED",
|
|
34
|
+
"ORG_NOT_FOUND",
|
|
35
|
+
"REPRESENTATION_REVOKED"
|
|
36
|
+
];
|
|
21
37
|
var NetworkError = class extends EidError {
|
|
22
38
|
};
|
|
23
39
|
var SessionFailedError = class extends EidError {
|
|
@@ -79,6 +95,7 @@ export {
|
|
|
79
95
|
AuthenticationError,
|
|
80
96
|
ForbiddenError,
|
|
81
97
|
ApiError,
|
|
98
|
+
ON_BEHALF_ERROR_CODES,
|
|
82
99
|
NetworkError,
|
|
83
100
|
SessionFailedError,
|
|
84
101
|
ValidationError,
|
package/dist/index.cjs
CHANGED
|
@@ -30,6 +30,9 @@ __export(index_exports, {
|
|
|
30
30
|
ForbiddenError: () => ForbiddenError,
|
|
31
31
|
Http: () => Http,
|
|
32
32
|
NetworkError: () => NetworkError,
|
|
33
|
+
ON_BEHALF_ERROR_CODES: () => ON_BEHALF_ERROR_CODES,
|
|
34
|
+
OrganizationApi: () => OrganizationApi,
|
|
35
|
+
PdfApi: () => PdfApi,
|
|
33
36
|
ResponseValidator: () => ResponseValidator,
|
|
34
37
|
SessionApi: () => SessionApi,
|
|
35
38
|
SessionFailedError: () => SessionFailedError,
|
|
@@ -63,16 +66,32 @@ var EidError = class extends Error {
|
|
|
63
66
|
var AuthenticationError = class extends EidError {
|
|
64
67
|
};
|
|
65
68
|
var ForbiddenError = class extends EidError {
|
|
69
|
+
constructor(message, code) {
|
|
70
|
+
super(message);
|
|
71
|
+
this.code = code;
|
|
72
|
+
}
|
|
73
|
+
code;
|
|
66
74
|
};
|
|
67
75
|
var ApiError = class extends EidError {
|
|
68
|
-
constructor(status, body) {
|
|
76
|
+
constructor(status, body, code) {
|
|
69
77
|
super(`RP-API ${status}: ${body}`);
|
|
70
78
|
this.status = status;
|
|
71
79
|
this.body = body;
|
|
80
|
+
this.code = code;
|
|
72
81
|
}
|
|
73
82
|
status;
|
|
74
83
|
body;
|
|
84
|
+
code;
|
|
75
85
|
};
|
|
86
|
+
var ON_BEHALF_ERROR_CODES = [
|
|
87
|
+
"REPRESENTATION_DENIED",
|
|
88
|
+
"REPRESENTATION_PENDING",
|
|
89
|
+
"REPRESENTATION_EXPIRED",
|
|
90
|
+
"ORG_NOT_ACTIVE",
|
|
91
|
+
"SIGNER_UNIDENTIFIED",
|
|
92
|
+
"ORG_NOT_FOUND",
|
|
93
|
+
"REPRESENTATION_REVOKED"
|
|
94
|
+
];
|
|
76
95
|
var NetworkError = class extends EidError {
|
|
77
96
|
};
|
|
78
97
|
var SessionFailedError = class extends EidError {
|
|
@@ -95,21 +114,35 @@ var Http = class {
|
|
|
95
114
|
}
|
|
96
115
|
cfg;
|
|
97
116
|
post(path, body, timeoutMs) {
|
|
98
|
-
return this.
|
|
117
|
+
return this.json("POST", path, JSON.stringify(body), "application/json", timeoutMs);
|
|
99
118
|
}
|
|
100
119
|
get(path, timeoutMs) {
|
|
101
|
-
return this.
|
|
120
|
+
return this.json("GET", path, void 0, void 0, timeoutMs);
|
|
121
|
+
}
|
|
122
|
+
/** multipart/form-data POST (Content-Type-ийг boundary-тай нь fetch тавина). JSON хариу. */
|
|
123
|
+
postMultipart(path, form, timeoutMs) {
|
|
124
|
+
return this.json("POST", path, form, void 0, timeoutMs);
|
|
125
|
+
}
|
|
126
|
+
/** GET — хариуг байтаар (ж: гарын үсэгтэй PDF). */
|
|
127
|
+
async getBytes(path, timeoutMs) {
|
|
128
|
+
const res = await this.send("GET", path, void 0, void 0, timeoutMs);
|
|
129
|
+
return new Uint8Array(await res.arrayBuffer());
|
|
130
|
+
}
|
|
131
|
+
async json(method, path, body, contentType, timeoutMs) {
|
|
132
|
+
const res = await this.send(method, path, body, contentType, timeoutMs);
|
|
133
|
+
const text = await res.text();
|
|
134
|
+
return text ? JSON.parse(text) : {};
|
|
102
135
|
}
|
|
103
|
-
async
|
|
136
|
+
async send(method, path, body, contentType, timeoutMs) {
|
|
104
137
|
const f = this.cfg.fetchImpl ?? fetch;
|
|
105
138
|
const url = this.cfg.baseUrl + path;
|
|
106
139
|
const init = {
|
|
107
140
|
method,
|
|
108
141
|
headers: {
|
|
109
142
|
Authorization: `Bearer ${this.cfg.apiSecret}`,
|
|
110
|
-
...
|
|
143
|
+
...contentType ? { "Content-Type": contentType } : {}
|
|
111
144
|
},
|
|
112
|
-
body
|
|
145
|
+
body,
|
|
113
146
|
signal: AbortSignal.timeout(timeoutMs ?? this.cfg.timeoutMs ?? DEFAULT_TIMEOUT_MS)
|
|
114
147
|
};
|
|
115
148
|
if (this.cfg.dispatcher) init.dispatcher = this.cfg.dispatcher;
|
|
@@ -123,13 +156,32 @@ var Http = class {
|
|
|
123
156
|
}
|
|
124
157
|
throw new NetworkError(`\u0421\u04AF\u043B\u0436\u044D\u044D\u043D\u0438\u0439 \u0430\u043B\u0434\u0430\u0430 (${method} ${path}): ${err.message}`);
|
|
125
158
|
}
|
|
159
|
+
if (res.status < 300) return res;
|
|
126
160
|
const text = await res.text();
|
|
161
|
+
const { error, code } = errorBody(text);
|
|
127
162
|
if (res.status === 401) throw new AuthenticationError("API secret \u0431\u0443\u0440\u0443\u0443 \u044D\u0441\u0432\u044D\u043B \u0431\u0430\u0439\u0445\u0433\u04AF\u0439 (401)");
|
|
128
|
-
if (res.status === 403)
|
|
129
|
-
|
|
130
|
-
|
|
163
|
+
if (res.status === 403) {
|
|
164
|
+
throw new ForbiddenError(
|
|
165
|
+
error ? `RP-API 403${code ? ` ${code}` : ""}: ${error}` : "IP allowlist \u044D\u0441\u0432\u044D\u043B mTLS \u0437\u04E9\u0432\u0448\u04E9\u04E9\u0440\u04E9\u04E9\u0433\u04AF\u0439 (403)",
|
|
166
|
+
code
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
throw new ApiError(res.status, text, code);
|
|
131
170
|
}
|
|
132
171
|
};
|
|
172
|
+
function errorBody(text) {
|
|
173
|
+
try {
|
|
174
|
+
const v = JSON.parse(text);
|
|
175
|
+
if (!v || typeof v !== "object") return {};
|
|
176
|
+
const o = v;
|
|
177
|
+
return {
|
|
178
|
+
error: typeof o.error === "string" && o.error ? o.error : void 0,
|
|
179
|
+
code: typeof o.code === "string" && o.code ? o.code : void 0
|
|
180
|
+
};
|
|
181
|
+
} catch {
|
|
182
|
+
return {};
|
|
183
|
+
}
|
|
184
|
+
}
|
|
133
185
|
|
|
134
186
|
// src/crypto.ts
|
|
135
187
|
var import_node_crypto = require("crypto");
|
|
@@ -341,9 +393,32 @@ function parseSessionResult(raw) {
|
|
|
341
393
|
initialCallbackUrl: typeof sig.initialCallbackUrl === "string" ? sig.initialCallbackUrl : null,
|
|
342
394
|
signatureAlgorithmParameters: parseSigParams(sig.signatureAlgorithmParameters),
|
|
343
395
|
interactionTypeUsed: str(r.interactionTypeUsed),
|
|
344
|
-
onBehalfOf: parseOrg(r.onBehalfOf)
|
|
396
|
+
onBehalfOf: parseOrg(r.onBehalfOf),
|
|
397
|
+
pdf: parsePdf(r.pdf)
|
|
345
398
|
};
|
|
346
399
|
}
|
|
400
|
+
function parsePdf(raw) {
|
|
401
|
+
const p = asRecord(raw);
|
|
402
|
+
const docID = str(p.docID);
|
|
403
|
+
if (!docID) return null;
|
|
404
|
+
const out = { docID, documentStatus: String(p.documentStatus ?? "") };
|
|
405
|
+
if (p.errorCode != null) out.errorCode = String(p.errorCode);
|
|
406
|
+
if (p.outSha256 != null) out.outSha256 = String(p.outSha256);
|
|
407
|
+
if (p.size != null) out.size = Number(p.size);
|
|
408
|
+
if (p.expiresAt != null) out.expiresAt = String(p.expiresAt);
|
|
409
|
+
if (p.signatureLevel != null) out.signatureLevel = String(p.signatureLevel);
|
|
410
|
+
const sg = asRecord(p.signer);
|
|
411
|
+
if (sg.etsi != null) {
|
|
412
|
+
out.signer = { etsi: String(sg.etsi), certSerial: String(sg.certSerial ?? "") };
|
|
413
|
+
if (sg.onBehalfOf) out.signer.onBehalfOf = String(sg.onBehalfOf);
|
|
414
|
+
if (sg.claimedRole) out.signer.claimedRole = String(sg.claimedRole);
|
|
415
|
+
}
|
|
416
|
+
const v = asRecord(p.validation);
|
|
417
|
+
if (v.indication != null) {
|
|
418
|
+
out.validation = { indication: String(v.indication), ltv: v.ltv === true, signatures: Number(v.signatures ?? 0) };
|
|
419
|
+
}
|
|
420
|
+
return out;
|
|
421
|
+
}
|
|
347
422
|
function parseSigParams(raw) {
|
|
348
423
|
const p = asRecord(raw);
|
|
349
424
|
const hash = str(p.hashAlgorithm);
|
|
@@ -398,6 +473,76 @@ var SessionApi = class {
|
|
|
398
473
|
}
|
|
399
474
|
};
|
|
400
475
|
|
|
476
|
+
// src/pdf.ts
|
|
477
|
+
function rec3(v) {
|
|
478
|
+
return v && typeof v === "object" ? v : {};
|
|
479
|
+
}
|
|
480
|
+
var PdfApi = class {
|
|
481
|
+
constructor(http, creds, defaults) {
|
|
482
|
+
this.http = http;
|
|
483
|
+
this.creds = creds;
|
|
484
|
+
this.defaults = defaults;
|
|
485
|
+
}
|
|
486
|
+
http;
|
|
487
|
+
creds;
|
|
488
|
+
defaults;
|
|
489
|
+
/** POST /pdf/sign/prepare — multipart (`request` JSON + `pdf`). SIGN эрх шаардана. */
|
|
490
|
+
async prepare(input) {
|
|
491
|
+
const request = {
|
|
492
|
+
relyingPartyUUID: this.creds.rpUUID,
|
|
493
|
+
relyingPartyName: this.creds.rpName,
|
|
494
|
+
certificateLevel: input.certificateLevel ?? this.defaults.certificateLevel,
|
|
495
|
+
signer: input.signer,
|
|
496
|
+
flow: input.flow ?? "notification",
|
|
497
|
+
fileName: input.fileName
|
|
498
|
+
};
|
|
499
|
+
if (input.initialCallbackUrl?.trim()) request.initialCallbackUrl = input.initialCallbackUrl.trim();
|
|
500
|
+
if (input.docID?.trim()) request.docID = input.docID.trim();
|
|
501
|
+
if (input.onBehalfOf?.trim()) request.onBehalfOf = input.onBehalfOf.trim();
|
|
502
|
+
const form = new FormData();
|
|
503
|
+
form.append("request", new Blob([JSON.stringify(request)], { type: "application/json" }));
|
|
504
|
+
form.append("pdf", new Blob([input.pdf], { type: "application/pdf" }), input.fileName);
|
|
505
|
+
const r = rec3(await this.http.postMultipart("/pdf/sign/prepare", form, 6e4));
|
|
506
|
+
const receivedAt = Date.now();
|
|
507
|
+
const vc = rec3(r.vc).value;
|
|
508
|
+
const dl = rec3(r.deviceLink);
|
|
509
|
+
return {
|
|
510
|
+
sessionId: String(r.sessionID),
|
|
511
|
+
docId: String(r.docID),
|
|
512
|
+
vc: vc != null ? String(vc) : null,
|
|
513
|
+
deviceLink: dl.sessionToken ? {
|
|
514
|
+
sessionToken: String(dl.sessionToken),
|
|
515
|
+
sessionSecret: String(dl.sessionSecret),
|
|
516
|
+
deviceLinkBase: String(dl.deviceLinkBase),
|
|
517
|
+
digest: String(dl.digest),
|
|
518
|
+
interactions: String(dl.interactions)
|
|
519
|
+
} : null,
|
|
520
|
+
receivedAt
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* GET /pdf/sign/{sessionID}/document — гарын үсэгтэй PDF (READY-ээс хойш 30 мин). Татсан байтын SHA-256-ийг
|
|
525
|
+
* session-ий `pdf.outSha256`-тай тулга. Эрх хасагдсан бол `ForbiddenError` `.code = "REPRESENTATION_REVOKED"`.
|
|
526
|
+
*/
|
|
527
|
+
document(sessionId) {
|
|
528
|
+
return this.http.getBytes(`/pdf/sign/${encodeURIComponent(sessionId)}/document`, 6e4);
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
// src/organization.ts
|
|
533
|
+
var OrganizationApi = class {
|
|
534
|
+
constructor(http) {
|
|
535
|
+
this.http = http;
|
|
536
|
+
}
|
|
537
|
+
http;
|
|
538
|
+
/** GET /organization/representations/etsi/{personEtsi}. Сонголт нь итгэх эх биш — сервер дахин шалгана. */
|
|
539
|
+
async getRepresentations(personEtsi) {
|
|
540
|
+
const raw = await this.http.get(`/organization/representations/etsi/${encodeURIComponent(personEtsi)}`);
|
|
541
|
+
const list = Array.isArray(raw.representations) ? raw.representations : [];
|
|
542
|
+
return { personEtsi: String(raw.personEtsi ?? personEtsi), representations: list };
|
|
543
|
+
}
|
|
544
|
+
};
|
|
545
|
+
|
|
401
546
|
// src/validator.ts
|
|
402
547
|
var import_node_crypto2 = require("crypto");
|
|
403
548
|
var ResponseValidator = class {
|
|
@@ -752,6 +897,8 @@ function resolveBaseUrl(baseUrl) {
|
|
|
752
897
|
var EidClient = class {
|
|
753
898
|
auth;
|
|
754
899
|
sign;
|
|
900
|
+
pdf;
|
|
901
|
+
organization;
|
|
755
902
|
session;
|
|
756
903
|
validator;
|
|
757
904
|
constructor(cfg) {
|
|
@@ -767,6 +914,8 @@ var EidClient = class {
|
|
|
767
914
|
const level = cfg.defaultCertificateLevel ?? "QUALIFIED";
|
|
768
915
|
this.auth = new AuthApi(http, cfg.credentials, { certificateLevel: level });
|
|
769
916
|
this.sign = new SignApi(http, cfg.credentials, { certificateLevel: level });
|
|
917
|
+
this.pdf = new PdfApi(http, cfg.credentials, { certificateLevel: level });
|
|
918
|
+
this.organization = new OrganizationApi(http);
|
|
770
919
|
this.session = new SessionApi(http);
|
|
771
920
|
this.validator = new ResponseValidator(cfg.trust ?? {});
|
|
772
921
|
}
|
|
@@ -895,6 +1044,9 @@ function qrDeviceLinkTicker(input, onLink, opts) {
|
|
|
895
1044
|
ForbiddenError,
|
|
896
1045
|
Http,
|
|
897
1046
|
NetworkError,
|
|
1047
|
+
ON_BEHALF_ERROR_CODES,
|
|
1048
|
+
OrganizationApi,
|
|
1049
|
+
PdfApi,
|
|
898
1050
|
ResponseValidator,
|
|
899
1051
|
SessionApi,
|
|
900
1052
|
SessionFailedError,
|
package/dist/index.d.cts
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, A as AcspContext, F as FlowType } from './browser-
|
|
2
|
-
export {
|
|
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, b as RepresentationsResponse, A as AcspContext, F as FlowType } from './browser-Db82DlYN.cjs';
|
|
2
|
+
export { c as ApiError, d as AuthenticationError, e as DeviceLinkError, f as DeviceLinkInput, E as EidError, g as EndResult, h as ForbiddenError, i as NavigatorLike, j as NetworkError, O as ON_BEHALF_ERROR_CODES, k as OnBehalfErrorCode, l as OpenOrShowQROptions, m as OrgResult, P as PdfDocumentStatus, n as PdfSessionBlock, o as PdfSigner, p as Representation, q as SessionFailedError, r as SessionState, s as SignatureAlgorithmParameters, t as SignatureProtocol, V as ValidationError, u as deviceLink, v as isMobileUserAgent, w as openOrShowQR } from './browser-Db82DlYN.cjs';
|
|
3
3
|
import { X509Certificate, KeyObject } from 'node:crypto';
|
|
4
4
|
|
|
5
5
|
interface HttpConfig {
|
|
@@ -23,7 +23,12 @@ declare class Http {
|
|
|
23
23
|
constructor(cfg: HttpConfig);
|
|
24
24
|
post(path: string, body: unknown, timeoutMs?: number): Promise<unknown>;
|
|
25
25
|
get(path: string, timeoutMs?: number): Promise<unknown>;
|
|
26
|
-
|
|
26
|
+
/** multipart/form-data POST (Content-Type-ийг boundary-тай нь fetch тавина). JSON хариу. */
|
|
27
|
+
postMultipart(path: string, form: FormData, timeoutMs?: number): Promise<unknown>;
|
|
28
|
+
/** GET — хариуг байтаар (ж: гарын үсэгтэй PDF). */
|
|
29
|
+
getBytes(path: string, timeoutMs?: number): Promise<Uint8Array>;
|
|
30
|
+
private json;
|
|
31
|
+
private send;
|
|
27
32
|
}
|
|
28
33
|
|
|
29
34
|
interface AuthDefaults {
|
|
@@ -131,6 +136,73 @@ declare class SessionApi {
|
|
|
131
136
|
}): Promise<SessionResult>;
|
|
132
137
|
}
|
|
133
138
|
|
|
139
|
+
interface PdfDefaults {
|
|
140
|
+
certificateLevel: CertificateLevel;
|
|
141
|
+
}
|
|
142
|
+
/** Гарын үсэг зурагч — яг нэг нь. */
|
|
143
|
+
type PdfSignerRef = {
|
|
144
|
+
etsi: string;
|
|
145
|
+
} | {
|
|
146
|
+
documentNumber: string;
|
|
147
|
+
} | {
|
|
148
|
+
certificateChoiceSessionId: string;
|
|
149
|
+
};
|
|
150
|
+
interface PdfPrepareInput {
|
|
151
|
+
/** Эх PDF (≤ 10 223 616 байт — `/.well-known/eid` `pdfSigning.maxInputBytes`). */
|
|
152
|
+
pdf: Uint8Array;
|
|
153
|
+
/** Баримтын нэр (≤ 120 тэмдэгт) — /verify хуудас, иргэний түүхэнд харагдана. */
|
|
154
|
+
fileName: string;
|
|
155
|
+
signer: PdfSignerRef;
|
|
156
|
+
/** `notification` (push) эсвэл `device-link` (QR/Web2App/App2App). Анхдагч notification. */
|
|
157
|
+
flow?: "notification" | "device-link";
|
|
158
|
+
certificateLevel?: CertificateLevel;
|
|
159
|
+
/** device-link Web2App/App2App буцах URL. */
|
|
160
|
+
initialCallbackUrl?: string;
|
|
161
|
+
/** Олон гарын үсэгтэй баримтад хүлээж буй docID (заавал биш — CA өөрөө олно). */
|
|
162
|
+
docID?: string;
|
|
163
|
+
/**
|
|
164
|
+
* Байгууллагын нэрийн өмнөөс: байгууллагын ETSI (`NTRMN-<бүртгэл>`). Сервер төлөөллийг prepare-д ба баримт
|
|
165
|
+
* угсрахын өмнө дахин шалгана; татгалзвал `ForbiddenError`/`ApiError` `.code` ({@link OnBehalfErrorCode}).
|
|
166
|
+
*/
|
|
167
|
+
onBehalfOf?: string;
|
|
168
|
+
}
|
|
169
|
+
/** prepare-ийн хариу. device-link-д `deviceLink` (digest/interactions-ийг authCode-д ЯГ ХЭВЭЭР). */
|
|
170
|
+
interface PdfPrepareSession {
|
|
171
|
+
sessionId: string;
|
|
172
|
+
docId: string;
|
|
173
|
+
/** Иргэнд ХАРУУЛАХ баталгаажуулах код (ПИН биш). */
|
|
174
|
+
vc: string | null;
|
|
175
|
+
deviceLink: {
|
|
176
|
+
sessionToken: string;
|
|
177
|
+
sessionSecret: string;
|
|
178
|
+
deviceLinkBase: string;
|
|
179
|
+
digest: string;
|
|
180
|
+
interactions: string;
|
|
181
|
+
} | null;
|
|
182
|
+
/** SDK хариу хүлээн авсан мөч (ms epoch) — QR-ийн `receivedAt` ({@link buildDeviceLink}). */
|
|
183
|
+
receivedAt: number;
|
|
184
|
+
}
|
|
185
|
+
declare class PdfApi {
|
|
186
|
+
private readonly http;
|
|
187
|
+
private readonly creds;
|
|
188
|
+
private readonly defaults;
|
|
189
|
+
constructor(http: Http, creds: RpCredentials, defaults: PdfDefaults);
|
|
190
|
+
/** POST /pdf/sign/prepare — multipart (`request` JSON + `pdf`). SIGN эрх шаардана. */
|
|
191
|
+
prepare(input: PdfPrepareInput): Promise<PdfPrepareSession>;
|
|
192
|
+
/**
|
|
193
|
+
* GET /pdf/sign/{sessionID}/document — гарын үсэгтэй PDF (READY-ээс хойш 30 мин). Татсан байтын SHA-256-ийг
|
|
194
|
+
* session-ий `pdf.outSha256`-тай тулга. Эрх хасагдсан бол `ForbiddenError` `.code = "REPRESENTATION_REVOKED"`.
|
|
195
|
+
*/
|
|
196
|
+
document(sessionId: string): Promise<Uint8Array>;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
declare class OrganizationApi {
|
|
200
|
+
private readonly http;
|
|
201
|
+
constructor(http: Http);
|
|
202
|
+
/** GET /organization/representations/etsi/{personEtsi}. Сонголт нь итгэх эх биш — сервер дахин шалгана. */
|
|
203
|
+
getRepresentations(personEtsi: string): Promise<RepresentationsResponse>;
|
|
204
|
+
}
|
|
205
|
+
|
|
134
206
|
/**
|
|
135
207
|
* validateAuth-ийн нэмэлт шалгалт — RP ЯМАР урсгал эхлүүлснээ мэддэг тул түүнийг тулгана
|
|
136
208
|
* (device-link relay хаалт).
|
|
@@ -283,6 +355,8 @@ declare function resolveBaseUrl(baseUrl: string | undefined): string;
|
|
|
283
355
|
declare class EidClient {
|
|
284
356
|
readonly auth: AuthApi;
|
|
285
357
|
readonly sign: SignApi;
|
|
358
|
+
readonly pdf: PdfApi;
|
|
359
|
+
readonly organization: OrganizationApi;
|
|
286
360
|
readonly session: SessionApi;
|
|
287
361
|
readonly validator: ResponseValidator;
|
|
288
362
|
constructor(cfg: ClientConfig);
|
|
@@ -383,4 +457,4 @@ interface QrDeviceLinkTickerOptions {
|
|
|
383
457
|
*/
|
|
384
458
|
declare function qrDeviceLinkTicker(input: Omit<BuildDeviceLinkInput, "deviceLinkType" | "now">, onLink: (link: string) => void, opts?: QrDeviceLinkTickerOptions): () => void;
|
|
385
459
|
|
|
386
|
-
export { AcspContext, type AcspV2Params, AuthApi, type AuthDefaults, type AuthOptions, type BuildDeviceLinkInput, CertificateLevel, type ClientConfig, DEFAULT_BASE_URL, DeviceLinkSession, type DeviceLinkSessionType, type DeviceLinkType, EidClient, FlowType, HashAlgorithm, Http, type HttpConfig, Interaction, NotificationSession, type QrDeviceLinkTickerOptions, ResponseValidator, type RevocationChecker, type RevocationStatus, RpCredentials, SessionApi, SessionResult, SignApi, type SignDefaults, type SignOptions, SignatureAlgorithm, type TrustConfig, type ValidateAuthOptions, type VerifiedIdentity, type VerifiedSignature, acspV2Digest, buildAcspV2Payload, buildDeviceLink, interactionsToBase64, parseSessionResult, qrDeviceLinkTicker, randomChallenge, resolveBaseUrl, sha256Base64, userChallengeOf, verifyPayloadSignature, verifyPrehashedSignature };
|
|
460
|
+
export { AcspContext, type AcspV2Params, AuthApi, type AuthDefaults, type AuthOptions, type BuildDeviceLinkInput, CertificateLevel, type ClientConfig, DEFAULT_BASE_URL, DeviceLinkSession, type DeviceLinkSessionType, type DeviceLinkType, EidClient, FlowType, HashAlgorithm, Http, type HttpConfig, Interaction, NotificationSession, OrganizationApi, PdfApi, type PdfDefaults, type PdfPrepareInput, type PdfPrepareSession, type PdfSignerRef, type QrDeviceLinkTickerOptions, RepresentationsResponse, ResponseValidator, type RevocationChecker, type RevocationStatus, RpCredentials, SessionApi, SessionResult, SignApi, type SignDefaults, type SignOptions, SignatureAlgorithm, type TrustConfig, type ValidateAuthOptions, type VerifiedIdentity, type VerifiedSignature, acspV2Digest, buildAcspV2Payload, buildDeviceLink, interactionsToBase64, parseSessionResult, qrDeviceLinkTicker, randomChallenge, resolveBaseUrl, sha256Base64, userChallengeOf, verifyPayloadSignature, verifyPrehashedSignature };
|
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, A as AcspContext, F as FlowType } from './browser-
|
|
2
|
-
export {
|
|
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, b as RepresentationsResponse, A as AcspContext, F as FlowType } from './browser-Db82DlYN.js';
|
|
2
|
+
export { c as ApiError, d as AuthenticationError, e as DeviceLinkError, f as DeviceLinkInput, E as EidError, g as EndResult, h as ForbiddenError, i as NavigatorLike, j as NetworkError, O as ON_BEHALF_ERROR_CODES, k as OnBehalfErrorCode, l as OpenOrShowQROptions, m as OrgResult, P as PdfDocumentStatus, n as PdfSessionBlock, o as PdfSigner, p as Representation, q as SessionFailedError, r as SessionState, s as SignatureAlgorithmParameters, t as SignatureProtocol, V as ValidationError, u as deviceLink, v as isMobileUserAgent, w as openOrShowQR } from './browser-Db82DlYN.js';
|
|
3
3
|
import { X509Certificate, KeyObject } from 'node:crypto';
|
|
4
4
|
|
|
5
5
|
interface HttpConfig {
|
|
@@ -23,7 +23,12 @@ declare class Http {
|
|
|
23
23
|
constructor(cfg: HttpConfig);
|
|
24
24
|
post(path: string, body: unknown, timeoutMs?: number): Promise<unknown>;
|
|
25
25
|
get(path: string, timeoutMs?: number): Promise<unknown>;
|
|
26
|
-
|
|
26
|
+
/** multipart/form-data POST (Content-Type-ийг boundary-тай нь fetch тавина). JSON хариу. */
|
|
27
|
+
postMultipart(path: string, form: FormData, timeoutMs?: number): Promise<unknown>;
|
|
28
|
+
/** GET — хариуг байтаар (ж: гарын үсэгтэй PDF). */
|
|
29
|
+
getBytes(path: string, timeoutMs?: number): Promise<Uint8Array>;
|
|
30
|
+
private json;
|
|
31
|
+
private send;
|
|
27
32
|
}
|
|
28
33
|
|
|
29
34
|
interface AuthDefaults {
|
|
@@ -131,6 +136,73 @@ declare class SessionApi {
|
|
|
131
136
|
}): Promise<SessionResult>;
|
|
132
137
|
}
|
|
133
138
|
|
|
139
|
+
interface PdfDefaults {
|
|
140
|
+
certificateLevel: CertificateLevel;
|
|
141
|
+
}
|
|
142
|
+
/** Гарын үсэг зурагч — яг нэг нь. */
|
|
143
|
+
type PdfSignerRef = {
|
|
144
|
+
etsi: string;
|
|
145
|
+
} | {
|
|
146
|
+
documentNumber: string;
|
|
147
|
+
} | {
|
|
148
|
+
certificateChoiceSessionId: string;
|
|
149
|
+
};
|
|
150
|
+
interface PdfPrepareInput {
|
|
151
|
+
/** Эх PDF (≤ 10 223 616 байт — `/.well-known/eid` `pdfSigning.maxInputBytes`). */
|
|
152
|
+
pdf: Uint8Array;
|
|
153
|
+
/** Баримтын нэр (≤ 120 тэмдэгт) — /verify хуудас, иргэний түүхэнд харагдана. */
|
|
154
|
+
fileName: string;
|
|
155
|
+
signer: PdfSignerRef;
|
|
156
|
+
/** `notification` (push) эсвэл `device-link` (QR/Web2App/App2App). Анхдагч notification. */
|
|
157
|
+
flow?: "notification" | "device-link";
|
|
158
|
+
certificateLevel?: CertificateLevel;
|
|
159
|
+
/** device-link Web2App/App2App буцах URL. */
|
|
160
|
+
initialCallbackUrl?: string;
|
|
161
|
+
/** Олон гарын үсэгтэй баримтад хүлээж буй docID (заавал биш — CA өөрөө олно). */
|
|
162
|
+
docID?: string;
|
|
163
|
+
/**
|
|
164
|
+
* Байгууллагын нэрийн өмнөөс: байгууллагын ETSI (`NTRMN-<бүртгэл>`). Сервер төлөөллийг prepare-д ба баримт
|
|
165
|
+
* угсрахын өмнө дахин шалгана; татгалзвал `ForbiddenError`/`ApiError` `.code` ({@link OnBehalfErrorCode}).
|
|
166
|
+
*/
|
|
167
|
+
onBehalfOf?: string;
|
|
168
|
+
}
|
|
169
|
+
/** prepare-ийн хариу. device-link-д `deviceLink` (digest/interactions-ийг authCode-д ЯГ ХЭВЭЭР). */
|
|
170
|
+
interface PdfPrepareSession {
|
|
171
|
+
sessionId: string;
|
|
172
|
+
docId: string;
|
|
173
|
+
/** Иргэнд ХАРУУЛАХ баталгаажуулах код (ПИН биш). */
|
|
174
|
+
vc: string | null;
|
|
175
|
+
deviceLink: {
|
|
176
|
+
sessionToken: string;
|
|
177
|
+
sessionSecret: string;
|
|
178
|
+
deviceLinkBase: string;
|
|
179
|
+
digest: string;
|
|
180
|
+
interactions: string;
|
|
181
|
+
} | null;
|
|
182
|
+
/** SDK хариу хүлээн авсан мөч (ms epoch) — QR-ийн `receivedAt` ({@link buildDeviceLink}). */
|
|
183
|
+
receivedAt: number;
|
|
184
|
+
}
|
|
185
|
+
declare class PdfApi {
|
|
186
|
+
private readonly http;
|
|
187
|
+
private readonly creds;
|
|
188
|
+
private readonly defaults;
|
|
189
|
+
constructor(http: Http, creds: RpCredentials, defaults: PdfDefaults);
|
|
190
|
+
/** POST /pdf/sign/prepare — multipart (`request` JSON + `pdf`). SIGN эрх шаардана. */
|
|
191
|
+
prepare(input: PdfPrepareInput): Promise<PdfPrepareSession>;
|
|
192
|
+
/**
|
|
193
|
+
* GET /pdf/sign/{sessionID}/document — гарын үсэгтэй PDF (READY-ээс хойш 30 мин). Татсан байтын SHA-256-ийг
|
|
194
|
+
* session-ий `pdf.outSha256`-тай тулга. Эрх хасагдсан бол `ForbiddenError` `.code = "REPRESENTATION_REVOKED"`.
|
|
195
|
+
*/
|
|
196
|
+
document(sessionId: string): Promise<Uint8Array>;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
declare class OrganizationApi {
|
|
200
|
+
private readonly http;
|
|
201
|
+
constructor(http: Http);
|
|
202
|
+
/** GET /organization/representations/etsi/{personEtsi}. Сонголт нь итгэх эх биш — сервер дахин шалгана. */
|
|
203
|
+
getRepresentations(personEtsi: string): Promise<RepresentationsResponse>;
|
|
204
|
+
}
|
|
205
|
+
|
|
134
206
|
/**
|
|
135
207
|
* validateAuth-ийн нэмэлт шалгалт — RP ЯМАР урсгал эхлүүлснээ мэддэг тул түүнийг тулгана
|
|
136
208
|
* (device-link relay хаалт).
|
|
@@ -283,6 +355,8 @@ declare function resolveBaseUrl(baseUrl: string | undefined): string;
|
|
|
283
355
|
declare class EidClient {
|
|
284
356
|
readonly auth: AuthApi;
|
|
285
357
|
readonly sign: SignApi;
|
|
358
|
+
readonly pdf: PdfApi;
|
|
359
|
+
readonly organization: OrganizationApi;
|
|
286
360
|
readonly session: SessionApi;
|
|
287
361
|
readonly validator: ResponseValidator;
|
|
288
362
|
constructor(cfg: ClientConfig);
|
|
@@ -383,4 +457,4 @@ interface QrDeviceLinkTickerOptions {
|
|
|
383
457
|
*/
|
|
384
458
|
declare function qrDeviceLinkTicker(input: Omit<BuildDeviceLinkInput, "deviceLinkType" | "now">, onLink: (link: string) => void, opts?: QrDeviceLinkTickerOptions): () => void;
|
|
385
459
|
|
|
386
|
-
export { AcspContext, type AcspV2Params, AuthApi, type AuthDefaults, type AuthOptions, type BuildDeviceLinkInput, CertificateLevel, type ClientConfig, DEFAULT_BASE_URL, DeviceLinkSession, type DeviceLinkSessionType, type DeviceLinkType, EidClient, FlowType, HashAlgorithm, Http, type HttpConfig, Interaction, NotificationSession, type QrDeviceLinkTickerOptions, ResponseValidator, type RevocationChecker, type RevocationStatus, RpCredentials, SessionApi, SessionResult, SignApi, type SignDefaults, type SignOptions, SignatureAlgorithm, type TrustConfig, type ValidateAuthOptions, type VerifiedIdentity, type VerifiedSignature, acspV2Digest, buildAcspV2Payload, buildDeviceLink, interactionsToBase64, parseSessionResult, qrDeviceLinkTicker, randomChallenge, resolveBaseUrl, sha256Base64, userChallengeOf, verifyPayloadSignature, verifyPrehashedSignature };
|
|
460
|
+
export { AcspContext, type AcspV2Params, AuthApi, type AuthDefaults, type AuthOptions, type BuildDeviceLinkInput, CertificateLevel, type ClientConfig, DEFAULT_BASE_URL, DeviceLinkSession, type DeviceLinkSessionType, type DeviceLinkType, EidClient, FlowType, HashAlgorithm, Http, type HttpConfig, Interaction, NotificationSession, OrganizationApi, PdfApi, type PdfDefaults, type PdfPrepareInput, type PdfPrepareSession, type PdfSignerRef, type QrDeviceLinkTickerOptions, RepresentationsResponse, ResponseValidator, type RevocationChecker, type RevocationStatus, RpCredentials, SessionApi, SessionResult, SignApi, type SignDefaults, type SignOptions, SignatureAlgorithm, type TrustConfig, type ValidateAuthOptions, type VerifiedIdentity, type VerifiedSignature, acspV2Digest, buildAcspV2Payload, buildDeviceLink, interactionsToBase64, parseSessionResult, qrDeviceLinkTicker, randomChallenge, resolveBaseUrl, sha256Base64, userChallengeOf, verifyPayloadSignature, verifyPrehashedSignature };
|
package/dist/index.js
CHANGED
|
@@ -5,12 +5,13 @@ import {
|
|
|
5
5
|
EidError,
|
|
6
6
|
ForbiddenError,
|
|
7
7
|
NetworkError,
|
|
8
|
+
ON_BEHALF_ERROR_CODES,
|
|
8
9
|
SessionFailedError,
|
|
9
10
|
ValidationError,
|
|
10
11
|
deviceLink,
|
|
11
12
|
isMobileUserAgent,
|
|
12
13
|
openOrShowQR
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-NXDKQZIW.js";
|
|
14
15
|
|
|
15
16
|
// src/http.ts
|
|
16
17
|
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
@@ -20,21 +21,35 @@ var Http = class {
|
|
|
20
21
|
}
|
|
21
22
|
cfg;
|
|
22
23
|
post(path, body, timeoutMs) {
|
|
23
|
-
return this.
|
|
24
|
+
return this.json("POST", path, JSON.stringify(body), "application/json", timeoutMs);
|
|
24
25
|
}
|
|
25
26
|
get(path, timeoutMs) {
|
|
26
|
-
return this.
|
|
27
|
+
return this.json("GET", path, void 0, void 0, timeoutMs);
|
|
27
28
|
}
|
|
28
|
-
|
|
29
|
+
/** multipart/form-data POST (Content-Type-ийг boundary-тай нь fetch тавина). JSON хариу. */
|
|
30
|
+
postMultipart(path, form, timeoutMs) {
|
|
31
|
+
return this.json("POST", path, form, void 0, timeoutMs);
|
|
32
|
+
}
|
|
33
|
+
/** GET — хариуг байтаар (ж: гарын үсэгтэй PDF). */
|
|
34
|
+
async getBytes(path, timeoutMs) {
|
|
35
|
+
const res = await this.send("GET", path, void 0, void 0, timeoutMs);
|
|
36
|
+
return new Uint8Array(await res.arrayBuffer());
|
|
37
|
+
}
|
|
38
|
+
async json(method, path, body, contentType, timeoutMs) {
|
|
39
|
+
const res = await this.send(method, path, body, contentType, timeoutMs);
|
|
40
|
+
const text = await res.text();
|
|
41
|
+
return text ? JSON.parse(text) : {};
|
|
42
|
+
}
|
|
43
|
+
async send(method, path, body, contentType, timeoutMs) {
|
|
29
44
|
const f = this.cfg.fetchImpl ?? fetch;
|
|
30
45
|
const url = this.cfg.baseUrl + path;
|
|
31
46
|
const init = {
|
|
32
47
|
method,
|
|
33
48
|
headers: {
|
|
34
49
|
Authorization: `Bearer ${this.cfg.apiSecret}`,
|
|
35
|
-
...
|
|
50
|
+
...contentType ? { "Content-Type": contentType } : {}
|
|
36
51
|
},
|
|
37
|
-
body
|
|
52
|
+
body,
|
|
38
53
|
signal: AbortSignal.timeout(timeoutMs ?? this.cfg.timeoutMs ?? DEFAULT_TIMEOUT_MS)
|
|
39
54
|
};
|
|
40
55
|
if (this.cfg.dispatcher) init.dispatcher = this.cfg.dispatcher;
|
|
@@ -48,13 +63,32 @@ var Http = class {
|
|
|
48
63
|
}
|
|
49
64
|
throw new NetworkError(`\u0421\u04AF\u043B\u0436\u044D\u044D\u043D\u0438\u0439 \u0430\u043B\u0434\u0430\u0430 (${method} ${path}): ${err.message}`);
|
|
50
65
|
}
|
|
66
|
+
if (res.status < 300) return res;
|
|
51
67
|
const text = await res.text();
|
|
68
|
+
const { error, code } = errorBody(text);
|
|
52
69
|
if (res.status === 401) throw new AuthenticationError("API secret \u0431\u0443\u0440\u0443\u0443 \u044D\u0441\u0432\u044D\u043B \u0431\u0430\u0439\u0445\u0433\u04AF\u0439 (401)");
|
|
53
|
-
if (res.status === 403)
|
|
54
|
-
|
|
55
|
-
|
|
70
|
+
if (res.status === 403) {
|
|
71
|
+
throw new ForbiddenError(
|
|
72
|
+
error ? `RP-API 403${code ? ` ${code}` : ""}: ${error}` : "IP allowlist \u044D\u0441\u0432\u044D\u043B mTLS \u0437\u04E9\u0432\u0448\u04E9\u04E9\u0440\u04E9\u04E9\u0433\u04AF\u0439 (403)",
|
|
73
|
+
code
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
throw new ApiError(res.status, text, code);
|
|
56
77
|
}
|
|
57
78
|
};
|
|
79
|
+
function errorBody(text) {
|
|
80
|
+
try {
|
|
81
|
+
const v = JSON.parse(text);
|
|
82
|
+
if (!v || typeof v !== "object") return {};
|
|
83
|
+
const o = v;
|
|
84
|
+
return {
|
|
85
|
+
error: typeof o.error === "string" && o.error ? o.error : void 0,
|
|
86
|
+
code: typeof o.code === "string" && o.code ? o.code : void 0
|
|
87
|
+
};
|
|
88
|
+
} catch {
|
|
89
|
+
return {};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
58
92
|
|
|
59
93
|
// src/crypto.ts
|
|
60
94
|
import { createHash, randomBytes } from "crypto";
|
|
@@ -266,9 +300,32 @@ function parseSessionResult(raw) {
|
|
|
266
300
|
initialCallbackUrl: typeof sig.initialCallbackUrl === "string" ? sig.initialCallbackUrl : null,
|
|
267
301
|
signatureAlgorithmParameters: parseSigParams(sig.signatureAlgorithmParameters),
|
|
268
302
|
interactionTypeUsed: str(r.interactionTypeUsed),
|
|
269
|
-
onBehalfOf: parseOrg(r.onBehalfOf)
|
|
303
|
+
onBehalfOf: parseOrg(r.onBehalfOf),
|
|
304
|
+
pdf: parsePdf(r.pdf)
|
|
270
305
|
};
|
|
271
306
|
}
|
|
307
|
+
function parsePdf(raw) {
|
|
308
|
+
const p = asRecord(raw);
|
|
309
|
+
const docID = str(p.docID);
|
|
310
|
+
if (!docID) return null;
|
|
311
|
+
const out = { docID, documentStatus: String(p.documentStatus ?? "") };
|
|
312
|
+
if (p.errorCode != null) out.errorCode = String(p.errorCode);
|
|
313
|
+
if (p.outSha256 != null) out.outSha256 = String(p.outSha256);
|
|
314
|
+
if (p.size != null) out.size = Number(p.size);
|
|
315
|
+
if (p.expiresAt != null) out.expiresAt = String(p.expiresAt);
|
|
316
|
+
if (p.signatureLevel != null) out.signatureLevel = String(p.signatureLevel);
|
|
317
|
+
const sg = asRecord(p.signer);
|
|
318
|
+
if (sg.etsi != null) {
|
|
319
|
+
out.signer = { etsi: String(sg.etsi), certSerial: String(sg.certSerial ?? "") };
|
|
320
|
+
if (sg.onBehalfOf) out.signer.onBehalfOf = String(sg.onBehalfOf);
|
|
321
|
+
if (sg.claimedRole) out.signer.claimedRole = String(sg.claimedRole);
|
|
322
|
+
}
|
|
323
|
+
const v = asRecord(p.validation);
|
|
324
|
+
if (v.indication != null) {
|
|
325
|
+
out.validation = { indication: String(v.indication), ltv: v.ltv === true, signatures: Number(v.signatures ?? 0) };
|
|
326
|
+
}
|
|
327
|
+
return out;
|
|
328
|
+
}
|
|
272
329
|
function parseSigParams(raw) {
|
|
273
330
|
const p = asRecord(raw);
|
|
274
331
|
const hash = str(p.hashAlgorithm);
|
|
@@ -323,6 +380,76 @@ var SessionApi = class {
|
|
|
323
380
|
}
|
|
324
381
|
};
|
|
325
382
|
|
|
383
|
+
// src/pdf.ts
|
|
384
|
+
function rec3(v) {
|
|
385
|
+
return v && typeof v === "object" ? v : {};
|
|
386
|
+
}
|
|
387
|
+
var PdfApi = class {
|
|
388
|
+
constructor(http, creds, defaults) {
|
|
389
|
+
this.http = http;
|
|
390
|
+
this.creds = creds;
|
|
391
|
+
this.defaults = defaults;
|
|
392
|
+
}
|
|
393
|
+
http;
|
|
394
|
+
creds;
|
|
395
|
+
defaults;
|
|
396
|
+
/** POST /pdf/sign/prepare — multipart (`request` JSON + `pdf`). SIGN эрх шаардана. */
|
|
397
|
+
async prepare(input) {
|
|
398
|
+
const request = {
|
|
399
|
+
relyingPartyUUID: this.creds.rpUUID,
|
|
400
|
+
relyingPartyName: this.creds.rpName,
|
|
401
|
+
certificateLevel: input.certificateLevel ?? this.defaults.certificateLevel,
|
|
402
|
+
signer: input.signer,
|
|
403
|
+
flow: input.flow ?? "notification",
|
|
404
|
+
fileName: input.fileName
|
|
405
|
+
};
|
|
406
|
+
if (input.initialCallbackUrl?.trim()) request.initialCallbackUrl = input.initialCallbackUrl.trim();
|
|
407
|
+
if (input.docID?.trim()) request.docID = input.docID.trim();
|
|
408
|
+
if (input.onBehalfOf?.trim()) request.onBehalfOf = input.onBehalfOf.trim();
|
|
409
|
+
const form = new FormData();
|
|
410
|
+
form.append("request", new Blob([JSON.stringify(request)], { type: "application/json" }));
|
|
411
|
+
form.append("pdf", new Blob([input.pdf], { type: "application/pdf" }), input.fileName);
|
|
412
|
+
const r = rec3(await this.http.postMultipart("/pdf/sign/prepare", form, 6e4));
|
|
413
|
+
const receivedAt = Date.now();
|
|
414
|
+
const vc = rec3(r.vc).value;
|
|
415
|
+
const dl = rec3(r.deviceLink);
|
|
416
|
+
return {
|
|
417
|
+
sessionId: String(r.sessionID),
|
|
418
|
+
docId: String(r.docID),
|
|
419
|
+
vc: vc != null ? String(vc) : null,
|
|
420
|
+
deviceLink: dl.sessionToken ? {
|
|
421
|
+
sessionToken: String(dl.sessionToken),
|
|
422
|
+
sessionSecret: String(dl.sessionSecret),
|
|
423
|
+
deviceLinkBase: String(dl.deviceLinkBase),
|
|
424
|
+
digest: String(dl.digest),
|
|
425
|
+
interactions: String(dl.interactions)
|
|
426
|
+
} : null,
|
|
427
|
+
receivedAt
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* GET /pdf/sign/{sessionID}/document — гарын үсэгтэй PDF (READY-ээс хойш 30 мин). Татсан байтын SHA-256-ийг
|
|
432
|
+
* session-ий `pdf.outSha256`-тай тулга. Эрх хасагдсан бол `ForbiddenError` `.code = "REPRESENTATION_REVOKED"`.
|
|
433
|
+
*/
|
|
434
|
+
document(sessionId) {
|
|
435
|
+
return this.http.getBytes(`/pdf/sign/${encodeURIComponent(sessionId)}/document`, 6e4);
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
// src/organization.ts
|
|
440
|
+
var OrganizationApi = class {
|
|
441
|
+
constructor(http) {
|
|
442
|
+
this.http = http;
|
|
443
|
+
}
|
|
444
|
+
http;
|
|
445
|
+
/** GET /organization/representations/etsi/{personEtsi}. Сонголт нь итгэх эх биш — сервер дахин шалгана. */
|
|
446
|
+
async getRepresentations(personEtsi) {
|
|
447
|
+
const raw = await this.http.get(`/organization/representations/etsi/${encodeURIComponent(personEtsi)}`);
|
|
448
|
+
const list = Array.isArray(raw.representations) ? raw.representations : [];
|
|
449
|
+
return { personEtsi: String(raw.personEtsi ?? personEtsi), representations: list };
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
|
|
326
453
|
// src/validator.ts
|
|
327
454
|
import { X509Certificate, constants, createHash as createHash2, publicDecrypt, verify } from "crypto";
|
|
328
455
|
var ResponseValidator = class {
|
|
@@ -677,6 +804,8 @@ function resolveBaseUrl(baseUrl) {
|
|
|
677
804
|
var EidClient = class {
|
|
678
805
|
auth;
|
|
679
806
|
sign;
|
|
807
|
+
pdf;
|
|
808
|
+
organization;
|
|
680
809
|
session;
|
|
681
810
|
validator;
|
|
682
811
|
constructor(cfg) {
|
|
@@ -692,6 +821,8 @@ var EidClient = class {
|
|
|
692
821
|
const level = cfg.defaultCertificateLevel ?? "QUALIFIED";
|
|
693
822
|
this.auth = new AuthApi(http, cfg.credentials, { certificateLevel: level });
|
|
694
823
|
this.sign = new SignApi(http, cfg.credentials, { certificateLevel: level });
|
|
824
|
+
this.pdf = new PdfApi(http, cfg.credentials, { certificateLevel: level });
|
|
825
|
+
this.organization = new OrganizationApi(http);
|
|
695
826
|
this.session = new SessionApi(http);
|
|
696
827
|
this.validator = new ResponseValidator(cfg.trust ?? {});
|
|
697
828
|
}
|
|
@@ -777,6 +908,9 @@ export {
|
|
|
777
908
|
ForbiddenError,
|
|
778
909
|
Http,
|
|
779
910
|
NetworkError,
|
|
911
|
+
ON_BEHALF_ERROR_CODES,
|
|
912
|
+
OrganizationApi,
|
|
913
|
+
PdfApi,
|
|
780
914
|
ResponseValidator,
|
|
781
915
|
SessionApi,
|
|
782
916
|
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.7.0",
|
|
4
4
|
"description": "e-ID Mongolia Relying Party SDK — иргэнээр утсаар нь нэвтрэлт ба хууль ёсны цахим гарын үсэг (RP-API v3, Smart-ID нийцтэй).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|