eimzo-ts 0.1.1 → 0.1.3

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.ru.md ADDED
@@ -0,0 +1,233 @@
1
+ # eimzo-ts
2
+
3
+ [![npm](https://img.shields.io/npm/v/eimzo-ts)](https://www.npmjs.com/package/eimzo-ts)
4
+ [![CI](https://github.com/abduazimkhuja/eimzo-ts/actions/workflows/ci.yml/badge.svg)](https://github.com/abduazimkhuja/eimzo-ts/actions/workflows/ci.yml)
5
+ [![license](https://img.shields.io/npm/l/eimzo-ts)](LICENSE)
6
+
7
+ [English](README.md) · **Русский**
8
+
9
+ TypeScript-клиент для [E-IMZO](https://e-imzo.uz): список ключей ЭЦП, подпись PKCS#7, вход по ЭЦП.
10
+ Без зависимостей и без привязки к фреймворку: Angular, React, Vue, Svelte или обычная страница.
11
+
12
+ Заменяет `e-imzo.js` и `e-imzo-client.js` из официального примера. Вызовы E-IMZO те же, но
13
+ на Promise, с типами, без глобальных переменных и без правок `String.prototype`/`Date.prototype`.
14
+
15
+ > **Неофициальная библиотека.** Не связана с разработчиками E-IMZO.
16
+
17
+ **[Документация](https://abduazimkhuja.github.io/eimzo-ts/ru/)** · **[Демо](https://abduazimkhuja.github.io/eimzo-ts/demo/)** работает и без E-IMZO, на вымышленных ключах.
18
+
19
+ Только для ПК: подпись выполняет приложение E-IMZO на компьютере пользователя. Мобильный
20
+ вход (ID-CARD E-IMZO MOBILE) пока не поддерживается.
21
+
22
+ ## Установка
23
+
24
+ ```bash
25
+ npm install eimzo-ts
26
+ ```
27
+
28
+ Без сборщика:
29
+
30
+ ```html
31
+ <script src="https://unpkg.com/eimzo-ts@0.1/dist/index.global.js"></script>
32
+ <script>
33
+ const eimzo = EimzoClient.createEimzo({ apiKeys: EimzoClient.DEV_API_KEYS });
34
+ </script>
35
+ ```
36
+
37
+ ## Быстрый старт
38
+
39
+ ```ts
40
+ import { createEimzo, createFetchBackend, DEV_API_KEYS } from 'eimzo-ts';
41
+
42
+ const eimzo = createEimzo({
43
+ apiKeys: { ...DEV_API_KEYS, 'my-site.uz': 'API-KEY от НИЦ НТ' },
44
+ backend: createFetchBackend({
45
+ challengeUrl: '/api/eimzo/challenge',
46
+ loginUrl: '/api/eimzo/login',
47
+ timestampUrl: '/api/eimzo/timestamp',
48
+ init: { credentials: 'include' }, // заголовки, CSRF и т.п.
49
+ }),
50
+ });
51
+
52
+ const keys = await eimzo.listKeys(); // ключи пользователя
53
+ const user = await eimzo.login(keys[0]); // вход: пароль спросит окно E-IMZO
54
+ const pkcs7 = await eimzo.signDocument('документ'); // подпись + метка времени
55
+ ```
56
+
57
+ Создавайте **один** экземпляр на всё приложение: он хранит `keyId` загруженного ключа.
58
+
59
+ ## API
60
+
61
+ | Метод | Что делает |
62
+ |---|---|
63
+ | `init()` | Проверяет версию E-IMZO и устанавливает API-ключи. Вызывается сам перед любой операцией. |
64
+ | `getVersion()` | Версия установленного E-IMZO. |
65
+ | `listKeys()` | Ключи (`EimzoKey`): `CN`, `TIN`, `PINFL`, `O`, `T`, `validFrom`, `validTo`, `expired`. |
66
+ | `listDevices()` | Подключены ли ID-карта, BAIK-токен, CKC: `{ idcard, baikey, ckc }`. |
67
+ | `loadKey(key \| 'idcard' \| 'baikey' \| 'ckc')` | Загружает ключ, запоминает `keyId`. Предыдущий ключ выгружается. |
68
+ | `sign(data, { detached, base64, keyId })` | PKCS#7 в base64. `data` — строка, `Uint8Array` или `ArrayBuffer`. |
69
+ | `signFile(file, { detached, maxSize })` | Подпись `File`/`Blob`. По умолчанию detached, не больше 10 МБ. |
70
+ | `login(key)` | Вход: challenge → `loadKey` → подпись → `backend.login`. |
71
+ | `signDocument(data, options)` | `sign` → `backend.timestamp`. |
72
+ | `unloadKey()` | Выгружает ключ из E-IMZO. Вызывайте при выходе пользователя. |
73
+ | `call(plugin, name, args)` | Любая функция E-IMZO, см. `http://127.0.0.1:64646/apidoc.html`. |
74
+ | `setLocale(locale)`, `t(error)` | Язык сообщений об ошибках. |
75
+
76
+ ### Опции `createEimzo`
77
+
78
+ | Опция | По умолчанию | |
79
+ |---|---|---|
80
+ | `apiKeys` | — | `{ домен: ключ }` или `[домен, ключ, ...]`. Для localhost — `DEV_API_KEYS`. |
81
+ | `backend` | — | `createFetchBackend(...)` или свой объект, см. ниже. |
82
+ | `minVersion` | `'4.86'` | Ниже — ошибка `OUTDATED_VERSION`. |
83
+ | `locale` | `'ru'` | `'ru'`, `'uz-Latn'`, `'uz-Cyrl'`, `'kaa'`, `'en'` или свой код. |
84
+ | `messages` | — | Свои тексты ошибок. |
85
+ | `autoReloadKey` | `true` | Если E-IMZO забыл `keyId`, загрузить ключ заново и повторить подпись. |
86
+ | `timeoutMs` | без ограничения | Таймаут вызова E-IMZO. |
87
+ | `url`, `WebSocketImpl`, `transport` | | Для тестов и нестандартного окружения. |
88
+
89
+ ## Ошибки
90
+
91
+ Все ошибки — `EimzoError`. Для логики используйте `code`, для показа — `message`
92
+ (уже на языке `locale`) или `eimzo.t(error)`.
93
+
94
+ ```ts
95
+ import { isEimzoError } from 'eimzo-ts';
96
+
97
+ try {
98
+ await eimzo.login(key);
99
+ } catch (e) {
100
+ if (isEimzoError(e, 'CANCELLED')) return; // пользователь закрыл окно
101
+ if (isEimzoError(e, 'NOT_INSTALLED')) showDownloadLink();
102
+ else showError(eimzo.t(e));
103
+ }
104
+ ```
105
+
106
+ | `code` | Когда |
107
+ |---|---|
108
+ | `NOT_INSTALLED` | E-IMZO не установлен или не запущен. |
109
+ | `OUTDATED_VERSION` | Версия ниже `minVersion`; в `params` — `installed` и `min`. |
110
+ | `API_KEY_REJECTED` | Нет API-KEY для домена страницы. |
111
+ | `WRONG_PASSWORD` | Неверный пароль ключа. |
112
+ | `CANCELLED` | Пользователь закрыл окно пароля. |
113
+ | `KEY_NOT_FOUND` | E-IMZO не знает `keyId` (прошло 24 часа, перезапуск E-IMZO). |
114
+ | `KEY_NOT_LOADED` | `sign()` до `loadKey()` — ошибка в коде. |
115
+ | `FILE_TOO_LARGE` | Файл больше `maxSize`. |
116
+ | `BACKEND_NOT_CONFIGURED` | Нет нужного метода в `backend` — ошибка в коде. |
117
+ | `BACKEND_ERROR` | Backend ответил ошибкой; `httpStatus`, `params.detail`. |
118
+ | `EIMZO_ERROR` | Прочие ошибки E-IMZO; исходный текст в `reason`, код в `status`. |
119
+ | `TIMEOUT`, `WEBSOCKET_UNSUPPORTED` | Редкие случаи. |
120
+
121
+ ### Языки
122
+
123
+ ```ts
124
+ const eimzo = createEimzo({
125
+ locale: 'uz-Latn',
126
+ messages: {
127
+ 'uz-Latn': { WRONG_PASSWORD: () => 'Parol xato, qayta urinib ko‘ring.' }, // заменить один текст
128
+ tg: { NOT_INSTALLED: () => '...' }, // добавить язык
129
+ },
130
+ });
131
+ eimzo.setLocale('en');
132
+ ```
133
+
134
+ Недостающие тексты берутся из русского. Без экземпляра: `formatEimzoError(error, 'en')`.
135
+
136
+ ## Пароль
137
+
138
+ - Пароль вводится в окне E-IMZO; сайт его не видит.
139
+ - Без флажка «Запомнить на 6 час.» E-IMZO помнит пароль 1 минуту, с флажком — 6 часов.
140
+ Запоминается для `keyId`, поэтому держите один экземпляр `Eimzo`.
141
+ - После перезагрузки страницы `keyId` теряется — снова нужен `loadKey()`.
142
+ - `unloadKey()` при выходе из аккаунта стирает запомненный пароль на этом компьютере.
143
+ - Несколько вызовов `sign()` подряд (двойной клик) выполняются по очереди, а не открывают два окна.
144
+
145
+ ## Backend
146
+
147
+ Браузер не обращается к e-imzo-server напрямую. `createFetchBackend` ждёт ответы в формате
148
+ e-imzo-server, поэтому backend может проксировать запросы:
149
+
150
+ | Запрос клиента | Backend | Ответ |
151
+ |---|---|---|
152
+ | `GET challengeUrl` | `GET /frontend/challenge`, без кеша | `{ "status": 1, "challenge": "..." }` |
153
+ | `POST loginUrl`, тело — PKCS#7 | `POST /backend/auth`, поиск пользователя по ПИНФЛ/ИНН, сессия | любой JSON — вернётся из `login()` |
154
+ | `POST timestampUrl`, тело — PKCS#7 | `POST /frontend/timestamp/pkcs7` | `{ "status": 1, "pkcs7b64": "..." }` |
155
+
156
+ Подробно, с примером на Java (Spring Boot): [docs/backend.md](docs/backend.md).
157
+
158
+ Другой формат — свой объект вместо `createFetchBackend`:
159
+
160
+ ```ts
161
+ createEimzo({
162
+ backend: {
163
+ getChallenge: () => api.get('/challenge').then((r) => r.data.value),
164
+ login: (pkcs7) => api.post('/login', { pkcs7 }).then((r) => r.data),
165
+ timestamp: (pkcs7) => api.post('/timestamp', { pkcs7 }).then((r) => r.data.pkcs7),
166
+ },
167
+ });
168
+ ```
169
+
170
+ ## Фреймворки
171
+
172
+ **Angular**
173
+
174
+ ```ts
175
+ @Injectable({ providedIn: 'root' })
176
+ export class EimzoService {
177
+ readonly client = createEimzo({ apiKeys: environment.eimzoApiKeys, backend: createFetchBackend({ /* ... */ }) });
178
+ }
179
+
180
+ // компонент
181
+ keys = signal<EimzoKey[]>([]);
182
+ async ngOnInit() { this.keys.set(await this.eimzo.client.listKeys()); }
183
+ async login(key: EimzoKey) { await this.eimzo.client.login(key); this.router.navigate(['/cabinet']); }
184
+ ```
185
+
186
+ Для `HttpClient` с интерсепторами передайте свой `backend` через `firstValueFrom(this.http.get(...))`.
187
+
188
+ **React**
189
+
190
+ ```tsx
191
+ export const eimzo = createEimzo({ /* ... */ }); // модуль-синглтон
192
+
193
+ function KeyPicker() {
194
+ const [keys, setKeys] = useState<EimzoKey[]>([]);
195
+ const [error, setError] = useState<string>();
196
+ useEffect(() => { eimzo.listKeys().then(setKeys, (e) => setError(eimzo.t(e))); }, []);
197
+ // ...
198
+ }
199
+ ```
200
+
201
+ **Vue**
202
+
203
+ ```ts
204
+ export const eimzo = createEimzo({ /* ... */ });
205
+
206
+ const keys = ref<EimzoKey[]>([]);
207
+ onMounted(async () => { keys.value = await eimzo.listKeys(); });
208
+ ```
209
+
210
+ ## API-ключи
211
+
212
+ - `localhost` и `127.0.0.1` — `DEV_API_KEYS` (публичные ключи из официального примера).
213
+ - Другой домен или IP при разработке — «Режим разработчика» в меню E-IMZO в трее.
214
+ - Production — API-KEY выдаёт НИЦ НТ, отдельно на каждый домен и поддомен.
215
+
216
+ ## Переход с e-imzo.js
217
+
218
+ Соответствие функций `EIMZOClient` и этой библиотеки: [docs/migration.md](docs/migration.md).
219
+
220
+ ## Разработка
221
+
222
+ ```bash
223
+ npm install
224
+ npm test # vitest
225
+ npm run typecheck
226
+ npm run build # dist/: ESM, CJS, IIFE + .d.ts
227
+ npm run demo # http://localhost:3000/demo/
228
+ npm run check:eimzo # проверка на установленном E-IMZO; --interactive N — с подписью ключом N
229
+ ```
230
+
231
+ ## Лицензия
232
+
233
+ [MIT](LICENSE)
package/dist/index.cjs CHANGED
@@ -152,10 +152,11 @@ function notInstalledError(wsCode, cause) {
152
152
  }
153
153
  var STATUS_KEY_NOT_FOUND = [-1010, -1014];
154
154
  var STATUS_CANCELLED = [-5e3];
155
+ var WRONG_PASSWORD_REASONS = /BadPaddingException|Sequence tag error|getSecretKey failed/;
155
156
  function errorFromResponse(res) {
156
157
  const { status, reason } = res;
157
158
  const details = { reason, status };
158
- if (reason && reason.indexOf("BadPaddingException") !== -1) return new EimzoError("WRONG_PASSWORD", {}, details);
159
+ if (reason && WRONG_PASSWORD_REASONS.test(reason)) return new EimzoError("WRONG_PASSWORD", {}, details);
159
160
  if (status !== void 0 && STATUS_KEY_NOT_FOUND.indexOf(status) !== -1) {
160
161
  return new EimzoError("KEY_NOT_FOUND", {}, details);
161
162
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/base64.ts","../src/certificate.ts","../src/locales/format.ts","../src/locales/ru.ts","../src/errors.ts","../src/locales/en.ts","../src/locales/kaa.ts","../src/locales/uz-Latn.ts","../src/locales/uz-Cyrl.ts","../src/i18n.ts","../src/transport.ts","../src/eimzo.ts","../src/backend.ts"],"sourcesContent":["export {\n Eimzo,\n createEimzo,\n DEV_API_KEYS,\n DEFAULT_MAX_FILE_SIZE,\n type SignFileOptions,\n type ApiKeys,\n type DeviceType,\n type EimzoOptions,\n type EimzoVersion,\n type LoadKeyOptions,\n type SignOptions,\n type SignableData,\n} from './eimzo';\nexport { createFetchBackend, type EimzoBackend, type FetchBackendOptions } from './backend';\nexport {\n parseCertificateInfo,\n parseX500,\n type CertificateInfo,\n type EimzoKey,\n type PfxKey,\n type TokenKey,\n} from './certificate';\nexport {\n EimzoError,\n isEimzoError,\n type EimzoErrorCode,\n type EimzoErrorDetails,\n type EimzoErrorParams,\n type EimzoMessages,\n} from './errors';\nexport {\n builtinMessages,\n DEFAULT_LOCALE,\n formatEimzoError,\n type BuiltinLocale,\n type EimzoLocale,\n type MessageOverrides,\n} from './i18n';\nexport { en } from './locales/en';\nexport { kaa } from './locales/kaa';\nexport { ru } from './locales/ru';\nexport { uzLatn } from './locales/uz-Latn';\nexport { uzCyrl } from './locales/uz-Cyrl';\nexport {\n createCapiwsTransport,\n createDefaultTransport,\n createWebSocketTransport,\n defaultEimzoUrl,\n type CapiwsLike,\n type EimzoRequest,\n type EimzoResponse,\n type Transport,\n type WebSocketTransportOptions,\n} from './transport';\n","export function bytesToBase64(bytes: Uint8Array): string {\n let binary = '';\n const chunk = 0x8000;\n for (let i = 0; i < bytes.length; i += chunk) {\n binary += String.fromCharCode.apply(null, Array.from(bytes.subarray(i, i + chunk)));\n }\n return btoa(binary);\n}\n\nexport function utf8ToBase64(text: string): string {\n return bytesToBase64(new TextEncoder().encode(text));\n}\n","export interface CertificateInfo {\n serialNumber: string;\n /** ФИО владельца. */\n CN: string;\n /** ИНН; для физлиц без ИНН — UID, как в e-imzo-client.js. */\n TIN: string;\n PINFL: string;\n UID: string;\n /** Организация. */\n O: string;\n /** Должность. */\n T: string;\n validFrom: Date | null;\n validTo: Date | null;\n /** Срок действия истёк на момент получения списка. */\n expired: boolean;\n}\n\nexport interface PfxKey extends CertificateInfo {\n type: 'pfx';\n disk: string;\n path: string;\n name: string;\n alias: string;\n}\n\n/** Токен, найденный плагином `ftjc` (только E-IMZO старше 4.12). */\nexport interface TokenKey extends CertificateInfo {\n type: 'ftjc';\n cardUID: string;\n statusInfo: string;\n ownerName: string;\n info: string;\n}\n\nexport type EimzoKey = PfxKey | TokenKey;\n\nconst OID_ALIASES: Record<string, string> = {\n '1.2.860.3.16.1.1': 'INN',\n '1.2.860.3.16.1.2': 'PINFL',\n};\n\n// Атрибут начинается в начале строки или после запятой: `cn=...,1.2.860.3.16.1.2=...`\nconst ATTRIBUTE_START = /(?:^|,)\\s*([A-Za-z][A-Za-z0-9]*|\\d+(?:\\.\\d+)+)=/g;\n\n/**\n * Разбирает строку вида `cn=Иванов,uid=123,validto=2024.09.24 23:59:59` в словарь\n * с ключами в верхнем регистре. Значения могут содержать запятые.\n */\nexport function parseX500(source: string): Record<string, string> {\n const matches: { key: string; start: number; end: number }[] = [];\n ATTRIBUTE_START.lastIndex = 0;\n for (let m = ATTRIBUTE_START.exec(source); m; m = ATTRIBUTE_START.exec(source)) {\n matches.push({ key: m[1], start: m.index, end: m.index + m[0].length });\n }\n const result: Record<string, string> = {};\n matches.forEach((m, i) => {\n const key = OID_ALIASES[m.key] ?? m.key.toUpperCase();\n const value = source.slice(m.end, i + 1 < matches.length ? matches[i + 1].start : source.length);\n if (!(key in result)) result[key] = value;\n });\n return result;\n}\n\n/** PFX отдаёт даты как `2022.09.24 17:29:21`, токены — в формате, понятном `Date`. */\nexport function parseEimzoDate(value: string | undefined): Date | null {\n if (!value) return null;\n const normalized = /^\\d{4}\\.\\d{2}\\.\\d{2}/.test(value)\n ? value.replace(/\\./g, '-').replace(' ', 'T')\n : value;\n const date = new Date(normalized);\n return isNaN(date.getTime()) ? null : date;\n}\n\n/** Возвращает `null` для сертификатов без ИНН и ПИНФЛ — e-imzo-client.js их пропускает. */\nexport function parseCertificateInfo(x500: string, now: Date = new Date()): CertificateInfo | null {\n const a = parseX500(x500);\n const TIN = a.INN || a.UID || '';\n const PINFL = a.PINFL || '';\n if (!TIN && !PINFL) return null;\n const validTo = parseEimzoDate(a.VALIDTO);\n // E-IMZO отдаёт alias в нижнем регистре; как и e-imzo-client.js, показываем имена заглавными.\n const upper = (value: string | undefined) => (value || '').toUpperCase();\n return {\n serialNumber: a.SERIALNUMBER || '',\n CN: upper(a.CN),\n TIN,\n PINFL,\n UID: a.UID || '',\n O: upper(a.O),\n T: upper(a.T),\n validFrom: parseEimzoDate(a.VALIDFROM),\n validTo,\n expired: validTo !== null && validTo.getTime() < now.getTime(),\n };\n}\n","/** Размер в байтах → \"12.3 MB\" (одинаково для всех языков). */\nexport function formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n","import type { EimzoMessages } from '../errors';\nimport { formatSize } from './format';\n\nconst DOWNLOAD_URL = 'https://e-imzo.uz/main/downloads/';\n\nexport const ru: EimzoMessages = {\n NOT_INSTALLED: () => 'Нет соединения с E-IMZO. Убедитесь, что приложение E-IMZO установлено и запущено.',\n WEBSOCKET_UNSUPPORTED: () => 'Браузер не поддерживает WebSocket. Обновите браузер.',\n TIMEOUT: () => 'E-IMZO не ответил вовремя. Попробуйте ещё раз.',\n OUTDATED_VERSION: (p) =>\n `Установлена устаревшая версия E-IMZO (${p.installed}). Установите версию ${p.min} или новее: ${DOWNLOAD_URL}`,\n API_KEY_REJECTED: () => 'E-IMZO отклонил API-ключ для этого сайта.',\n WRONG_PASSWORD: () => 'Неверный пароль.',\n CANCELLED: () => 'Операция отменена.',\n KEY_NOT_FOUND: () => 'Ключ не найден в E-IMZO. Выберите ключ заново.',\n FILE_TOO_LARGE: (p) => `Файл слишком большой (${formatSize(p.size)}). Максимум — ${formatSize(p.max)}.`,\n KEY_NOT_LOADED: () => 'Ключ не выбран.',\n BACKEND_NOT_CONFIGURED: (p) => `Backend не настроен: нет методов ${p.methods}.`,\n BACKEND_ERROR: (p) =>\n p.detail ? `Ошибка сервера: ${p.detail}` : p.status ? `Ошибка сервера (HTTP ${p.status}).` : 'Ошибка сервера.',\n EIMZO_ERROR: (p) => (p.reason ? `Ошибка E-IMZO: ${p.reason}` : 'Неизвестная ошибка E-IMZO.'),\n};\n","import { ru } from './locales/ru';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\ntype NoParams = {};\n\n/** Параметры, которые подставляются в текст ошибки, по каждому коду. */\nexport interface EimzoErrorParams {\n /** E-IMZO.exe не запущен или не установлен (WebSocket не открылся). */\n NOT_INSTALLED: NoParams;\n /** Браузер не поддерживает WebSocket. */\n WEBSOCKET_UNSUPPORTED: NoParams;\n /** E-IMZO не ответил за `timeoutMs`. */\n TIMEOUT: NoParams;\n /** Установленная версия E-IMZO ниже `minVersion`. */\n OUTDATED_VERSION: { installed: string; min: string };\n /** E-IMZO отклонил API-KEY для домена страницы. */\n API_KEY_REJECTED: NoParams;\n /** Неверный пароль PFX-ключа. */\n WRONG_PASSWORD: NoParams;\n /** Пользователь закрыл окно пароля/PIN. Обычно это не ошибка, показывать не нужно. */\n CANCELLED: NoParams;\n /** E-IMZO не знает этот `keyId`: прошло 24 часа, ключ выгружен или E-IMZO перезапущен. */\n KEY_NOT_FOUND: NoParams;\n /** Файл больше `maxSize` в `signFile()`. Размеры в байтах. */\n FILE_TOO_LARGE: { size: number; max: number };\n /** `sign()` вызван до `loadKey()`. */\n KEY_NOT_LOADED: NoParams;\n /** В `options.backend` нет нужных методов — ошибка в коде приложения. */\n BACKEND_NOT_CONFIGURED: { methods: string };\n /** Backend ответил ошибкой или некорректными данными. */\n BACKEND_ERROR: { status?: number; detail?: string };\n /** Прочие ошибки E-IMZO; исходный текст — в `reason`. */\n EIMZO_ERROR: { reason?: string };\n}\n\nexport type EimzoErrorCode = keyof EimzoErrorParams;\n\n/** Словарь сообщений: функция на каждый код ошибки. */\nexport type EimzoMessages = {\n [C in EimzoErrorCode]: (params: EimzoErrorParams[C]) => string;\n};\n\nexport interface EimzoErrorDetails {\n /** Текст ошибки от E-IMZO (`data.reason`), не переводится. */\n reason?: string;\n /** Числовой `status` из ответа E-IMZO. */\n status?: number;\n /** Код закрытия WebSocket. */\n wsCode?: number;\n /** HTTP-статус ответа backend. */\n httpStatus?: number;\n cause?: unknown;\n}\n\ntype ParamsArg<C extends EimzoErrorCode> = keyof EimzoErrorParams[C] extends never\n ? [params?: EimzoErrorParams[C], details?: EimzoErrorDetails]\n : [params: EimzoErrorParams[C], details?: EimzoErrorDetails];\n\n/**\n * Ошибка библиотеки. Для логики используйте `code` и `params`.\n * `message` — текст на языке экземпляра `Eimzo` (по умолчанию на русском);\n * чтобы перевести на другой язык, используйте `eimzo.t(error)` или `formatEimzoError()`.\n */\nexport class EimzoError<C extends EimzoErrorCode = EimzoErrorCode> extends Error {\n readonly code: C;\n readonly params: EimzoErrorParams[C];\n readonly reason?: string;\n readonly status?: number;\n readonly wsCode?: number;\n readonly httpStatus?: number;\n\n constructor(code: C, ...[params, details = {}]: ParamsArg<C>) {\n const p = (params ?? {}) as EimzoErrorParams[C];\n super(ru[code](p));\n this.name = 'EimzoError';\n this.code = code;\n this.params = p;\n this.reason = details.reason;\n this.status = details.status;\n this.wsCode = details.wsCode;\n this.httpStatus = details.httpStatus;\n if (details.cause !== undefined) (this as { cause?: unknown }).cause = details.cause;\n }\n}\n\nexport function isEimzoError<C extends EimzoErrorCode>(error: unknown, code?: C): error is EimzoError<C> {\n return error instanceof EimzoError && (code === undefined || error.code === code);\n}\n\nexport function notInstalledError(wsCode?: number, cause?: unknown): EimzoError<'NOT_INSTALLED'> {\n return new EimzoError('NOT_INSTALLED', {}, { wsCode, cause });\n}\n\n// Коды `status` E-IMZO, проверенные на E-IMZO 6.3.5.\nconst STATUS_KEY_NOT_FOUND = [-1010, -1014];\n// -5000 «Ввод пароля отменен»: кнопка «Отмена» в окне пароля.\nconst STATUS_CANCELLED = [-5000];\n\n/** Превращает неуспешный ответ E-IMZO (`status`, `reason`) в типизированную ошибку. */\nexport function errorFromResponse(res: { status?: number; reason?: string }): EimzoError {\n const { status, reason } = res;\n const details = { reason, status };\n if (reason && reason.indexOf('BadPaddingException') !== -1) return new EimzoError('WRONG_PASSWORD', {}, details);\n if (status !== undefined && STATUS_KEY_NOT_FOUND.indexOf(status) !== -1) {\n return new EimzoError('KEY_NOT_FOUND', {}, details);\n }\n if (status !== undefined && STATUS_CANCELLED.indexOf(status) !== -1) return new EimzoError('CANCELLED', {}, details);\n return new EimzoError('EIMZO_ERROR', { reason }, details);\n}\n","import type { EimzoMessages } from '../errors';\nimport { formatSize } from './format';\n\nconst DOWNLOAD_URL = 'https://e-imzo.uz/main/downloads/';\n\nexport const en: EimzoMessages = {\n NOT_INSTALLED: () => 'Cannot connect to E-IMZO. Make sure the E-IMZO application is installed and running.',\n WEBSOCKET_UNSUPPORTED: () => 'Your browser does not support WebSocket. Please update your browser.',\n TIMEOUT: () => 'E-IMZO did not respond in time. Please try again.',\n OUTDATED_VERSION: (p) =>\n `An outdated version of E-IMZO is installed (${p.installed}). Install version ${p.min} or newer: ${DOWNLOAD_URL}`,\n API_KEY_REJECTED: () => 'E-IMZO rejected the API key for this site.',\n WRONG_PASSWORD: () => 'Wrong password.',\n CANCELLED: () => 'Operation cancelled.',\n KEY_NOT_FOUND: () => 'Key not found in E-IMZO. Please select the key again.',\n FILE_TOO_LARGE: (p) => `File is too large (${formatSize(p.size)}). Maximum is ${formatSize(p.max)}.`,\n KEY_NOT_LOADED: () => 'No key selected.',\n BACKEND_NOT_CONFIGURED: (p) => `Backend is not configured: missing methods ${p.methods}.`,\n BACKEND_ERROR: (p) =>\n p.detail ? `Server error: ${p.detail}` : p.status ? `Server error (HTTP ${p.status}).` : 'Server error.',\n EIMZO_ERROR: (p) => (p.reason ? `E-IMZO error: ${p.reason}` : 'Unknown E-IMZO error.'),\n};\n","import type { EimzoMessages } from '../errors';\nimport { formatSize } from './format';\n\nconst DOWNLOAD_URL = 'https://e-imzo.uz/main/downloads/';\n\n/** Qaraqalpaqsha (latın). */\nexport const kaa: EimzoMessages = {\n NOT_INSTALLED: () =>\n 'E-IMZO menen baylanıs joq. E-IMZO baǵdarlaması ornatılǵanın hám iske túsirilgenin tekseriń.',\n WEBSOCKET_UNSUPPORTED: () => 'Brauzer WebSocket texnologiyasın qollap-quwatlamaydı. Brauzerdi jańalań.',\n TIMEOUT: () => 'E-IMZO óz waqtında juwap bermedi. Qaytadan urınıp kóriń.',\n OUTDATED_VERSION: (p) =>\n `E-IMZO baǵdarlamasınıń eski versiyası ornatılǵan (${p.installed}). ${p.min} yamasa onnan jańa versiyanı ornatıń: ${DOWNLOAD_URL}`,\n API_KEY_REJECTED: () => 'E-IMZO usı sayt ushın API-giltti qabıl etpedi.',\n WRONG_PASSWORD: () => 'Parol qáte.',\n CANCELLED: () => 'Ámel biykar etildi.',\n KEY_NOT_FOUND: () => 'Gilt E-IMZO-da tabılmadı. Giltti qaytadan tańlań.',\n FILE_TOO_LARGE: (p) => `Fayl júdá úlken (${formatSize(p.size)}). Eń kóbi — ${formatSize(p.max)}.`,\n KEY_NOT_LOADED: () => 'Gilt tańlanbaǵan.',\n BACKEND_NOT_CONFIGURED: (p) => `Backend sazlanbaǵan: ${p.methods} metodları joq.`,\n BACKEND_ERROR: (p) =>\n p.detail ? `Server qátesi: ${p.detail}` : p.status ? `Server qátesi (HTTP ${p.status}).` : 'Server qátesi.',\n EIMZO_ERROR: (p) => (p.reason ? `E-IMZO qátesi: ${p.reason}` : 'E-IMZO-da belgisiz qátelik.'),\n};\n","import type { EimzoMessages } from '../errors';\nimport { formatSize } from './format';\n\nconst DOWNLOAD_URL = 'https://e-imzo.uz/main/downloads/';\n\n/** Oʻzbekcha (lotin). */\nexport const uzLatn: EimzoMessages = {\n NOT_INSTALLED: () =>\n 'E-IMZO bilan aloqa yoʻq. E-IMZO dasturi oʻrnatilgan va ishga tushirilganiga ishonch hosil qiling.',\n WEBSOCKET_UNSUPPORTED: () => 'Brauzer WebSocket texnologiyasini qoʻllab-quvvatlamaydi. Brauzerni yangilang.',\n TIMEOUT: () => 'E-IMZO oʻz vaqtida javob bermadi. Qaytadan urinib koʻring.',\n OUTDATED_VERSION: (p) =>\n `E-IMZO dasturining eskirgan versiyasi oʻrnatilgan (${p.installed}). ${p.min} yoki undan yangi versiyani oʻrnating: ${DOWNLOAD_URL}`,\n API_KEY_REJECTED: () => 'E-IMZO ushbu sayt uchun API-kalitni rad etdi.',\n WRONG_PASSWORD: () => 'Parol notoʻgʻri.',\n CANCELLED: () => 'Amal bekor qilindi.',\n KEY_NOT_FOUND: () => 'Kalit E-IMZO da topilmadi. Kalitni qaytadan tanlang.',\n FILE_TOO_LARGE: (p) => `Fayl juda katta (${formatSize(p.size)}). Eng koʻpi — ${formatSize(p.max)}.`,\n KEY_NOT_LOADED: () => 'Kalit tanlanmagan.',\n BACKEND_NOT_CONFIGURED: (p) => `Backend sozlanmagan: ${p.methods} metodlari yoʻq.`,\n BACKEND_ERROR: (p) =>\n p.detail ? `Server xatosi: ${p.detail}` : p.status ? `Server xatosi (HTTP ${p.status}).` : 'Server xatosi.',\n EIMZO_ERROR: (p) => (p.reason ? `E-IMZO xatosi: ${p.reason}` : 'E-IMZO da nomaʼlum xatolik.'),\n};\n","import type { EimzoMessages } from '../errors';\nimport { formatSize } from './format';\n\nconst DOWNLOAD_URL = 'https://e-imzo.uz/main/downloads/';\n\n/** Ўзбекча (кирилл). */\nexport const uzCyrl: EimzoMessages = {\n NOT_INSTALLED: () =>\n 'E-IMZO билан алоқа йўқ. E-IMZO дастури ўрнатилган ва ишга туширилганига ишонч ҳосил қилинг.',\n WEBSOCKET_UNSUPPORTED: () => 'Браузер WebSocket технологиясини қўллаб-қувватламайди. Браузерни янгиланг.',\n TIMEOUT: () => 'E-IMZO ўз вақтида жавоб бермади. Қайтадан уриниб кўринг.',\n OUTDATED_VERSION: (p) =>\n `E-IMZO дастурининг эскирган версияси ўрнатилган (${p.installed}). ${p.min} ёки ундан янги версияни ўрнатинг: ${DOWNLOAD_URL}`,\n API_KEY_REJECTED: () => 'E-IMZO ушбу сайт учун API-калитни рад этди.',\n WRONG_PASSWORD: () => 'Парол нотўғри.',\n CANCELLED: () => 'Амал бекор қилинди.',\n KEY_NOT_FOUND: () => 'Калит E-IMZO да топилмади. Калитни қайтадан танланг.',\n FILE_TOO_LARGE: (p) => `Файл жуда катта (${formatSize(p.size)}). Энг кўпи — ${formatSize(p.max)}.`,\n KEY_NOT_LOADED: () => 'Калит танланмаган.',\n BACKEND_NOT_CONFIGURED: (p) => `Backend созланмаган: ${p.methods} методлари йўқ.`,\n BACKEND_ERROR: (p) =>\n p.detail ? `Сервер хатоси: ${p.detail}` : p.status ? `Сервер хатоси (HTTP ${p.status}).` : 'Сервер хатоси.',\n EIMZO_ERROR: (p) => (p.reason ? `E-IMZO хатоси: ${p.reason}` : 'E-IMZO да номаълум хатолик.'),\n};\n","import { EimzoError, type EimzoErrorCode, type EimzoMessages } from './errors';\nimport { en } from './locales/en';\nimport { kaa } from './locales/kaa';\nimport { ru } from './locales/ru';\nimport { uzLatn } from './locales/uz-Latn';\nimport { uzCyrl } from './locales/uz-Cyrl';\n\n/** Встроенные языки. Можно передать и любой свой код языка вместе с `messages`. */\nexport type BuiltinLocale = 'ru' | 'uz-Latn' | 'uz-Cyrl' | 'kaa' | 'en';\nexport type EimzoLocale = BuiltinLocale | (string & {});\n\nexport const DEFAULT_LOCALE: BuiltinLocale = 'ru';\n\nexport const builtinMessages: Record<BuiltinLocale, EimzoMessages> = {\n ru,\n 'uz-Latn': uzLatn,\n 'uz-Cyrl': uzCyrl,\n kaa,\n en,\n};\n\n/** Свои тексты: новый язык целиком или замена отдельных сообщений встроенного. */\nexport type MessageOverrides = Record<string, Partial<EimzoMessages>>;\n\n/**\n * Текст ошибки на нужном языке. Порядок поиска: `overrides[locale]` → встроенный `locale`\n * → русский. Для не-`EimzoError` возвращает `error.message`.\n */\nexport function formatEimzoError(\n error: unknown,\n locale: EimzoLocale = DEFAULT_LOCALE,\n overrides: MessageOverrides = {},\n): string {\n if (!(error instanceof EimzoError)) {\n return error instanceof Error ? error.message : String(error);\n }\n const code = error.code as EimzoErrorCode;\n const format = (overrides[locale]?.[code] ??\n builtinMessages[locale as BuiltinLocale]?.[code] ??\n ru[code]) as (params: unknown) => string;\n return format(error.params);\n}\n","import { EimzoError, notInstalledError } from './errors';\n\nexport interface EimzoRequest {\n plugin?: string;\n name: string;\n arguments?: unknown[];\n}\n\nexport interface EimzoResponse {\n success: boolean;\n reason?: string;\n [key: string]: any;\n}\n\n/** Один вызов функции E-IMZO. Подменяется в тестах или для нестандартного окружения. */\nexport type Transport = (request: EimzoRequest) => Promise<EimzoResponse>;\n\nexport interface WebSocketTransportOptions {\n /** По умолчанию выбирается по протоколу страницы, см. `defaultEimzoUrl()`. */\n url?: string;\n /**\n * Таймаут одного вызова, мс. По умолчанию не ограничен: `create_pkcs7`\n * ждёт, пока пользователь введёт пароль.\n */\n timeoutMs?: number;\n /** Реализация WebSocket, если глобальной нет. */\n WebSocketImpl?: typeof WebSocket;\n}\n\n/** Совместимый с `CAPIWS` объект; так устроено браузерное расширение `EIMZOEXT`. */\nexport interface CapiwsLike {\n callFunction(def: EimzoRequest, onSuccess: (event: unknown, data: EimzoResponse) => void, onError: (code?: number) => void): void;\n version(onSuccess: (event: unknown, data: EimzoResponse) => void, onError: (code?: number) => void): void;\n apikey(keys: unknown[], onSuccess: (event: unknown, data: EimzoResponse) => void, onError: (code?: number) => void): void;\n}\n\nexport function defaultEimzoUrl(): string {\n const https = typeof location !== 'undefined' && location.protocol.toLowerCase() === 'https:';\n return (https ? 'wss://127.0.0.1:64443' : 'ws://127.0.0.1:64646') + '/service/cryptapi';\n}\n\n/** Как `CAPIWS` в e-imzo.js: одно WebSocket-соединение на каждый вызов. */\nexport function createWebSocketTransport(options: WebSocketTransportOptions = {}): Transport {\n return (request) =>\n new Promise<EimzoResponse>((resolve, reject) => {\n const WS = options.WebSocketImpl ?? (globalThis as { WebSocket?: typeof WebSocket }).WebSocket;\n if (!WS) {\n reject(new EimzoError('WEBSOCKET_UNSUPPORTED'));\n return;\n }\n\n let socket: WebSocket;\n try {\n socket = new WS(options.url ?? defaultEimzoUrl());\n } catch (e) {\n reject(notInstalledError(undefined, e));\n return;\n }\n\n let settled = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const settle = (fn: () => void) => {\n if (settled) return;\n settled = true;\n if (timer !== undefined) clearTimeout(timer);\n fn();\n };\n\n if (options.timeoutMs) {\n timer = setTimeout(() => {\n settle(() => reject(new EimzoError('TIMEOUT')));\n socket.close();\n }, options.timeoutMs);\n }\n\n socket.onopen = () => socket.send(JSON.stringify(request));\n socket.onmessage = (event) => {\n settle(() => {\n try {\n resolve(JSON.parse(event.data as string) as EimzoResponse);\n } catch (e) {\n reject(new EimzoError('EIMZO_ERROR', { reason: 'invalid JSON response' }, { cause: e }));\n }\n });\n socket.close();\n };\n // Закрытие до ответа — значит E-IMZO недоступен.\n socket.onclose = (event) => settle(() => reject(notInstalledError(event.code)));\n });\n}\n\nexport function createCapiwsTransport(capiws: CapiwsLike): Transport {\n return (request) =>\n new Promise<EimzoResponse>((resolve, reject) => {\n const ok = (_event: unknown, data: EimzoResponse) => resolve(data);\n const fail = (code?: number) => reject(notInstalledError(code));\n if (!request.plugin && request.name === 'version') capiws.version(ok, fail);\n else if (!request.plugin && request.name === 'apikey') capiws.apikey(request.arguments ?? [], ok, fail);\n else capiws.callFunction(request, ok, fail);\n });\n}\n\n/**\n * Через расширение `EIMZOEXT`, если оно есть на странице, иначе через WebSocket.\n * Проверка на каждом вызове: расширение может внедриться после загрузки скрипта.\n */\nexport function createDefaultTransport(options: WebSocketTransportOptions = {}): Transport {\n const ws = createWebSocketTransport(options);\n return (request) => {\n const ext = (globalThis as { EIMZOEXT?: CapiwsLike }).EIMZOEXT;\n return ext ? createCapiwsTransport(ext)(request) : ws(request);\n };\n}\n","import { bytesToBase64, utf8ToBase64 } from './base64';\nimport type { EimzoBackend } from './backend';\nimport { parseCertificateInfo, type EimzoKey, type PfxKey, type TokenKey } from './certificate';\nimport { EimzoError, errorFromResponse, isEimzoError } from './errors';\nimport { DEFAULT_LOCALE, formatEimzoError, type EimzoLocale, type MessageOverrides } from './i18n';\nimport { createDefaultTransport, type EimzoResponse, type Transport, type WebSocketTransportOptions } from './transport';\n\n/** Пары «домен → API-KEY» или плоский массив `[домен, ключ, домен, ключ, ...]`, как в демо. */\nexport type ApiKeys = Record<string, string> | string[];\n\n/** Аппаратные носители: подписывают без `load_key`, `id` передаётся в `create_pkcs7` напрямую. */\nexport type DeviceType = 'idcard' | 'baikey' | 'ckc';\n\nexport interface EimzoVersion {\n major: number;\n minor: number;\n}\n\nexport interface EimzoOptions<TLogin = unknown> extends WebSocketTransportOptions {\n /**\n * API-ключи доменов. Пусто — `apikey` не вызывается (E-IMZO v6 подбирает ключ по домену сам).\n * Для localhost используйте `DEV_API_KEYS`.\n */\n apiKeys?: ApiKeys;\n /** Минимальная версия E-IMZO, `\"major.minor\"`. По умолчанию `\"4.86\"`. */\n minVersion?: string;\n backend?: EimzoBackend<TLogin>;\n /** Своя реализация вызовов E-IMZO, например для тестов. */\n transport?: Transport;\n /**\n * Язык сообщений об ошибках: `'ru'` (по умолчанию), `'uz-Latn'`, `'uz-Cyrl'`, `'kaa'`, `'en'`\n * или свой код вместе с `messages`.\n */\n locale?: EimzoLocale;\n /**\n * Свои тексты: `{ ru: { WRONG_PASSWORD: () => '...' } }` заменяет одно сообщение,\n * `{ kk: { ... } }` добавляет язык. Недостающие сообщения берутся из русского.\n */\n messages?: MessageOverrides;\n /**\n * Если E-IMZO забыл `keyId` (24 часа, перезапуск E-IMZO), `sign()` сам загрузит\n * тот же ключ заново и повторит подпись. E-IMZO при этом снова спросит пароль.\n * По умолчанию `true`.\n */\n autoReloadKey?: boolean;\n}\n\nexport interface LoadKeyOptions {\n /**\n * Сразу спросить пароль/PIN (`verify_password` / `verify_pin`).\n * Внимание: `verify_password` не показывает флажок «Запомнить на 6 час.»\n * и сокращает уже запомненный пароль до 1 минуты.\n */\n verifyPassword?: boolean;\n}\n\nexport interface SignOptions {\n /** PKCS#7 без вложенных данных (detached). По умолчанию — с данными (attached). */\n detached?: boolean;\n /** Строка `data` уже в base64 (например, содержимое файла). */\n base64?: boolean;\n /** Подписать другим ключом, а не загруженным через `loadKey()`. */\n keyId?: string;\n}\n\nexport type SignableData = string | Uint8Array | ArrayBuffer;\n\nexport interface SignFileOptions {\n /** По умолчанию `true`: файл хранится у вас, класть его копию в подпись незачем. */\n detached?: boolean;\n /** Максимальный размер файла в байтах. По умолчанию 10 МБ. */\n maxSize?: number;\n /** Подписать другим ключом, а не загруженным через `loadKey()`. */\n keyId?: string;\n}\n\nexport const DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;\n\n/** Публичные ключи E-IMZO для локальной разработки (из официального примера). */\nexport const DEV_API_KEYS: Record<string, string> = {\n localhost:\n '96D0C1491615C82B9A54D9989779DF825B690748224C2B04F500F370D51827CE2644D8D4A82C18184D73AB8530BB8ED537269603F61DB0D03D2104ABF789970B',\n '127.0.0.1':\n 'A7BCFA5D490B351BE0754130DF03A068F855DB4333D43921125B9CF2670EF6A40370C646B90401955E1F7BC9CDBF59CE0B2C5467D820BE189C845D0B79CFC96F',\n};\n\nconst DEFAULT_MIN_VERSION = '4.86';\n// Пороги из e-imzo-client.js (NEW_API2 / NEW_API3).\nconst VERSION_PFX_ONLY = 412;\nconst VERSION_BAIK_CKC = 486;\n\nconst versionNumber = (v: EimzoVersion) => v.major * 100 + v.minor;\n\nfunction parseVersion(value: string): EimzoVersion {\n const [major, minor] = value.split('.').map((part) => parseInt(part, 10));\n if (isNaN(major) || isNaN(minor)) throw new Error(`Invalid E-IMZO version: \"${value}\"`);\n return { major, minor };\n}\n\nfunction flattenApiKeys(keys: ApiKeys | undefined): string[] {\n if (!keys) return [];\n if (Array.isArray(keys)) return keys;\n return Object.keys(keys).reduce<string[]>((acc, domain) => acc.concat(domain, keys[domain]), []);\n}\n\nfunction toBase64(data: SignableData, alreadyBase64: boolean): string {\n if (typeof data === 'string') return alreadyBase64 ? data : utf8ToBase64(data);\n return bytesToBase64(data instanceof Uint8Array ? data : new Uint8Array(data));\n}\n\nexport class Eimzo<TLogin = unknown> {\n private readonly transport: Transport;\n private readonly minVersion: EimzoVersion;\n private ready: Promise<EimzoVersion> | null = null;\n private currentKeyId: string | null = null;\n /** Ключ, из которого получен `currentKeyId`, — чтобы загрузить его заново. */\n private currentKey: EimzoKey | DeviceType | null = null;\n private currentLocale: EimzoLocale;\n /** Хвост очереди операций, которые могут открыть окно пароля. */\n private queue: Promise<unknown> = Promise.resolve();\n\n constructor(private readonly options: EimzoOptions<TLogin> = {}) {\n this.transport = options.transport ?? createDefaultTransport(options);\n this.minVersion = parseVersion(options.minVersion ?? DEFAULT_MIN_VERSION);\n this.currentLocale = options.locale ?? DEFAULT_LOCALE;\n }\n\n /** `keyId` последнего `loadKey()`. Держите его, чтобы работало запоминание пароля на 6 часов. */\n get keyId(): string | null {\n return this.currentKeyId;\n }\n\n get locale(): EimzoLocale {\n return this.currentLocale;\n }\n\n /** Сменить язык. Влияет на `t()` и на `message` следующих ошибок. */\n setLocale(locale: EimzoLocale): void {\n this.currentLocale = locale;\n }\n\n /**\n * Текст ошибки на текущем (или указанном) языке. Используйте при показе, а не\n * `error.message`: так после смены языка старая ошибка тоже покажется на новом.\n */\n t(error: unknown, locale: EimzoLocale = this.currentLocale): string {\n return formatEimzoError(error, locale, this.options.messages);\n }\n\n /** Все публичные методы проходят через guard: `message` ошибки — на текущем языке. */\n private guard<T>(work: () => Promise<T>): Promise<T> {\n return work().catch((error: unknown) => {\n if (error instanceof EimzoError) error.message = this.t(error);\n throw error;\n });\n }\n\n /**\n * Операции, которые могут открыть окно пароля, выполняются строго по одной:\n * двойной клик по «Подписать» не откроет два окна, второй вызов дождётся первого.\n */\n private exclusive<T>(work: () => Promise<T>): Promise<T> {\n const run = this.queue.then(work, work);\n this.queue = run.catch(() => undefined);\n return this.guard(() => run);\n }\n\n /**\n * Проверяет версию и устанавливает API-ключи. Вызывается автоматически перед любой\n * операцией; результат кешируется, после ошибки следующий вызов пробует заново.\n */\n init(): Promise<EimzoVersion> {\n if (!this.ready) {\n this.ready = this.doInit().catch((error) => {\n this.ready = null;\n throw error;\n });\n }\n const ready = this.ready;\n return this.guard(() => ready);\n }\n\n private async doInit(): Promise<EimzoVersion> {\n const version = await this.readVersion();\n if (versionNumber(version) < versionNumber(this.minVersion)) {\n throw new EimzoError('OUTDATED_VERSION', {\n installed: `${version.major}.${version.minor}`,\n min: `${this.minVersion.major}.${this.minVersion.minor}`,\n });\n }\n const apiKeys = flattenApiKeys(this.options.apiKeys);\n if (apiKeys.length > 0) {\n const res = await this.transport({ name: 'apikey', arguments: apiKeys });\n if (!res.success) throw new EimzoError('API_KEY_REJECTED', {}, { reason: res.reason });\n }\n return version;\n }\n\n /** Версия установленного E-IMZO. Не требует API-ключа. */\n getVersion(): Promise<EimzoVersion> {\n return this.guard(() => this.readVersion());\n }\n\n private async readVersion(): Promise<EimzoVersion> {\n const res = await this.transport({ name: 'version' });\n if (!res.success) throw errorFromResponse(res);\n const major = parseInt(res.major, 10);\n const minor = parseInt(res.minor, 10);\n if (isNaN(major) || isNaN(minor)) throw new EimzoError('EIMZO_ERROR', { reason: 'version is undefined' });\n return { major, minor };\n }\n\n /** Прямой вызов функции плагина E-IMZO (см. http://127.0.0.1:64646/apidoc.html). */\n call(plugin: string, name: string, args: unknown[] = []): Promise<EimzoResponse> {\n return this.guard(() => this.invoke(plugin, name, args));\n }\n\n private async invoke(plugin: string, name: string, args: unknown[] = []): Promise<EimzoResponse> {\n await this.init();\n const res = await this.transport({ plugin, name, arguments: args });\n if (!res.success) throw errorFromResponse(res);\n return res;\n }\n\n /** PFX-ключи (и токены `ftjc` для E-IMZO старше 4.12). Ключи без ИНН и ПИНФЛ пропускаются. */\n listKeys(): Promise<EimzoKey[]> {\n return this.guard(async () => {\n const version = await this.init();\n const sources: Promise<EimzoKey[]>[] = [this.listPfx()];\n if (versionNumber(version) < VERSION_PFX_ONLY) sources.push(this.listTokens());\n\n const results = await Promise.allSettled(sources);\n const keys: EimzoKey[] = [];\n let firstError: unknown;\n for (const r of results) {\n if (r.status === 'fulfilled') keys.push(...r.value);\n else if (firstError === undefined) firstError = r.reason;\n }\n // Как в оригинале: ошибка, только если ничего не нашлось.\n if (keys.length === 0 && firstError !== undefined) throw firstError;\n return keys;\n });\n }\n\n private async listPfx(): Promise<PfxKey[]> {\n const res = await this.invoke('pfx', 'list_all_certificates');\n const now = new Date();\n const keys: PfxKey[] = [];\n for (const el of res.certificates ?? []) {\n const info = parseCertificateInfo(el.alias, now);\n if (info) keys.push({ ...info, type: 'pfx', disk: el.disk, path: el.path, name: el.name, alias: el.alias });\n }\n return keys;\n }\n\n private async listTokens(): Promise<TokenKey[]> {\n const res = await this.invoke('ftjc', 'list_all_keys', ['']);\n const now = new Date();\n const keys: TokenKey[] = [];\n for (const el of res.tokens ?? []) {\n const info = parseCertificateInfo(el.info, now);\n if (info) {\n keys.push({\n ...info,\n type: 'ftjc',\n cardUID: el.cardUID,\n statusInfo: el.statusInfo,\n ownerName: el.ownerName,\n info: el.info,\n });\n }\n }\n return keys;\n }\n\n /** Какие аппаратные носители подключены. Носители, которые версия E-IMZO не поддерживает, — `false`. */\n listDevices(): Promise<Record<DeviceType, boolean>> {\n return this.guard(async () => {\n const v = versionNumber(await this.init());\n const check = async (enabled: boolean, plugin: string, name: string, field: string) => {\n if (!enabled) return false;\n try {\n const res = await this.invoke(plugin, name);\n return Array.isArray(res[field]) && res[field].length > 0;\n } catch (error) {\n // Ошибка плагина = носителя нет; ошибки связи пробрасываем.\n if (error instanceof EimzoError && error.code === 'EIMZO_ERROR') return false;\n throw error;\n }\n };\n const [idcard, baikey, ckc] = await Promise.all([\n check(v >= VERSION_PFX_ONLY, 'idcard', 'list_readers', 'readers'),\n check(v >= VERSION_BAIK_CKC, 'baikey', 'list_tokens', 'tokens'),\n check(v >= VERSION_BAIK_CKC, 'ckc', 'list_ckc', 'devices'),\n ]);\n return { idcard, baikey, ckc };\n });\n }\n\n /**\n * Загружает ключ и запоминает его `keyId` для `sign()`.\n * Для аппаратного носителя (`'idcard' | 'baikey' | 'ckc'`) E-IMZO не вызывается.\n * Каждый вызов для PFX создаёт новую сессию, и E-IMZO снова спросит пароль.\n * Предыдущий загруженный PFX-ключ выгружается из E-IMZO.\n */\n loadKey(key: EimzoKey | DeviceType, options: LoadKeyOptions = {}): Promise<string> {\n return this.exclusive(() => this.doLoadKey(key, options));\n }\n\n private async doLoadKey(key: EimzoKey | DeviceType, options: LoadKeyOptions): Promise<string> {\n await this.releaseCurrentKey();\n let keyId: string;\n if (typeof key === 'string') {\n keyId = key;\n } else if (key.type === 'pfx') {\n keyId = (await this.invoke('pfx', 'load_key', [key.disk, key.path, key.name, key.alias])).keyId;\n if (options.verifyPassword) await this.invoke('pfx', 'verify_password', [keyId]);\n } else {\n keyId = (await this.invoke('ftjc', 'load_key', [key.cardUID])).keyId;\n if (options.verifyPassword) await this.invoke('ftjc', 'verify_pin', [keyId, '1']);\n }\n this.currentKey = key;\n this.currentKeyId = keyId;\n return keyId;\n }\n\n /**\n * Выгрузить ключ из E-IMZO и забыть его. Вызывайте при выходе пользователя:\n * иначе пароль, запомненный на 6 часов, останется в E-IMZO на этом компьютере.\n */\n unloadKey(): Promise<void> {\n return this.exclusive(() => this.releaseCurrentKey());\n }\n\n private async releaseCurrentKey(): Promise<void> {\n const key = this.currentKey;\n const keyId = this.currentKeyId;\n this.currentKey = null;\n this.currentKeyId = null;\n if (!keyId || !key || typeof key === 'string' || key.type !== 'pfx') return;\n try {\n await this.invoke('pfx', 'unload_key', [keyId]);\n } catch (error) {\n // Уже выгружен или E-IMZO перезапущен — цель достигнута.\n if (!isEimzoError(error, 'KEY_NOT_FOUND')) throw error;\n }\n }\n\n /** Создаёт PKCS#7 (base64). Пароль спрашивает окно E-IMZO, сайт его не видит. */\n sign(data: SignableData, options: SignOptions = {}): Promise<string> {\n return this.exclusive(() => this.doSign(data, options));\n }\n\n /**\n * Подписывает файл (`File` из `<input type=\"file\">` или `Blob`). По умолчанию detached.\n * Метку времени добавьте отдельно: `signDocument(await file.arrayBuffer(), { detached: true })`.\n */\n signFile(file: Blob, options: SignFileOptions = {}): Promise<string> {\n return this.exclusive(async () => {\n const max = options.maxSize ?? DEFAULT_MAX_FILE_SIZE;\n if (file.size > max) throw new EimzoError('FILE_TOO_LARGE', { size: file.size, max });\n const bytes = new Uint8Array(await file.arrayBuffer());\n return this.doSign(bytes, { detached: options.detached ?? true, keyId: options.keyId });\n });\n }\n\n private async doSign(data: SignableData, options: SignOptions): Promise<string> {\n const keyId = options.keyId ?? this.currentKeyId;\n if (!keyId) throw new EimzoError('KEY_NOT_LOADED');\n const data64 = toBase64(data, options.base64 === true);\n const create = (id: string) =>\n this.invoke('pkcs7', 'create_pkcs7', [data64, id, options.detached ? 'yes' : 'no']).then((res) => res.pkcs7_64);\n try {\n return await create(keyId);\n } catch (error) {\n // E-IMZO забыл keyId (24 часа или перезапуск): загружаем тот же ключ и пробуем ещё раз.\n const key = this.currentKey;\n const canReload =\n this.options.autoReloadKey !== false &&\n options.keyId === undefined &&\n isEimzoError(error, 'KEY_NOT_FOUND') &&\n key !== null &&\n typeof key !== 'string';\n if (!canReload) throw error;\n this.currentKeyId = null; // старый keyId уже недействителен, выгружать нечего\n return create(await this.doLoadKey(key, {}));\n }\n }\n\n /**\n * Вход по ЭЦП: challenge с backend → `loadKey` → подпись challenge → `backend.login`.\n * Возвращает то, что вернул `backend.login` (сессия, JWT и т.п.).\n */\n login(key: EimzoKey | DeviceType): Promise<TLogin> {\n return this.exclusive(async () => {\n const backend = this.requireBackend('getChallenge', 'login');\n const challenge = await backend.getChallenge!();\n await this.doLoadKey(key, {});\n const pkcs7 = await this.doSign(challenge, {});\n return backend.login!(pkcs7);\n });\n }\n\n /** Подпись документа загруженным ключом + метка времени через backend. */\n signDocument(data: SignableData, options: SignOptions = {}): Promise<string> {\n return this.exclusive(async () => {\n const backend = this.requireBackend('timestamp');\n const pkcs7 = await this.doSign(data, options);\n return backend.timestamp!(pkcs7);\n });\n }\n\n private requireBackend(...methods: (keyof EimzoBackend)[]): EimzoBackend<TLogin> {\n const backend = this.options.backend;\n const missing = methods.filter((m) => typeof backend?.[m] !== 'function');\n if (!backend || missing.length > 0) {\n throw new EimzoError('BACKEND_NOT_CONFIGURED', { methods: missing.join(', ') });\n }\n return backend;\n }\n}\n\nexport function createEimzo<TLogin = unknown>(options: EimzoOptions<TLogin> = {}): Eimzo<TLogin> {\n return new Eimzo<TLogin>(options);\n}\n","import { EimzoError } from './errors';\n\n/**\n * Связь с вашим backend. Библиотека не знает ваших адресов и формата ответа,\n * поэтому каждый шаг задаётся функцией. Нужны только те методы, которые вы вызываете:\n * `login()` требует `getChallenge` и `login`, `signDocument()` — `timestamp`.\n */\nexport interface EimzoBackend<TLogin = unknown> {\n /** Одноразовый challenge от e-imzo-server (`/frontend/challenge`). */\n getChallenge?(): Promise<string>;\n /** Отправить PKCS#7 с подписанным challenge; backend проверяет его через `/backend/auth`. */\n login?(pkcs7: string): Promise<TLogin>;\n /** Прикрепить метку времени (`/frontend/timestamp/pkcs7`); вернуть PKCS#7 с меткой. */\n timestamp?(pkcs7: string): Promise<string>;\n}\n\nexport interface FetchBackendOptions {\n /** GET, ответ `{ challenge, status }`. */\n challengeUrl?: string;\n /** POST, тело — PKCS#7 в base64 (text/plain). Ответ возвращается из `login()` как есть. */\n loginUrl?: string;\n /** POST, тело — PKCS#7 в base64 (text/plain). Ответ `{ pkcs7b64, status }`. */\n timestampUrl?: string;\n /** Общие параметры запросов: заголовки (CSRF, Authorization), `credentials` и т.п. */\n init?: RequestInit;\n fetch?: typeof fetch;\n}\n\n/**\n * Backend на `fetch`. Форматы ответов совпадают с e-imzo-server, поэтому backend\n * может просто проксировать `/frontend/challenge` и `/frontend/timestamp/pkcs7`.\n */\nexport function createFetchBackend<TLogin = unknown>(options: FetchBackendOptions): EimzoBackend<TLogin> {\n const doFetch = options.fetch ?? ((input: RequestInfo | URL, init?: RequestInit) => fetch(input, init));\n const base = options.init ?? {};\n\n const request = async (url: string, init: RequestInit): Promise<any> => {\n const response = await doFetch(url, {\n ...base,\n ...init,\n headers: { ...headersToObject(base.headers), ...headersToObject(init.headers) },\n });\n const text = await response.text();\n let body: any = text;\n try {\n body = text ? JSON.parse(text) : null;\n } catch {\n // не JSON — вернём текст\n }\n if (!response.ok) {\n const detail = body && typeof body === 'object' && body.message ? String(body.message) : undefined;\n throw new EimzoError('BACKEND_ERROR', { status: response.status, detail }, { httpStatus: response.status });\n }\n if (body && typeof body === 'object' && 'status' in body && body.status !== 1) {\n const detail = body.message ? String(body.message) : `status ${body.status}`;\n throw new EimzoError('BACKEND_ERROR', { status: response.status, detail }, { httpStatus: response.status });\n }\n return body;\n };\n\n const postPkcs7 = (url: string, pkcs7: string) =>\n request(url, { method: 'POST', body: pkcs7, headers: { 'Content-Type': 'text/plain' } });\n\n const backend: EimzoBackend<TLogin> = {};\n if (options.challengeUrl) {\n const url = options.challengeUrl;\n backend.getChallenge = async () => {\n const body = await request(url, { method: 'GET', cache: 'no-store' });\n if (!body || typeof body.challenge !== 'string') {\n throw new EimzoError('BACKEND_ERROR', { detail: 'no \"challenge\" field in response' });\n }\n return body.challenge;\n };\n }\n if (options.loginUrl) {\n const url = options.loginUrl;\n backend.login = (pkcs7) => postPkcs7(url, pkcs7);\n }\n if (options.timestampUrl) {\n const url = options.timestampUrl;\n backend.timestamp = async (pkcs7) => {\n const body = await postPkcs7(url, pkcs7);\n if (!body || typeof body.pkcs7b64 !== 'string') {\n throw new EimzoError('BACKEND_ERROR', { detail: 'no \"pkcs7b64\" field in response' });\n }\n return body.pkcs7b64;\n };\n }\n return backend;\n}\n\nfunction headersToObject(headers: HeadersInit | undefined): Record<string, string> {\n if (!headers) return {};\n if (typeof Headers !== 'undefined' && headers instanceof Headers) {\n const result: Record<string, string> = {};\n headers.forEach((value, key) => (result[key] = value));\n return result;\n }\n if (Array.isArray(headers)) return Object.fromEntries(headers);\n return headers as Record<string, string>;\n}\n"],"mappings":"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","names":["DOWNLOAD_URL","DOWNLOAD_URL","DOWNLOAD_URL","DOWNLOAD_URL"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/base64.ts","../src/certificate.ts","../src/locales/format.ts","../src/locales/ru.ts","../src/errors.ts","../src/locales/en.ts","../src/locales/kaa.ts","../src/locales/uz-Latn.ts","../src/locales/uz-Cyrl.ts","../src/i18n.ts","../src/transport.ts","../src/eimzo.ts","../src/backend.ts"],"sourcesContent":["export {\n Eimzo,\n createEimzo,\n DEV_API_KEYS,\n DEFAULT_MAX_FILE_SIZE,\n type SignFileOptions,\n type ApiKeys,\n type DeviceType,\n type EimzoOptions,\n type EimzoVersion,\n type LoadKeyOptions,\n type SignOptions,\n type SignableData,\n} from './eimzo';\nexport { createFetchBackend, type EimzoBackend, type FetchBackendOptions } from './backend';\nexport {\n parseCertificateInfo,\n parseX500,\n type CertificateInfo,\n type EimzoKey,\n type PfxKey,\n type TokenKey,\n} from './certificate';\nexport {\n EimzoError,\n isEimzoError,\n type EimzoErrorCode,\n type EimzoErrorDetails,\n type EimzoErrorParams,\n type EimzoMessages,\n} from './errors';\nexport {\n builtinMessages,\n DEFAULT_LOCALE,\n formatEimzoError,\n type BuiltinLocale,\n type EimzoLocale,\n type MessageOverrides,\n} from './i18n';\nexport { en } from './locales/en';\nexport { kaa } from './locales/kaa';\nexport { ru } from './locales/ru';\nexport { uzLatn } from './locales/uz-Latn';\nexport { uzCyrl } from './locales/uz-Cyrl';\nexport {\n createCapiwsTransport,\n createDefaultTransport,\n createWebSocketTransport,\n defaultEimzoUrl,\n type CapiwsLike,\n type EimzoRequest,\n type EimzoResponse,\n type Transport,\n type WebSocketTransportOptions,\n} from './transport';\n","export function bytesToBase64(bytes: Uint8Array): string {\n let binary = '';\n const chunk = 0x8000;\n for (let i = 0; i < bytes.length; i += chunk) {\n binary += String.fromCharCode.apply(null, Array.from(bytes.subarray(i, i + chunk)));\n }\n return btoa(binary);\n}\n\nexport function utf8ToBase64(text: string): string {\n return bytesToBase64(new TextEncoder().encode(text));\n}\n","export interface CertificateInfo {\n serialNumber: string;\n /** ФИО владельца. */\n CN: string;\n /** ИНН; для физлиц без ИНН — UID, как в e-imzo-client.js. */\n TIN: string;\n PINFL: string;\n UID: string;\n /** Организация. */\n O: string;\n /** Должность. */\n T: string;\n validFrom: Date | null;\n validTo: Date | null;\n /** Срок действия истёк на момент получения списка. */\n expired: boolean;\n}\n\nexport interface PfxKey extends CertificateInfo {\n type: 'pfx';\n disk: string;\n path: string;\n name: string;\n alias: string;\n}\n\n/** Токен, найденный плагином `ftjc` (только E-IMZO старше 4.12). */\nexport interface TokenKey extends CertificateInfo {\n type: 'ftjc';\n cardUID: string;\n statusInfo: string;\n ownerName: string;\n info: string;\n}\n\nexport type EimzoKey = PfxKey | TokenKey;\n\nconst OID_ALIASES: Record<string, string> = {\n '1.2.860.3.16.1.1': 'INN',\n '1.2.860.3.16.1.2': 'PINFL',\n};\n\n// Атрибут начинается в начале строки или после запятой: `cn=...,1.2.860.3.16.1.2=...`\nconst ATTRIBUTE_START = /(?:^|,)\\s*([A-Za-z][A-Za-z0-9]*|\\d+(?:\\.\\d+)+)=/g;\n\n/**\n * Разбирает строку вида `cn=Иванов,uid=123,validto=2024.09.24 23:59:59` в словарь\n * с ключами в верхнем регистре. Значения могут содержать запятые.\n */\nexport function parseX500(source: string): Record<string, string> {\n const matches: { key: string; start: number; end: number }[] = [];\n ATTRIBUTE_START.lastIndex = 0;\n for (let m = ATTRIBUTE_START.exec(source); m; m = ATTRIBUTE_START.exec(source)) {\n matches.push({ key: m[1], start: m.index, end: m.index + m[0].length });\n }\n const result: Record<string, string> = {};\n matches.forEach((m, i) => {\n const key = OID_ALIASES[m.key] ?? m.key.toUpperCase();\n const value = source.slice(m.end, i + 1 < matches.length ? matches[i + 1].start : source.length);\n if (!(key in result)) result[key] = value;\n });\n return result;\n}\n\n/** PFX отдаёт даты как `2022.09.24 17:29:21`, токены — в формате, понятном `Date`. */\nexport function parseEimzoDate(value: string | undefined): Date | null {\n if (!value) return null;\n const normalized = /^\\d{4}\\.\\d{2}\\.\\d{2}/.test(value)\n ? value.replace(/\\./g, '-').replace(' ', 'T')\n : value;\n const date = new Date(normalized);\n return isNaN(date.getTime()) ? null : date;\n}\n\n/** Возвращает `null` для сертификатов без ИНН и ПИНФЛ — e-imzo-client.js их пропускает. */\nexport function parseCertificateInfo(x500: string, now: Date = new Date()): CertificateInfo | null {\n const a = parseX500(x500);\n const TIN = a.INN || a.UID || '';\n const PINFL = a.PINFL || '';\n if (!TIN && !PINFL) return null;\n const validTo = parseEimzoDate(a.VALIDTO);\n // E-IMZO отдаёт alias в нижнем регистре; как и e-imzo-client.js, показываем имена заглавными.\n const upper = (value: string | undefined) => (value || '').toUpperCase();\n return {\n serialNumber: a.SERIALNUMBER || '',\n CN: upper(a.CN),\n TIN,\n PINFL,\n UID: a.UID || '',\n O: upper(a.O),\n T: upper(a.T),\n validFrom: parseEimzoDate(a.VALIDFROM),\n validTo,\n expired: validTo !== null && validTo.getTime() < now.getTime(),\n };\n}\n","/** Размер в байтах → \"12.3 MB\" (одинаково для всех языков). */\nexport function formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n","import type { EimzoMessages } from '../errors';\nimport { formatSize } from './format';\n\nconst DOWNLOAD_URL = 'https://e-imzo.uz/main/downloads/';\n\nexport const ru: EimzoMessages = {\n NOT_INSTALLED: () => 'Нет соединения с E-IMZO. Убедитесь, что приложение E-IMZO установлено и запущено.',\n WEBSOCKET_UNSUPPORTED: () => 'Браузер не поддерживает WebSocket. Обновите браузер.',\n TIMEOUT: () => 'E-IMZO не ответил вовремя. Попробуйте ещё раз.',\n OUTDATED_VERSION: (p) =>\n `Установлена устаревшая версия E-IMZO (${p.installed}). Установите версию ${p.min} или новее: ${DOWNLOAD_URL}`,\n API_KEY_REJECTED: () => 'E-IMZO отклонил API-ключ для этого сайта.',\n WRONG_PASSWORD: () => 'Неверный пароль.',\n CANCELLED: () => 'Операция отменена.',\n KEY_NOT_FOUND: () => 'Ключ не найден в E-IMZO. Выберите ключ заново.',\n FILE_TOO_LARGE: (p) => `Файл слишком большой (${formatSize(p.size)}). Максимум — ${formatSize(p.max)}.`,\n KEY_NOT_LOADED: () => 'Ключ не выбран.',\n BACKEND_NOT_CONFIGURED: (p) => `Backend не настроен: нет методов ${p.methods}.`,\n BACKEND_ERROR: (p) =>\n p.detail ? `Ошибка сервера: ${p.detail}` : p.status ? `Ошибка сервера (HTTP ${p.status}).` : 'Ошибка сервера.',\n EIMZO_ERROR: (p) => (p.reason ? `Ошибка E-IMZO: ${p.reason}` : 'Неизвестная ошибка E-IMZO.'),\n};\n","import { ru } from './locales/ru';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\ntype NoParams = {};\n\n/** Параметры, которые подставляются в текст ошибки, по каждому коду. */\nexport interface EimzoErrorParams {\n /** E-IMZO.exe не запущен или не установлен (WebSocket не открылся). */\n NOT_INSTALLED: NoParams;\n /** Браузер не поддерживает WebSocket. */\n WEBSOCKET_UNSUPPORTED: NoParams;\n /** E-IMZO не ответил за `timeoutMs`. */\n TIMEOUT: NoParams;\n /** Установленная версия E-IMZO ниже `minVersion`. */\n OUTDATED_VERSION: { installed: string; min: string };\n /** E-IMZO отклонил API-KEY для домена страницы. */\n API_KEY_REJECTED: NoParams;\n /** Неверный пароль PFX-ключа. */\n WRONG_PASSWORD: NoParams;\n /** Пользователь закрыл окно пароля/PIN. Обычно это не ошибка, показывать не нужно. */\n CANCELLED: NoParams;\n /** E-IMZO не знает этот `keyId`: прошло 24 часа, ключ выгружен или E-IMZO перезапущен. */\n KEY_NOT_FOUND: NoParams;\n /** Файл больше `maxSize` в `signFile()`. Размеры в байтах. */\n FILE_TOO_LARGE: { size: number; max: number };\n /** `sign()` вызван до `loadKey()`. */\n KEY_NOT_LOADED: NoParams;\n /** В `options.backend` нет нужных методов — ошибка в коде приложения. */\n BACKEND_NOT_CONFIGURED: { methods: string };\n /** Backend ответил ошибкой или некорректными данными. */\n BACKEND_ERROR: { status?: number; detail?: string };\n /** Прочие ошибки E-IMZO; исходный текст — в `reason`. */\n EIMZO_ERROR: { reason?: string };\n}\n\nexport type EimzoErrorCode = keyof EimzoErrorParams;\n\n/** Словарь сообщений: функция на каждый код ошибки. */\nexport type EimzoMessages = {\n [C in EimzoErrorCode]: (params: EimzoErrorParams[C]) => string;\n};\n\nexport interface EimzoErrorDetails {\n /** Текст ошибки от E-IMZO (`data.reason`), не переводится. */\n reason?: string;\n /** Числовой `status` из ответа E-IMZO. */\n status?: number;\n /** Код закрытия WebSocket. */\n wsCode?: number;\n /** HTTP-статус ответа backend. */\n httpStatus?: number;\n cause?: unknown;\n}\n\ntype ParamsArg<C extends EimzoErrorCode> = keyof EimzoErrorParams[C] extends never\n ? [params?: EimzoErrorParams[C], details?: EimzoErrorDetails]\n : [params: EimzoErrorParams[C], details?: EimzoErrorDetails];\n\n/**\n * Ошибка библиотеки. Для логики используйте `code` и `params`.\n * `message` — текст на языке экземпляра `Eimzo` (по умолчанию на русском);\n * чтобы перевести на другой язык, используйте `eimzo.t(error)` или `formatEimzoError()`.\n */\nexport class EimzoError<C extends EimzoErrorCode = EimzoErrorCode> extends Error {\n readonly code: C;\n readonly params: EimzoErrorParams[C];\n readonly reason?: string;\n readonly status?: number;\n readonly wsCode?: number;\n readonly httpStatus?: number;\n\n constructor(code: C, ...[params, details = {}]: ParamsArg<C>) {\n const p = (params ?? {}) as EimzoErrorParams[C];\n super(ru[code](p));\n this.name = 'EimzoError';\n this.code = code;\n this.params = p;\n this.reason = details.reason;\n this.status = details.status;\n this.wsCode = details.wsCode;\n this.httpStatus = details.httpStatus;\n if (details.cause !== undefined) (this as { cause?: unknown }).cause = details.cause;\n }\n}\n\nexport function isEimzoError<C extends EimzoErrorCode>(error: unknown, code?: C): error is EimzoError<C> {\n return error instanceof EimzoError && (code === undefined || error.code === code);\n}\n\nexport function notInstalledError(wsCode?: number, cause?: unknown): EimzoError<'NOT_INSTALLED'> {\n return new EimzoError('NOT_INSTALLED', {}, { wsCode, cause });\n}\n\n// Коды `status` E-IMZO, проверенные на E-IMZO 6.3.5.\nconst STATUS_KEY_NOT_FOUND = [-1010, -1014];\n// -5000 «Ввод пароля отменен»: кнопка «Отмена» в окне пароля.\nconst STATUS_CANCELLED = [-5000];\n// Неверный пароль PFX. Старые версии: BadPaddingException. E-IMZO 6.3 — status -9999 с текстом\n// «Sequence tag error» или «getSecretKey failed: Password is not ASCII» (пароль в другой раскладке).\n// -9999 бывает и у других ошибок, поэтому сверяем текст.\nconst WRONG_PASSWORD_REASONS = /BadPaddingException|Sequence tag error|getSecretKey failed/;\n\n/** Превращает неуспешный ответ E-IMZO (`status`, `reason`) в типизированную ошибку. */\nexport function errorFromResponse(res: { status?: number; reason?: string }): EimzoError {\n const { status, reason } = res;\n const details = { reason, status };\n if (reason && WRONG_PASSWORD_REASONS.test(reason)) return new EimzoError('WRONG_PASSWORD', {}, details);\n if (status !== undefined && STATUS_KEY_NOT_FOUND.indexOf(status) !== -1) {\n return new EimzoError('KEY_NOT_FOUND', {}, details);\n }\n if (status !== undefined && STATUS_CANCELLED.indexOf(status) !== -1) return new EimzoError('CANCELLED', {}, details);\n return new EimzoError('EIMZO_ERROR', { reason }, details);\n}\n","import type { EimzoMessages } from '../errors';\nimport { formatSize } from './format';\n\nconst DOWNLOAD_URL = 'https://e-imzo.uz/main/downloads/';\n\nexport const en: EimzoMessages = {\n NOT_INSTALLED: () => 'Cannot connect to E-IMZO. Make sure the E-IMZO application is installed and running.',\n WEBSOCKET_UNSUPPORTED: () => 'Your browser does not support WebSocket. Please update your browser.',\n TIMEOUT: () => 'E-IMZO did not respond in time. Please try again.',\n OUTDATED_VERSION: (p) =>\n `An outdated version of E-IMZO is installed (${p.installed}). Install version ${p.min} or newer: ${DOWNLOAD_URL}`,\n API_KEY_REJECTED: () => 'E-IMZO rejected the API key for this site.',\n WRONG_PASSWORD: () => 'Wrong password.',\n CANCELLED: () => 'Operation cancelled.',\n KEY_NOT_FOUND: () => 'Key not found in E-IMZO. Please select the key again.',\n FILE_TOO_LARGE: (p) => `File is too large (${formatSize(p.size)}). Maximum is ${formatSize(p.max)}.`,\n KEY_NOT_LOADED: () => 'No key selected.',\n BACKEND_NOT_CONFIGURED: (p) => `Backend is not configured: missing methods ${p.methods}.`,\n BACKEND_ERROR: (p) =>\n p.detail ? `Server error: ${p.detail}` : p.status ? `Server error (HTTP ${p.status}).` : 'Server error.',\n EIMZO_ERROR: (p) => (p.reason ? `E-IMZO error: ${p.reason}` : 'Unknown E-IMZO error.'),\n};\n","import type { EimzoMessages } from '../errors';\nimport { formatSize } from './format';\n\nconst DOWNLOAD_URL = 'https://e-imzo.uz/main/downloads/';\n\n/** Qaraqalpaqsha (latın). */\nexport const kaa: EimzoMessages = {\n NOT_INSTALLED: () =>\n 'E-IMZO menen baylanıs joq. E-IMZO baǵdarlaması ornatılǵanın hám iske túsirilgenin tekseriń.',\n WEBSOCKET_UNSUPPORTED: () => 'Brauzer WebSocket texnologiyasın qollap-quwatlamaydı. Brauzerdi jańalań.',\n TIMEOUT: () => 'E-IMZO óz waqtında juwap bermedi. Qaytadan urınıp kóriń.',\n OUTDATED_VERSION: (p) =>\n `E-IMZO baǵdarlamasınıń eski versiyası ornatılǵan (${p.installed}). ${p.min} yamasa onnan jańa versiyanı ornatıń: ${DOWNLOAD_URL}`,\n API_KEY_REJECTED: () => 'E-IMZO usı sayt ushın API-giltti qabıl etpedi.',\n WRONG_PASSWORD: () => 'Parol qáte.',\n CANCELLED: () => 'Ámel biykar etildi.',\n KEY_NOT_FOUND: () => 'Gilt E-IMZO-da tabılmadı. Giltti qaytadan tańlań.',\n FILE_TOO_LARGE: (p) => `Fayl júdá úlken (${formatSize(p.size)}). Eń kóbi — ${formatSize(p.max)}.`,\n KEY_NOT_LOADED: () => 'Gilt tańlanbaǵan.',\n BACKEND_NOT_CONFIGURED: (p) => `Backend sazlanbaǵan: ${p.methods} metodları joq.`,\n BACKEND_ERROR: (p) =>\n p.detail ? `Server qátesi: ${p.detail}` : p.status ? `Server qátesi (HTTP ${p.status}).` : 'Server qátesi.',\n EIMZO_ERROR: (p) => (p.reason ? `E-IMZO qátesi: ${p.reason}` : 'E-IMZO-da belgisiz qátelik.'),\n};\n","import type { EimzoMessages } from '../errors';\nimport { formatSize } from './format';\n\nconst DOWNLOAD_URL = 'https://e-imzo.uz/main/downloads/';\n\n/** Oʻzbekcha (lotin). */\nexport const uzLatn: EimzoMessages = {\n NOT_INSTALLED: () =>\n 'E-IMZO bilan aloqa yoʻq. E-IMZO dasturi oʻrnatilgan va ishga tushirilganiga ishonch hosil qiling.',\n WEBSOCKET_UNSUPPORTED: () => 'Brauzer WebSocket texnologiyasini qoʻllab-quvvatlamaydi. Brauzerni yangilang.',\n TIMEOUT: () => 'E-IMZO oʻz vaqtida javob bermadi. Qaytadan urinib koʻring.',\n OUTDATED_VERSION: (p) =>\n `E-IMZO dasturining eskirgan versiyasi oʻrnatilgan (${p.installed}). ${p.min} yoki undan yangi versiyani oʻrnating: ${DOWNLOAD_URL}`,\n API_KEY_REJECTED: () => 'E-IMZO ushbu sayt uchun API-kalitni rad etdi.',\n WRONG_PASSWORD: () => 'Parol notoʻgʻri.',\n CANCELLED: () => 'Amal bekor qilindi.',\n KEY_NOT_FOUND: () => 'Kalit E-IMZO da topilmadi. Kalitni qaytadan tanlang.',\n FILE_TOO_LARGE: (p) => `Fayl juda katta (${formatSize(p.size)}). Eng koʻpi — ${formatSize(p.max)}.`,\n KEY_NOT_LOADED: () => 'Kalit tanlanmagan.',\n BACKEND_NOT_CONFIGURED: (p) => `Backend sozlanmagan: ${p.methods} metodlari yoʻq.`,\n BACKEND_ERROR: (p) =>\n p.detail ? `Server xatosi: ${p.detail}` : p.status ? `Server xatosi (HTTP ${p.status}).` : 'Server xatosi.',\n EIMZO_ERROR: (p) => (p.reason ? `E-IMZO xatosi: ${p.reason}` : 'E-IMZO da nomaʼlum xatolik.'),\n};\n","import type { EimzoMessages } from '../errors';\nimport { formatSize } from './format';\n\nconst DOWNLOAD_URL = 'https://e-imzo.uz/main/downloads/';\n\n/** Ўзбекча (кирилл). */\nexport const uzCyrl: EimzoMessages = {\n NOT_INSTALLED: () =>\n 'E-IMZO билан алоқа йўқ. E-IMZO дастури ўрнатилган ва ишга туширилганига ишонч ҳосил қилинг.',\n WEBSOCKET_UNSUPPORTED: () => 'Браузер WebSocket технологиясини қўллаб-қувватламайди. Браузерни янгиланг.',\n TIMEOUT: () => 'E-IMZO ўз вақтида жавоб бермади. Қайтадан уриниб кўринг.',\n OUTDATED_VERSION: (p) =>\n `E-IMZO дастурининг эскирган версияси ўрнатилган (${p.installed}). ${p.min} ёки ундан янги версияни ўрнатинг: ${DOWNLOAD_URL}`,\n API_KEY_REJECTED: () => 'E-IMZO ушбу сайт учун API-калитни рад этди.',\n WRONG_PASSWORD: () => 'Парол нотўғри.',\n CANCELLED: () => 'Амал бекор қилинди.',\n KEY_NOT_FOUND: () => 'Калит E-IMZO да топилмади. Калитни қайтадан танланг.',\n FILE_TOO_LARGE: (p) => `Файл жуда катта (${formatSize(p.size)}). Энг кўпи — ${formatSize(p.max)}.`,\n KEY_NOT_LOADED: () => 'Калит танланмаган.',\n BACKEND_NOT_CONFIGURED: (p) => `Backend созланмаган: ${p.methods} методлари йўқ.`,\n BACKEND_ERROR: (p) =>\n p.detail ? `Сервер хатоси: ${p.detail}` : p.status ? `Сервер хатоси (HTTP ${p.status}).` : 'Сервер хатоси.',\n EIMZO_ERROR: (p) => (p.reason ? `E-IMZO хатоси: ${p.reason}` : 'E-IMZO да номаълум хатолик.'),\n};\n","import { EimzoError, type EimzoErrorCode, type EimzoMessages } from './errors';\nimport { en } from './locales/en';\nimport { kaa } from './locales/kaa';\nimport { ru } from './locales/ru';\nimport { uzLatn } from './locales/uz-Latn';\nimport { uzCyrl } from './locales/uz-Cyrl';\n\n/** Встроенные языки. Можно передать и любой свой код языка вместе с `messages`. */\nexport type BuiltinLocale = 'ru' | 'uz-Latn' | 'uz-Cyrl' | 'kaa' | 'en';\nexport type EimzoLocale = BuiltinLocale | (string & {});\n\nexport const DEFAULT_LOCALE: BuiltinLocale = 'ru';\n\nexport const builtinMessages: Record<BuiltinLocale, EimzoMessages> = {\n ru,\n 'uz-Latn': uzLatn,\n 'uz-Cyrl': uzCyrl,\n kaa,\n en,\n};\n\n/** Свои тексты: новый язык целиком или замена отдельных сообщений встроенного. */\nexport type MessageOverrides = Record<string, Partial<EimzoMessages>>;\n\n/**\n * Текст ошибки на нужном языке. Порядок поиска: `overrides[locale]` → встроенный `locale`\n * → русский. Для не-`EimzoError` возвращает `error.message`.\n */\nexport function formatEimzoError(\n error: unknown,\n locale: EimzoLocale = DEFAULT_LOCALE,\n overrides: MessageOverrides = {},\n): string {\n if (!(error instanceof EimzoError)) {\n return error instanceof Error ? error.message : String(error);\n }\n const code = error.code as EimzoErrorCode;\n const format = (overrides[locale]?.[code] ??\n builtinMessages[locale as BuiltinLocale]?.[code] ??\n ru[code]) as (params: unknown) => string;\n return format(error.params);\n}\n","import { EimzoError, notInstalledError } from './errors';\n\nexport interface EimzoRequest {\n plugin?: string;\n name: string;\n arguments?: unknown[];\n}\n\nexport interface EimzoResponse {\n success: boolean;\n reason?: string;\n [key: string]: any;\n}\n\n/** Один вызов функции E-IMZO. Подменяется в тестах или для нестандартного окружения. */\nexport type Transport = (request: EimzoRequest) => Promise<EimzoResponse>;\n\nexport interface WebSocketTransportOptions {\n /** По умолчанию выбирается по протоколу страницы, см. `defaultEimzoUrl()`. */\n url?: string;\n /**\n * Таймаут одного вызова, мс. По умолчанию не ограничен: `create_pkcs7`\n * ждёт, пока пользователь введёт пароль.\n */\n timeoutMs?: number;\n /** Реализация WebSocket, если глобальной нет. */\n WebSocketImpl?: typeof WebSocket;\n}\n\n/** Совместимый с `CAPIWS` объект; так устроено браузерное расширение `EIMZOEXT`. */\nexport interface CapiwsLike {\n callFunction(def: EimzoRequest, onSuccess: (event: unknown, data: EimzoResponse) => void, onError: (code?: number) => void): void;\n version(onSuccess: (event: unknown, data: EimzoResponse) => void, onError: (code?: number) => void): void;\n apikey(keys: unknown[], onSuccess: (event: unknown, data: EimzoResponse) => void, onError: (code?: number) => void): void;\n}\n\nexport function defaultEimzoUrl(): string {\n const https = typeof location !== 'undefined' && location.protocol.toLowerCase() === 'https:';\n return (https ? 'wss://127.0.0.1:64443' : 'ws://127.0.0.1:64646') + '/service/cryptapi';\n}\n\n/** Как `CAPIWS` в e-imzo.js: одно WebSocket-соединение на каждый вызов. */\nexport function createWebSocketTransport(options: WebSocketTransportOptions = {}): Transport {\n return (request) =>\n new Promise<EimzoResponse>((resolve, reject) => {\n const WS = options.WebSocketImpl ?? (globalThis as { WebSocket?: typeof WebSocket }).WebSocket;\n if (!WS) {\n reject(new EimzoError('WEBSOCKET_UNSUPPORTED'));\n return;\n }\n\n let socket: WebSocket;\n try {\n socket = new WS(options.url ?? defaultEimzoUrl());\n } catch (e) {\n reject(notInstalledError(undefined, e));\n return;\n }\n\n let settled = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const settle = (fn: () => void) => {\n if (settled) return;\n settled = true;\n if (timer !== undefined) clearTimeout(timer);\n fn();\n };\n\n if (options.timeoutMs) {\n timer = setTimeout(() => {\n settle(() => reject(new EimzoError('TIMEOUT')));\n socket.close();\n }, options.timeoutMs);\n }\n\n socket.onopen = () => socket.send(JSON.stringify(request));\n socket.onmessage = (event) => {\n settle(() => {\n try {\n resolve(JSON.parse(event.data as string) as EimzoResponse);\n } catch (e) {\n reject(new EimzoError('EIMZO_ERROR', { reason: 'invalid JSON response' }, { cause: e }));\n }\n });\n socket.close();\n };\n // Закрытие до ответа — значит E-IMZO недоступен.\n socket.onclose = (event) => settle(() => reject(notInstalledError(event.code)));\n });\n}\n\nexport function createCapiwsTransport(capiws: CapiwsLike): Transport {\n return (request) =>\n new Promise<EimzoResponse>((resolve, reject) => {\n const ok = (_event: unknown, data: EimzoResponse) => resolve(data);\n const fail = (code?: number) => reject(notInstalledError(code));\n if (!request.plugin && request.name === 'version') capiws.version(ok, fail);\n else if (!request.plugin && request.name === 'apikey') capiws.apikey(request.arguments ?? [], ok, fail);\n else capiws.callFunction(request, ok, fail);\n });\n}\n\n/**\n * Через расширение `EIMZOEXT`, если оно есть на странице, иначе через WebSocket.\n * Проверка на каждом вызове: расширение может внедриться после загрузки скрипта.\n */\nexport function createDefaultTransport(options: WebSocketTransportOptions = {}): Transport {\n const ws = createWebSocketTransport(options);\n return (request) => {\n const ext = (globalThis as { EIMZOEXT?: CapiwsLike }).EIMZOEXT;\n return ext ? createCapiwsTransport(ext)(request) : ws(request);\n };\n}\n","import { bytesToBase64, utf8ToBase64 } from './base64';\nimport type { EimzoBackend } from './backend';\nimport { parseCertificateInfo, type EimzoKey, type PfxKey, type TokenKey } from './certificate';\nimport { EimzoError, errorFromResponse, isEimzoError } from './errors';\nimport { DEFAULT_LOCALE, formatEimzoError, type EimzoLocale, type MessageOverrides } from './i18n';\nimport { createDefaultTransport, type EimzoResponse, type Transport, type WebSocketTransportOptions } from './transport';\n\n/** Пары «домен → API-KEY» или плоский массив `[домен, ключ, домен, ключ, ...]`, как в демо. */\nexport type ApiKeys = Record<string, string> | string[];\n\n/** Аппаратные носители: подписывают без `load_key`, `id` передаётся в `create_pkcs7` напрямую. */\nexport type DeviceType = 'idcard' | 'baikey' | 'ckc';\n\nexport interface EimzoVersion {\n major: number;\n minor: number;\n}\n\nexport interface EimzoOptions<TLogin = unknown> extends WebSocketTransportOptions {\n /**\n * API-ключи доменов. Пусто — `apikey` не вызывается (E-IMZO v6 подбирает ключ по домену сам).\n * Для localhost используйте `DEV_API_KEYS`.\n */\n apiKeys?: ApiKeys;\n /** Минимальная версия E-IMZO, `\"major.minor\"`. По умолчанию `\"4.86\"`. */\n minVersion?: string;\n backend?: EimzoBackend<TLogin>;\n /** Своя реализация вызовов E-IMZO, например для тестов. */\n transport?: Transport;\n /**\n * Язык сообщений об ошибках: `'ru'` (по умолчанию), `'uz-Latn'`, `'uz-Cyrl'`, `'kaa'`, `'en'`\n * или свой код вместе с `messages`.\n */\n locale?: EimzoLocale;\n /**\n * Свои тексты: `{ ru: { WRONG_PASSWORD: () => '...' } }` заменяет одно сообщение,\n * `{ kk: { ... } }` добавляет язык. Недостающие сообщения берутся из русского.\n */\n messages?: MessageOverrides;\n /**\n * Если E-IMZO забыл `keyId` (24 часа, перезапуск E-IMZO), `sign()` сам загрузит\n * тот же ключ заново и повторит подпись. E-IMZO при этом снова спросит пароль.\n * По умолчанию `true`.\n */\n autoReloadKey?: boolean;\n}\n\nexport interface LoadKeyOptions {\n /**\n * Сразу спросить пароль/PIN (`verify_password` / `verify_pin`).\n * Внимание: `verify_password` не показывает флажок «Запомнить на 6 час.»\n * и сокращает уже запомненный пароль до 1 минуты.\n */\n verifyPassword?: boolean;\n}\n\nexport interface SignOptions {\n /** PKCS#7 без вложенных данных (detached). По умолчанию — с данными (attached). */\n detached?: boolean;\n /** Строка `data` уже в base64 (например, содержимое файла). */\n base64?: boolean;\n /** Подписать другим ключом, а не загруженным через `loadKey()`. */\n keyId?: string;\n}\n\nexport type SignableData = string | Uint8Array | ArrayBuffer;\n\nexport interface SignFileOptions {\n /** По умолчанию `true`: файл хранится у вас, класть его копию в подпись незачем. */\n detached?: boolean;\n /** Максимальный размер файла в байтах. По умолчанию 10 МБ. */\n maxSize?: number;\n /** Подписать другим ключом, а не загруженным через `loadKey()`. */\n keyId?: string;\n}\n\nexport const DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;\n\n/** Публичные ключи E-IMZO для локальной разработки (из официального примера). */\nexport const DEV_API_KEYS: Record<string, string> = {\n localhost:\n '96D0C1491615C82B9A54D9989779DF825B690748224C2B04F500F370D51827CE2644D8D4A82C18184D73AB8530BB8ED537269603F61DB0D03D2104ABF789970B',\n '127.0.0.1':\n 'A7BCFA5D490B351BE0754130DF03A068F855DB4333D43921125B9CF2670EF6A40370C646B90401955E1F7BC9CDBF59CE0B2C5467D820BE189C845D0B79CFC96F',\n};\n\nconst DEFAULT_MIN_VERSION = '4.86';\n// Пороги из e-imzo-client.js (NEW_API2 / NEW_API3).\nconst VERSION_PFX_ONLY = 412;\nconst VERSION_BAIK_CKC = 486;\n\nconst versionNumber = (v: EimzoVersion) => v.major * 100 + v.minor;\n\nfunction parseVersion(value: string): EimzoVersion {\n const [major, minor] = value.split('.').map((part) => parseInt(part, 10));\n if (isNaN(major) || isNaN(minor)) throw new Error(`Invalid E-IMZO version: \"${value}\"`);\n return { major, minor };\n}\n\nfunction flattenApiKeys(keys: ApiKeys | undefined): string[] {\n if (!keys) return [];\n if (Array.isArray(keys)) return keys;\n return Object.keys(keys).reduce<string[]>((acc, domain) => acc.concat(domain, keys[domain]), []);\n}\n\nfunction toBase64(data: SignableData, alreadyBase64: boolean): string {\n if (typeof data === 'string') return alreadyBase64 ? data : utf8ToBase64(data);\n return bytesToBase64(data instanceof Uint8Array ? data : new Uint8Array(data));\n}\n\nexport class Eimzo<TLogin = unknown> {\n private readonly transport: Transport;\n private readonly minVersion: EimzoVersion;\n private ready: Promise<EimzoVersion> | null = null;\n private currentKeyId: string | null = null;\n /** Ключ, из которого получен `currentKeyId`, — чтобы загрузить его заново. */\n private currentKey: EimzoKey | DeviceType | null = null;\n private currentLocale: EimzoLocale;\n /** Хвост очереди операций, которые могут открыть окно пароля. */\n private queue: Promise<unknown> = Promise.resolve();\n\n constructor(private readonly options: EimzoOptions<TLogin> = {}) {\n this.transport = options.transport ?? createDefaultTransport(options);\n this.minVersion = parseVersion(options.minVersion ?? DEFAULT_MIN_VERSION);\n this.currentLocale = options.locale ?? DEFAULT_LOCALE;\n }\n\n /** `keyId` последнего `loadKey()`. Держите его, чтобы работало запоминание пароля на 6 часов. */\n get keyId(): string | null {\n return this.currentKeyId;\n }\n\n get locale(): EimzoLocale {\n return this.currentLocale;\n }\n\n /** Сменить язык. Влияет на `t()` и на `message` следующих ошибок. */\n setLocale(locale: EimzoLocale): void {\n this.currentLocale = locale;\n }\n\n /**\n * Текст ошибки на текущем (или указанном) языке. Используйте при показе, а не\n * `error.message`: так после смены языка старая ошибка тоже покажется на новом.\n */\n t(error: unknown, locale: EimzoLocale = this.currentLocale): string {\n return formatEimzoError(error, locale, this.options.messages);\n }\n\n /** Все публичные методы проходят через guard: `message` ошибки — на текущем языке. */\n private guard<T>(work: () => Promise<T>): Promise<T> {\n return work().catch((error: unknown) => {\n if (error instanceof EimzoError) error.message = this.t(error);\n throw error;\n });\n }\n\n /**\n * Операции, которые могут открыть окно пароля, выполняются строго по одной:\n * двойной клик по «Подписать» не откроет два окна, второй вызов дождётся первого.\n */\n private exclusive<T>(work: () => Promise<T>): Promise<T> {\n const run = this.queue.then(work, work);\n this.queue = run.catch(() => undefined);\n return this.guard(() => run);\n }\n\n /**\n * Проверяет версию и устанавливает API-ключи. Вызывается автоматически перед любой\n * операцией; результат кешируется, после ошибки следующий вызов пробует заново.\n */\n init(): Promise<EimzoVersion> {\n if (!this.ready) {\n this.ready = this.doInit().catch((error) => {\n this.ready = null;\n throw error;\n });\n }\n const ready = this.ready;\n return this.guard(() => ready);\n }\n\n private async doInit(): Promise<EimzoVersion> {\n const version = await this.readVersion();\n if (versionNumber(version) < versionNumber(this.minVersion)) {\n throw new EimzoError('OUTDATED_VERSION', {\n installed: `${version.major}.${version.minor}`,\n min: `${this.minVersion.major}.${this.minVersion.minor}`,\n });\n }\n const apiKeys = flattenApiKeys(this.options.apiKeys);\n if (apiKeys.length > 0) {\n const res = await this.transport({ name: 'apikey', arguments: apiKeys });\n if (!res.success) throw new EimzoError('API_KEY_REJECTED', {}, { reason: res.reason });\n }\n return version;\n }\n\n /** Версия установленного E-IMZO. Не требует API-ключа. */\n getVersion(): Promise<EimzoVersion> {\n return this.guard(() => this.readVersion());\n }\n\n private async readVersion(): Promise<EimzoVersion> {\n const res = await this.transport({ name: 'version' });\n if (!res.success) throw errorFromResponse(res);\n const major = parseInt(res.major, 10);\n const minor = parseInt(res.minor, 10);\n if (isNaN(major) || isNaN(minor)) throw new EimzoError('EIMZO_ERROR', { reason: 'version is undefined' });\n return { major, minor };\n }\n\n /** Прямой вызов функции плагина E-IMZO (см. http://127.0.0.1:64646/apidoc.html). */\n call(plugin: string, name: string, args: unknown[] = []): Promise<EimzoResponse> {\n return this.guard(() => this.invoke(plugin, name, args));\n }\n\n private async invoke(plugin: string, name: string, args: unknown[] = []): Promise<EimzoResponse> {\n await this.init();\n const res = await this.transport({ plugin, name, arguments: args });\n if (!res.success) throw errorFromResponse(res);\n return res;\n }\n\n /** PFX-ключи (и токены `ftjc` для E-IMZO старше 4.12). Ключи без ИНН и ПИНФЛ пропускаются. */\n listKeys(): Promise<EimzoKey[]> {\n return this.guard(async () => {\n const version = await this.init();\n const sources: Promise<EimzoKey[]>[] = [this.listPfx()];\n if (versionNumber(version) < VERSION_PFX_ONLY) sources.push(this.listTokens());\n\n const results = await Promise.allSettled(sources);\n const keys: EimzoKey[] = [];\n let firstError: unknown;\n for (const r of results) {\n if (r.status === 'fulfilled') keys.push(...r.value);\n else if (firstError === undefined) firstError = r.reason;\n }\n // Как в оригинале: ошибка, только если ничего не нашлось.\n if (keys.length === 0 && firstError !== undefined) throw firstError;\n return keys;\n });\n }\n\n private async listPfx(): Promise<PfxKey[]> {\n const res = await this.invoke('pfx', 'list_all_certificates');\n const now = new Date();\n const keys: PfxKey[] = [];\n for (const el of res.certificates ?? []) {\n const info = parseCertificateInfo(el.alias, now);\n if (info) keys.push({ ...info, type: 'pfx', disk: el.disk, path: el.path, name: el.name, alias: el.alias });\n }\n return keys;\n }\n\n private async listTokens(): Promise<TokenKey[]> {\n const res = await this.invoke('ftjc', 'list_all_keys', ['']);\n const now = new Date();\n const keys: TokenKey[] = [];\n for (const el of res.tokens ?? []) {\n const info = parseCertificateInfo(el.info, now);\n if (info) {\n keys.push({\n ...info,\n type: 'ftjc',\n cardUID: el.cardUID,\n statusInfo: el.statusInfo,\n ownerName: el.ownerName,\n info: el.info,\n });\n }\n }\n return keys;\n }\n\n /** Какие аппаратные носители подключены. Носители, которые версия E-IMZO не поддерживает, — `false`. */\n listDevices(): Promise<Record<DeviceType, boolean>> {\n return this.guard(async () => {\n const v = versionNumber(await this.init());\n const check = async (enabled: boolean, plugin: string, name: string, field: string) => {\n if (!enabled) return false;\n try {\n const res = await this.invoke(plugin, name);\n return Array.isArray(res[field]) && res[field].length > 0;\n } catch (error) {\n // Ошибка плагина = носителя нет; ошибки связи пробрасываем.\n if (error instanceof EimzoError && error.code === 'EIMZO_ERROR') return false;\n throw error;\n }\n };\n const [idcard, baikey, ckc] = await Promise.all([\n check(v >= VERSION_PFX_ONLY, 'idcard', 'list_readers', 'readers'),\n check(v >= VERSION_BAIK_CKC, 'baikey', 'list_tokens', 'tokens'),\n check(v >= VERSION_BAIK_CKC, 'ckc', 'list_ckc', 'devices'),\n ]);\n return { idcard, baikey, ckc };\n });\n }\n\n /**\n * Загружает ключ и запоминает его `keyId` для `sign()`.\n * Для аппаратного носителя (`'idcard' | 'baikey' | 'ckc'`) E-IMZO не вызывается.\n * Каждый вызов для PFX создаёт новую сессию, и E-IMZO снова спросит пароль.\n * Предыдущий загруженный PFX-ключ выгружается из E-IMZO.\n */\n loadKey(key: EimzoKey | DeviceType, options: LoadKeyOptions = {}): Promise<string> {\n return this.exclusive(() => this.doLoadKey(key, options));\n }\n\n private async doLoadKey(key: EimzoKey | DeviceType, options: LoadKeyOptions): Promise<string> {\n await this.releaseCurrentKey();\n let keyId: string;\n if (typeof key === 'string') {\n keyId = key;\n } else if (key.type === 'pfx') {\n keyId = (await this.invoke('pfx', 'load_key', [key.disk, key.path, key.name, key.alias])).keyId;\n if (options.verifyPassword) await this.invoke('pfx', 'verify_password', [keyId]);\n } else {\n keyId = (await this.invoke('ftjc', 'load_key', [key.cardUID])).keyId;\n if (options.verifyPassword) await this.invoke('ftjc', 'verify_pin', [keyId, '1']);\n }\n this.currentKey = key;\n this.currentKeyId = keyId;\n return keyId;\n }\n\n /**\n * Выгрузить ключ из E-IMZO и забыть его. Вызывайте при выходе пользователя:\n * иначе пароль, запомненный на 6 часов, останется в E-IMZO на этом компьютере.\n */\n unloadKey(): Promise<void> {\n return this.exclusive(() => this.releaseCurrentKey());\n }\n\n private async releaseCurrentKey(): Promise<void> {\n const key = this.currentKey;\n const keyId = this.currentKeyId;\n this.currentKey = null;\n this.currentKeyId = null;\n if (!keyId || !key || typeof key === 'string' || key.type !== 'pfx') return;\n try {\n await this.invoke('pfx', 'unload_key', [keyId]);\n } catch (error) {\n // Уже выгружен или E-IMZO перезапущен — цель достигнута.\n if (!isEimzoError(error, 'KEY_NOT_FOUND')) throw error;\n }\n }\n\n /** Создаёт PKCS#7 (base64). Пароль спрашивает окно E-IMZO, сайт его не видит. */\n sign(data: SignableData, options: SignOptions = {}): Promise<string> {\n return this.exclusive(() => this.doSign(data, options));\n }\n\n /**\n * Подписывает файл (`File` из `<input type=\"file\">` или `Blob`). По умолчанию detached.\n * Метку времени добавьте отдельно: `signDocument(await file.arrayBuffer(), { detached: true })`.\n */\n signFile(file: Blob, options: SignFileOptions = {}): Promise<string> {\n return this.exclusive(async () => {\n const max = options.maxSize ?? DEFAULT_MAX_FILE_SIZE;\n if (file.size > max) throw new EimzoError('FILE_TOO_LARGE', { size: file.size, max });\n const bytes = new Uint8Array(await file.arrayBuffer());\n return this.doSign(bytes, { detached: options.detached ?? true, keyId: options.keyId });\n });\n }\n\n private async doSign(data: SignableData, options: SignOptions): Promise<string> {\n const keyId = options.keyId ?? this.currentKeyId;\n if (!keyId) throw new EimzoError('KEY_NOT_LOADED');\n const data64 = toBase64(data, options.base64 === true);\n const create = (id: string) =>\n this.invoke('pkcs7', 'create_pkcs7', [data64, id, options.detached ? 'yes' : 'no']).then((res) => res.pkcs7_64);\n try {\n return await create(keyId);\n } catch (error) {\n // E-IMZO забыл keyId (24 часа или перезапуск): загружаем тот же ключ и пробуем ещё раз.\n const key = this.currentKey;\n const canReload =\n this.options.autoReloadKey !== false &&\n options.keyId === undefined &&\n isEimzoError(error, 'KEY_NOT_FOUND') &&\n key !== null &&\n typeof key !== 'string';\n if (!canReload) throw error;\n this.currentKeyId = null; // старый keyId уже недействителен, выгружать нечего\n return create(await this.doLoadKey(key, {}));\n }\n }\n\n /**\n * Вход по ЭЦП: challenge с backend → `loadKey` → подпись challenge → `backend.login`.\n * Возвращает то, что вернул `backend.login` (сессия, JWT и т.п.).\n */\n login(key: EimzoKey | DeviceType): Promise<TLogin> {\n return this.exclusive(async () => {\n const backend = this.requireBackend('getChallenge', 'login');\n const challenge = await backend.getChallenge!();\n await this.doLoadKey(key, {});\n const pkcs7 = await this.doSign(challenge, {});\n return backend.login!(pkcs7);\n });\n }\n\n /** Подпись документа загруженным ключом + метка времени через backend. */\n signDocument(data: SignableData, options: SignOptions = {}): Promise<string> {\n return this.exclusive(async () => {\n const backend = this.requireBackend('timestamp');\n const pkcs7 = await this.doSign(data, options);\n return backend.timestamp!(pkcs7);\n });\n }\n\n private requireBackend(...methods: (keyof EimzoBackend)[]): EimzoBackend<TLogin> {\n const backend = this.options.backend;\n const missing = methods.filter((m) => typeof backend?.[m] !== 'function');\n if (!backend || missing.length > 0) {\n throw new EimzoError('BACKEND_NOT_CONFIGURED', { methods: missing.join(', ') });\n }\n return backend;\n }\n}\n\nexport function createEimzo<TLogin = unknown>(options: EimzoOptions<TLogin> = {}): Eimzo<TLogin> {\n return new Eimzo<TLogin>(options);\n}\n","import { EimzoError } from './errors';\n\n/**\n * Связь с вашим backend. Библиотека не знает ваших адресов и формата ответа,\n * поэтому каждый шаг задаётся функцией. Нужны только те методы, которые вы вызываете:\n * `login()` требует `getChallenge` и `login`, `signDocument()` — `timestamp`.\n */\nexport interface EimzoBackend<TLogin = unknown> {\n /** Одноразовый challenge от e-imzo-server (`/frontend/challenge`). */\n getChallenge?(): Promise<string>;\n /** Отправить PKCS#7 с подписанным challenge; backend проверяет его через `/backend/auth`. */\n login?(pkcs7: string): Promise<TLogin>;\n /** Прикрепить метку времени (`/frontend/timestamp/pkcs7`); вернуть PKCS#7 с меткой. */\n timestamp?(pkcs7: string): Promise<string>;\n}\n\nexport interface FetchBackendOptions {\n /** GET, ответ `{ challenge, status }`. */\n challengeUrl?: string;\n /** POST, тело — PKCS#7 в base64 (text/plain). Ответ возвращается из `login()` как есть. */\n loginUrl?: string;\n /** POST, тело — PKCS#7 в base64 (text/plain). Ответ `{ pkcs7b64, status }`. */\n timestampUrl?: string;\n /** Общие параметры запросов: заголовки (CSRF, Authorization), `credentials` и т.п. */\n init?: RequestInit;\n fetch?: typeof fetch;\n}\n\n/**\n * Backend на `fetch`. Форматы ответов совпадают с e-imzo-server, поэтому backend\n * может просто проксировать `/frontend/challenge` и `/frontend/timestamp/pkcs7`.\n */\nexport function createFetchBackend<TLogin = unknown>(options: FetchBackendOptions): EimzoBackend<TLogin> {\n const doFetch = options.fetch ?? ((input: RequestInfo | URL, init?: RequestInit) => fetch(input, init));\n const base = options.init ?? {};\n\n const request = async (url: string, init: RequestInit): Promise<any> => {\n const response = await doFetch(url, {\n ...base,\n ...init,\n headers: { ...headersToObject(base.headers), ...headersToObject(init.headers) },\n });\n const text = await response.text();\n let body: any = text;\n try {\n body = text ? JSON.parse(text) : null;\n } catch {\n // не JSON — вернём текст\n }\n if (!response.ok) {\n const detail = body && typeof body === 'object' && body.message ? String(body.message) : undefined;\n throw new EimzoError('BACKEND_ERROR', { status: response.status, detail }, { httpStatus: response.status });\n }\n if (body && typeof body === 'object' && 'status' in body && body.status !== 1) {\n const detail = body.message ? String(body.message) : `status ${body.status}`;\n throw new EimzoError('BACKEND_ERROR', { status: response.status, detail }, { httpStatus: response.status });\n }\n return body;\n };\n\n const postPkcs7 = (url: string, pkcs7: string) =>\n request(url, { method: 'POST', body: pkcs7, headers: { 'Content-Type': 'text/plain' } });\n\n const backend: EimzoBackend<TLogin> = {};\n if (options.challengeUrl) {\n const url = options.challengeUrl;\n backend.getChallenge = async () => {\n const body = await request(url, { method: 'GET', cache: 'no-store' });\n if (!body || typeof body.challenge !== 'string') {\n throw new EimzoError('BACKEND_ERROR', { detail: 'no \"challenge\" field in response' });\n }\n return body.challenge;\n };\n }\n if (options.loginUrl) {\n const url = options.loginUrl;\n backend.login = (pkcs7) => postPkcs7(url, pkcs7);\n }\n if (options.timestampUrl) {\n const url = options.timestampUrl;\n backend.timestamp = async (pkcs7) => {\n const body = await postPkcs7(url, pkcs7);\n if (!body || typeof body.pkcs7b64 !== 'string') {\n throw new EimzoError('BACKEND_ERROR', { detail: 'no \"pkcs7b64\" field in response' });\n }\n return body.pkcs7b64;\n };\n }\n return backend;\n}\n\nfunction headersToObject(headers: HeadersInit | undefined): Record<string, string> {\n if (!headers) return {};\n if (typeof Headers !== 'undefined' && headers instanceof Headers) {\n const result: Record<string, string> = {};\n headers.forEach((value, key) => (result[key] = value));\n return result;\n }\n if (Array.isArray(headers)) return Object.fromEntries(headers);\n return headers as Record<string, string>;\n}\n"],"mappings":"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","names":["DOWNLOAD_URL","DOWNLOAD_URL","DOWNLOAD_URL","DOWNLOAD_URL"]}
@@ -152,10 +152,11 @@ var EimzoClient = (() => {
152
152
  }
153
153
  var STATUS_KEY_NOT_FOUND = [-1010, -1014];
154
154
  var STATUS_CANCELLED = [-5e3];
155
+ var WRONG_PASSWORD_REASONS = /BadPaddingException|Sequence tag error|getSecretKey failed/;
155
156
  function errorFromResponse(res) {
156
157
  const { status, reason } = res;
157
158
  const details = { reason, status };
158
- if (reason && reason.indexOf("BadPaddingException") !== -1) return new EimzoError("WRONG_PASSWORD", {}, details);
159
+ if (reason && WRONG_PASSWORD_REASONS.test(reason)) return new EimzoError("WRONG_PASSWORD", {}, details);
159
160
  if (status !== void 0 && STATUS_KEY_NOT_FOUND.indexOf(status) !== -1) {
160
161
  return new EimzoError("KEY_NOT_FOUND", {}, details);
161
162
  }