eimzo-client
v0.2.0
Published
Modern, typed, framework-agnostic E-IMZO (O'zbekiston ERI) client for the web. Vue 3 + React adapters, inline WebSocket transport, mobile detection.
Maintainers
Readme
eimzo-client
Zamonaviy, TypeScript bilan to'liq typed, framework-agnostik E-IMZO (O'zbekiston ERI) klienti — web ilovalar uchun. Vue 3, React, Angular va Nuxt 3 adapterlari ham ichida.
npm install eimzo-clientimport { createEimzo } from 'eimzo-client'
const eimzo = createEimzo()
await eimzo.install() // 1. E-IMZO'ga ulanish
const certs = await eimzo.listKeys() // 2. Sertifikatlar ro'yxati
const { pkcs7 } = await eimzo.sign(certs[0], 'Imzolanadigan matn') // 3. ImzolashAsosiy imkoniyatlar
- ✅ 100% mustaqil — tashqi
e-imzo.jsskript yuklanmaydi (ichki WebSocket transport) - ✅ Promise-asosli API (callback-hell yo'q), to'liq TypeScript typed
- ✅ E-IMZO v5 va v6 bilan mos (v6 da API-key avtomatik)
- ✅ PFX sertifikatlar + ID-card / BAIK / CKC qurilmalari
- ✅ PKCS#7 imzolash + Timestamp (TST) ulash + katta fayllar uchun SHA-256 hash imzolash
- ✅ Mobil ID-card QR / deeplink (
eimzo-client/mobile-idcard) - ✅ Vue 3 plugin + composable, React Provider + hook, Angular Signal'lar, Nuxt module
- ✅ ESM + CJS, tree-shake mos, 32 MB hujjatgacha imzolash (v6 limiti)
- ✅ Xavfsizlik: SRI, prototype-pollution himoyasi,
AbortSignalbilan bekor qilish
Mundarija
- E-IMZO qanday ishlaydi? — avval shu yerni o'qing
- O'rnatish va talablar
- Tezkor boshlash (vanilla)
- Hayotiy sikl: 4 qadam
- Framework adapterlari — Vue / Nuxt / React / Angular
- Imzolash holatlari
- Qurilma orqali kirish (ID-card / BAIK / CKC)
- Mobil ID-card (QR + deeplink)
- Timestamp (TST) qo'shish
- Transport rejimi
- API ma'lumotnomasi
- Xavfsizlik
- E-IMZO v6 yangiliklari
E-IMZO qanday ishlaydi?
E-IMZO — foydalanuvchi kompyuteriga o'rnatiladigan ERI (elektron raqamli imzo) dasturi.
U fonda localhost'da WebSocket server sifatida ishlaydi (wss://127.0.0.1:64443).
Brauzer shu serverga ulanib, kalitlar ro'yxatini oladi va imzolash buyruqlarini yuboradi.
eimzo-client — aynan shu WebSocket aloqasining toza, tipli o'ramidir. Maxsus tashqi
skript yuklamaydi (ichki transport).
Tipik oqim har doim 2 tomonda ketadi — frontend imzolaydi, backend tekshiradi:
┌──────────┐ 1. install / listKeys / sign ┌─────────────────┐
│ Brauzer │ ───────────────────────────────► │ E-IMZO daemon │
│ (sizning │ ◄─────────────────────────────── │ (localhost WS) │
│ sayt) │ PKCS#7 imzo └─────────────────┘
└────┬─────┘
│ 2. PKCS#7 ni backendga yuborasiz
▼
┌──────────┐ imzoni tekshirish (e-imzo-server)
│ Backend │ ──────────────────────────────────► vpn.e-imzo.uz
└──────────┘⚠️ Muhim: bu paket faqat frontend qismini bajaradi (imzo hosil qilish). Imzo haqiqiyligini, sertifikat statusini va challenge mosligini backend tekshirishi shart (
e-imzo-server). Qarang: Xavfsizlik.
Uchta ishchi muhit bor:
| Muhit | Nima ishlatiladi | Qanday | |---|---|---| | Desktop | PFX sertifikatlar | localhost WebSocket orqali to'g'ridan-to'g'ri | | Desktop qurilma | ID-card / BAIK / CKC | xuddi shu, daemon PIN'ni o'zi so'raydi | | Mobil | E-IMZO ID-CARD ilovasi | QR / deeplink + backend polling (pastga) |
O'rnatish va talablar
npm install eimzo-client
# yoki
pnpm add eimzo-client
# yoki
yarn add eimzo-clientTalab: foydalanuvchi kompyuterida E-IMZO dasturi o'rnatilgan va
ishga tushirilgan bo'lishi kerak. Aks holda install() EimzoNotInstalledError tashlaydi.
Tezkor boshlash (vanilla)
import { createEimzo } from 'eimzo-client'
const eimzo = createEimzo({
// v5 uchun API-key'lar (v6 da kerak emas — E-IMZO o'zi o'rnatadi):
apiKeys: {
'localhost': '96D0C1491615C82B...',
'mysite.uz': 'C691454C3DBAC565...',
},
})
await eimzo.install() // skript/version/apikey
const certs = await eimzo.listKeys() // PFX sertifikatlari
const result = await eimzo.sign(certs[0], 'Imzolanadigan matn')
console.log(result.pkcs7) // base64 PKCS#7v6:
apiKeysopsiyasi e'tiborga olinmaydi — E-IMZO domenni o'zi avtomatik aniqlaydi.
Hayotiy sikl: 4 qadam
Deyarli har bir oqim shu to'rt qadamdan iborat. Tartibni saqlash muhim.
// 1. ULANISH — E-IMZO'ni topadi, versiyani aniqlaydi, API-key o'rnatadi
await eimzo.install()
// 2. RO'YXAT — mavjud PFX sertifikatlarni oladi (rol flag'lari avtomatik qo'shiladi)
const certs = await eimzo.listKeys()
// 3. TANLASH — foydalanuvchi UI'dan bittasini tanlaydi
const cert = certs[0]
// 4a. KIRISH (auth) — backend bergan challenge'ni imzolaydi
const challenge = await fetch('/api/auth/challenge').then(r => r.text())
const pkcs7 = await eimzo.authenticate(challenge, cert)
await fetch('/api/auth/login', { method: 'POST', body: pkcs7 })
// 4b. yoki HUJJAT IMZOLASH
const { pkcs7: signed } = await eimzo.sign(cert, JSON.stringify({ orderId: 12345 }))authenticate()— kirish (login) uchun: backend tasodifiychallengeberadi, foydalanuvchi uni imzolaydi, backend imzoni tekshirib sessiya ochadi.sign()— hujjat imzolash uchun: natija backendda arxivlanadi / tekshiriladi.
Framework adapterlari
Core API (createEimzo()) har bir metodga sertifikatni argument sifatida beradi.
Adapter'larda esa (useEimzo() / EimzoService) sertifikat ichki state'da saqlanadi —
qarang: Adapter API qoidalari.
Vue 3
// main.ts
import { createApp } from 'vue'
import { EimzoVuePlugin } from 'eimzo-client/vue'
import App from './App.vue'
createApp(App)
.use(EimzoVuePlugin, { apiKeys: { 'localhost': '96D0C1491615C82B...' } })
.mount('#app')<!-- KeySelector.vue -->
<script setup lang="ts">
import { onMounted } from 'vue'
import { useEimzo } from 'eimzo-client/vue'
const { certificates, selected, loading, error, loadCertificates, select, sign } = useEimzo()
onMounted(loadCertificates)
async function onSign() {
const result = await sign('Hujjat matni')
console.log(result.pkcs7)
}
</script>
<template>
<div v-if="loading">Yuklanmoqda...</div>
<div v-else-if="error">{{ error.message }}</div>
<ul>
<li v-for="c in certificates" :key="c.serialNumber" @click="select(c)">
{{ c.CN }} ({{ c.TIN || c.PINFL }})
</li>
</ul>
<button :disabled="!selected" @click="onSign">Imzolash</button>
</template>Nuxt 3
Module sifatida ulang — useEimzo() avto-import bo'ladi:
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['eimzo-client/nuxt'],
eimzo: {
apiKeys: { 'mysite.uz': process.env.NUXT_PUBLIC_EIMZO_KEY ?? '' },
transport: 'inline', // 'inline' (default) | 'external'
onMobile: 'throw', // 'throw' (default) | 'warn' | 'ignore'
},
})<!-- pages/sign.vue -->
<script setup lang="ts">
const { certificates, selected, error, install, loadCertificates, select, sign } = useEimzo()
onMounted(async () => {
await install()
await loadCertificates()
})
async function onSign() {
if (!selected.value) return
const result = await sign('Imzolanadigan matn')
await $fetch('/api/sign', { method: 'POST', body: { pkcs7: result.pkcs7 } })
}
</script>SSR: plugin faqat brauzerda ishlaydi (E-IMZO daemon localhost'da bo'lgani uchun).
install()va boshqa metodlarnionMounted()ichida (yoki<client-only>blokida) chaqiring.
React
// main.tsx
import { EimzoProvider } from 'eimzo-client/react'
ReactDOM.createRoot(root).render(
<EimzoProvider options={{ apiKeys: { 'localhost': '96D0C1...' } }} autoInstall>
<App />
</EimzoProvider>
)// KeySelector.tsx
import { useEffect } from 'react'
import { useEimzo } from 'eimzo-client/react'
export function KeySelector() {
const { certificates, selected, loading, error, loadCertificates, select, sign } = useEimzo()
useEffect(() => { loadCertificates() }, [loadCertificates])
if (loading) return <div>Yuklanmoqda...</div>
if (error) return <div>{error.message}</div>
return (
<>
<ul>
{certificates.map(c => (
<li key={c.serialNumber} onClick={() => select(c)}>
{c.CN} ({c.TIN || c.PINFL})
</li>
))}
</ul>
<button disabled={!selected} onClick={() => sign('Hujjat matni')}>Imzolash</button>
</>
)
}Angular (≥16)
Standalone API + Signal'lar bilan. provideEimzo() orqali sozlanadi:
// app.config.ts
import { provideEimzo } from 'eimzo-client/angular'
export const appConfig = {
providers: [provideEimzo({ apiKeys: { 'mysite.uz': '...' } })],
}// key-selector.component.ts
import { Component, inject, OnInit } from '@angular/core'
import { EimzoService } from 'eimzo-client/angular'
@Component({ standalone: true, selector: 'app-key-selector', template: `...` })
export class KeySelectorComponent implements OnInit {
readonly eimzo = inject(EimzoService)
async ngOnInit() {
await this.eimzo.install()
await this.eimzo.loadCertificates()
}
async onSign() {
const result = await this.eimzo.sign('Hujjat matni')
console.log(result.pkcs7)
}
}EimzoService reaktiv field'lari (Signal):
certificates(), selected(), loading(), error(), version().
Tayyor EimzoClient'ni ham berish mumkin (test / shared client uchun):
import { provideEimzoClient } from 'eimzo-client/angular'
import { createEimzo } from 'eimzo-client'
providers: [provideEimzoClient(createEimzo({ apiKeys: { /* ... */ } }))]Adapter API qoidalari
Adapter'larda imzolash metodlaridan oldin selected'ga sertifikat qo'yilishi shart,
aks holda Error("Sertifikat tanlanmagan") qaytariladi.
Sertifikat tanlash:
// Vue — uch ekvivalent yo'l:
select(cert) // 1. select() metodi
selected.value = cert // 2. ref'ga to'g'ridan-to'g'ri
// 3. template'da: <select v-model="selected">
// React / Angular — faqat select():
select(cert)Qaysi metod selected talab qiladi:
| Metod | selected kerakmi? | Sabab |
|---|:-:|---|
| install() / loadCertificates() / select() | ❌ | Sertifikatsiz ishlaydi |
| sign(data, opts?) | ✅ | selected'dan oladi |
| signHash(file, opts?) | ✅ | selected'dan oladi |
| authenticate(challenge) | ✅ | selected'dan oladi |
| signWithSerial(serial, data) | ❌ | Serial bo'yicha topadi |
// To'g'ri tartib:
await install() // 1
const certs = await loadCertificates() // 2
select(certs[0]) // 3 ⚠️ MAJBURIY — o'tkazib yuborilsa, authenticate xato beradi
const pkcs7 = await authenticate(challenge) // 4💡 Sertifikatni state'da saqlamasdan ishlash uchun core API'ni (
createEimzo()) ishlating.
Imzolash holatlari
Misollar core API uchun. Adapter'larda cert'ni argument sifatida bermaysiz —
selected'dan olinadi.
sign() qabul qiladigan turlar:
type BinaryInput = string | ArrayBuffer | ArrayBufferView | Blob1. Auth challenge (matn):
const challenge = await fetch('/api/auth/challenge').then(r => r.text())
const pkcs7 = await eimzo.authenticate(challenge, cert)2. JSON hujjat:
const result = await eimzo.sign(cert, JSON.stringify({ orderId: 12345, amount: 1_000_000 }))3. PDF/DOC fayl (Blob/File):
const file = inputElement.files[0]
const result = await eimzo.sign(cert, file)4. Katta fayl — SHA-256 hash imzolash (10+ MB uchun tavsiya etiladi):
const { pkcs7, hash } = await eimzo.signHash(cert, file) // avto SHA-256 + detached PKCS#7
await fetch('/api/sign', {
method: 'POST',
body: JSON.stringify({ pkcs7, hashHex: bytesToHex(hash) }),
})5. Binary baytlar:
const result = await eimzo.sign(cert, new Uint8Array([0x01, 0x02, 0x03]))6. Allaqachon base64 satr:
const result = await eimzo.sign(cert, alreadyBase64, { isBase64: true })7. Detached imzo (asl hujjatsiz):
const result = await eimzo.sign(cert, file, { detached: true }) // PKCS#7 ichida fayl yo'qQurilma orqali kirish (ID-card / BAIK / CKC)
Bu uchta qurilma sertifikat ro'yxatiga kirmaydi (listKeys() ularni qaytarmaydi) —
alohida tugma orqali ishlatiladi. PIN'ni E-IMZO daemon o'zi so'raydi (JS tomondan
load_key/verify_pin chaqirilmaydi).
if (await eimzo.isBaikConnected()) {
const challenge = await fetch('/api/challenge').then(r => r.text())
const pkcs7 = await eimzo.authenticateWithBaik(challenge)
await fetch('/api/login', { method: 'POST', body: pkcs7 })
}| Metod | Tavsif |
|---|---|
| isIdCardConnected() / isBaikConnected() / isCkcConnected() | Qurilma ulanganmi? |
| signWithIdCard(data, opts?) / signWithBaik(...) / signWithCkc(...) | Imzolash |
| authenticateWithIdCard(challenge) / authenticateWithBaik(...) / authenticateWithCkc(...) | Challenge imzolash |
| signWithDevice(device, data, opts?) | Umumiy variant (device: 'idcard'/'baikey'/'ckc') |
Versiya talabi: ID-card uchun E-IMZO 4.12+, BAIK/CKC uchun 4.86+. Eski versiyada
EimzoVersionErrortashlanadi.
Mobil ID-card (QR + deeplink)
E-IMZO desktop dasturi telefonda yo'q — uning o'rniga E-IMZO ID-CARD mobile ilovasi ishlatiladi. U butunlay boshqa, REST-API asosidagi oqim (qo0p/e-imzo-doc, 3-bo'lim):
- Backend
POST /frontend/mobile/auth→{ siteId, documentId, challange } - Frontend
challange'dan GOST hash + CRC32 hisoblabqcquradi:- web (desktop) —
qcQR rasm bo'lib chiziladi, foydalanuvchi telefon bilan skanlaydi - same-device (mobil brauzer) —
eimzo://...deeplink ochiladi
- web (desktop) —
POST /frontend/mobile/status(documentId=…) nistatus:1bo'lguncha poll qilamiz- Backend
GET /backend/mobile/authenticate/{documentId}orqali tasdiqlaydi
QR/deeplink quruvchi alohida, tree-shake'lanadigan subpath'da: eimzo-client/mobile-idcard
(GOST jadvallari faqat shuni import qilgan bundle'ga kiradi).
⚠️ GOST hash'ni frontend hisoblaydi — bu rasmiy protokol talabi, backend tayyor
qcqaytarmaydi. Bu modul rasmiye-imzo-mobile.jsning toza TS ekvivalenti (7/7 GOST test-vektori + real skanlangan QR bilan tasdiqlangan), shuning uchun tashqi skript yuklash shart emas.
import { buildIdCardMobileQr } from 'eimzo-client/mobile-idcard'
import { pollMobileResult, isMobilePlatform } from 'eimzo-client'
import QRCode from 'qrcode'
// 1. Backend auth sessiyasini yaratadi
const auth = await fetch('/frontend/mobile/auth', { method: 'POST' }).then(r => r.json())
// { siteId, documentId, challange }
// 2. qc / deeplink / hash quramiz
const { qc, deeplink, hash } = buildIdCardMobileQr(auth)
if (isMobilePlatform()) {
window.location.href = deeplink // same-device: ilovani ochamiz
} else {
const dataUrl = await QRCode.toDataURL(qc) // desktop: QR chizamiz (boshqa telefon skanlaydi)
}
// `hash` — QR yonida ko'rsatiladigan "hesh-kod"; foydalanuvchi ilovadagi bilan solishtiradi
// 3. status:1 bo'lguncha poll qilamiz
await pollMobileResult(
async () => {
const r = await fetch('/frontend/mobile/status', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `documentId=${encodeURIComponent(auth.documentId)}`,
}).then(r => r.json())
return r.status === 1 ? { ready: true, data: r } : { ready: false }
},
{ intervalMs: 2000, timeoutMs: 5 * 60 * 1000 },
)
// 4. Backend tasdiqlaydi:
// GET /backend/mobile/authenticate/{documentId} → { status:1, subjectCertificateInfo }eimzo-client/mobile-idcard eksportlari:
| Funksiya | Tavsif |
|---|---|
| buildIdCardMobileQr({ siteId, documentId, challange }) | { qc, deeplink, hash } quradi |
| gostHash(text) | GOST R 34.11-94 hash (ASCII matn — login/auth uchun) |
| gostHashHex(hex) | GOST hash (hex input — hujjat imzolash uchun) |
| crc32Hex(hex) | CRC32, 8 belgi lowercase hex |
Platformani aniqlash:
getPlatform()→'ios' | 'android' | 'desktop' | 'unknown',isMobilePlatform()→boolean. Default'dainstall()mobil brauzerdaEimzoMobileUnsupportedErrortashlaydi (onMobile: 'throw').
Timestamp (TST) qo'shish
Imzoga ishonchli vaqt belgisi ulash uchun timestamp callback bering:
const result = await eimzo.sign(cert, data, {
async timestamp(signatureHex) {
return fetch('/api/timestamp', { method: 'POST', body: signatureHex }).then(r => r.text())
},
})Transport rejimi
Default — inline: paket o'zining WebSocket transportini ishlatadi, tashqi skript yuklamaydi.
const eimzo = createEimzo({ transport: 'inline' }) // DEFAULTEski window.CAPIWS skriptiga tayanish (legacy):
const eimzo = createEimzo({
transport: 'external',
scriptUrl: 'https://e-imzo.uz/e-imzo-cm/e-imzo.js',
scriptIntegrity: 'sha384-...', // SRI tavsiya etiladi
})| Xususiyat | inline (default) | external |
|---|---|---|
| Tashqi skript yuklash | ❌ Yo'q | ✅ e-imzo.uz dan ≈50KB |
| Supply-chain xavfi | ✅ Yo'q | ⚠️ CDN xavfi (SRI bilan kamayadi) |
| CSP script-src | Faqat 'self' | 'self' https://e-imzo.uz |
| WebSocket bekor qilish (AbortSignal) | ✅ Bor | ❌ Yo'q |
| Birinchi imzo tezligi | ⚡ Tezroq | Skript yuklash kutiladi |
| Offline (intranet) | ✅ Ishlaydi | ❌ e-imzo.uz kerak |
Tavsiya: production'da
inline'da qoldiring.externalfaqat eski integratsiyalar uchun.
API ma'lumotnomasi
createEimzo(options): EimzoClient
| Opsiya | Tip | Default | Tavsif |
|---|---|---|---|
| apiKeys | Record<string, string> | — | domen → key (faqat v5; v6 da e'tiborsiz) |
| transport | 'inline' \| 'external' | 'inline' | Transport rejimi |
| capiwsUrl | string | wss://127.0.0.1:64443/... | Inline mode WebSocket URL |
| scriptUrl | string | e-imzo.uz CDN | External mode skript URL |
| skipScriptLoad | boolean | false | Skript allaqachon mavjud bo'lsa |
| scriptIntegrity | string | — | External mode SRI hash |
| timeoutMs | number | 0 (timeout yo'q) | Har bir CAPIWS chaqiruv timeout'i |
| maxDataBytes | number | 32 MB | Imzolanadigan ma'lumot maks hajmi |
| onMobile | 'throw' \| 'warn' \| 'ignore' | 'throw' | Mobil brauzerda install() xatti-harakati |
timeoutMsdefault0— chunkiload_key/create_pkcs7foydalanuvchidan parol kutadi. Programmatik chaqiruvlar uchun> 0bering.
EimzoClient metodlari
| Metod | Tavsif |
|---|---|
| install() | Ulanish: version aniqlash + apikey o'rnatish (external'da skript ham) |
| listKeys() | PFX sertifikatlar ro'yxati (rol flag'lari bilan) |
| loadKey(cert, { verify }) | Kalitni yuklash, ixtiyoriy parol/PIN tekshiruvi |
| sign(cert, data, opts?) | PKCS#7 imzolash |
| signWithSerial(serial, data, opts?) | Serial bo'yicha topib imzolash |
| signHash(cert, file, opts?) | SHA-256 hash + detached PKCS#7 |
| authenticate(challenge, cert) | Auth challenge'ni imzolash |
| getCertificateChain(handle) | x509 sertifikat zanjiri |
| isIdCardConnected() / isBaikConnected() / isCkcConnected() | Qurilma ulanganmi |
| signWithDevice(device, data, opts?) | Qurilma orqali imzolash (umumiy) |
| signWithIdCard(...) / signWithBaik(...) / signWithCkc(...) | Qurilma orqali imzolash (qisqartma) |
| authenticateWithIdCard(...) / authenticateWithBaik(...) / authenticateWithCkc(...) | Challenge imzolash |
| version | Versiya ma'lumoti (install() dan keyin) |
Sertifikat yordamchilari
Har bir Certificate listKeys() paytida avtomatik rol flag'lari bilan boyitiladi:
const cert = (await eimzo.listKeys())[0]
cert.isLegalEntity // yuridik shaxsmi?
cert.isPhysicalPerson // jismoniy shaxs (YATT ham kiradi)?
cert.isYATT // yakka tartibdagi tadbirkor?Free-funksiyalar (Pick'lar bilan ham ishlaydi):
import {
isLegalEntity, isPhysicalPerson, isYATT,
getCertificateRole, getCertificateRoleLabel, getCertificateStatus,
} from 'eimzo-client'
getCertificateRole(cert) // 'legal' | 'yatt' | 'physical'
getCertificateRoleLabel(cert) // "Yuridik shaxs" | "Yakka tartibdagi tadbirkor" | "Jismoniy shaxs"
getCertificateRoleLabel(cert, 'en') // inglizcha variant
getCertificateStatus(cert) // { status: 'active'|'expiring'|'expired'|'pending', daysLeft }Encoding yordamchilari
import {
encodeBase64, encodeBase64Async, decodeBase64, decodeBase64Text,
bytesToHex, hexToBytes, sha256, sha256Hex, sha256Base64, byteLength,
} from 'eimzo-client'
encodeBase64('Salom dunyo') // UTF-8 → base64
await encodeBase64Async(file) // Blob/File → base64
decodeBase64Text('SGVsbG8=') // base64 → string
await sha256Hex(file) // SHA-256 hex
bytesToHex(new Uint8Array([0xab, 0xcd])) // 'abcd'Native fast path:
Uint8Array.prototype.toBase64()mavjud bo'lgan brauzerlarda (Chrome 130+, Safari 18+) avtomatik undan foydalanadi; eski brauzerlarda chunkedbtoa(32 MB gacha stack overflow yo'q).
Xato turlari
Hammasi EimzoError'dan meros oladi va code xususiyatiga ega.
| Xato | Qachon |
|---|---|
| EimzoNotInstalledError | E-IMZO dasturi ishlamayapti |
| EimzoTransportError | WebSocket / tarmoq xatosi |
| EimzoVersionError | E-IMZO versiyasi mos kelmadi |
| EimzoApiKeyError | API-key noto'g'ri yoki yo'q |
| EimzoTimeoutError | Chaqiruv kutish vaqti tugadi |
| EimzoWrongPasswordError | Noto'g'ri PFX parol / token PIN |
| EimzoSignError | Imzolashda xatolik |
| EimzoKeyNotFoundError | Sertifikat topilmadi |
| EimzoDataTooLargeError | Ma'lumot maxDataBytes'dan oshdi |
| EimzoResponseTooLargeError | Daemon javobi juda katta |
| EimzoMobileUnsupportedError | Mobil brauzerda install() chaqirilgan |
import { EimzoError, EimzoNotInstalledError, EimzoWrongPasswordError } from 'eimzo-client'
try {
await eimzo.signWithBaik(data)
} catch (e) {
if (e instanceof EimzoNotInstalledError) alert('E-IMZO dasturini ishga tushiring')
else if (e instanceof EimzoWrongPasswordError) alert("Noto'g'ri PIN")
else if (e instanceof EimzoError) console.error(e.code, e.message)
}Xavfsizlik
E-IMZO bilan ishlashda frontend imzo hosil qiladi, lekin tekshirmaydi. Backend tomonida quyidagilar majburiy.
Auth (login) checklist
- ✅ Challenge tasodifiyligi — kamida 32 bayt CSPRNG (
crypto.randomBytes(32)) - ✅ TTL ≤ 5 daqiqa — challenge cache'da muddati cheklangan (masalan, Redis TTL)
- ✅ Bir martalik — verify'dan keyin challenge'ni darhol o'chiring
- ✅ Origin/audience binding — challenge ichida saytingiz host'i bo'lsin
- ✅ Sertifikat zanjiri — Root CA gacha tekshiring (E-IMZO PKI'siga ishonch)
- ✅ Sertifikat statusi —
validFrom <= now <= validTo, mumkin bo'lsa CRL/OCSP - ✅ PKCS#7 imzosi GOST/RSA bilan tekshirilgan va challenge baytlariga mos
Token saqlash
localStorage JWT uchun zaif (XSS'da o'g'irlanadi):
- 🟢 HttpOnly + Secure + SameSite=Strict cookie
- 🟡 Qisqa TTL (15–30 min) + refresh token rotation
- 🔴
localStorage— faqat development yoki token bo'lmagan narsa uchun
ID-card mobil oqim xavfsizligi
- ✅
documentId/challangeni backend yaratadi — frontend faqat GOST hash/CRC32 quradi.siteIdro'yxatdan o'tgan UPLOAD URL'ga bog'langan, shuning uchun PKCS#7 faqat sizning/frontend/mobile/uploadga keladi. - ✅
challangebir martalik + qisqa TTL — harauthda yangi challange, backend Redis'da cheklangan muddat saqlaydi. - ✅ Yakuniy tekshiruv backendda — frontend'dagi
status:1o'zi yetarli emas; foydalanuvchi ma'lumoti/backend/mobile/authenticate/{documentId}javobidan olinadi. - ✅
hash("hesh-kod") ni foydalanuvchiga ko'rsating — ilovadagi bilan ko'z bilan solishtirish phishing'ni kamaytiradi.
Localhost daemon TLS
E-IMZO daemon wss://127.0.0.1:64443 da self-signed sertifikat ishlatadi (pinning yo'q).
Lokal mashinadagi zararli proses portga "o'tirib" imzolarni tutib qolishi mumkin — bu paket
buni oldini olmaydi (tahdid model — OS-level malware). Mitigatsiya: ishonchli mashina,
antivirus, host-based IDS.
CSP tavsiyalari
script-src 'self'; # inline mode
connect-src 'self' wss://127.0.0.1:* ws://127.0.0.1:*;External mode'da script-src ga https://e-imzo.uz qo'shing va scriptIntegrity (SRI) bering.
E-IMZO v6 yangiliklari
Paket avtomatik aniqlaydi va moslashadi:
- ✅ API-KEY avtomatik o'rnatiladi (
apikeychaqiruv kerak emas) - ✅ 32 MB gacha hujjat imzolash
- ✅ ID-card emulyatori (test rejimi)
- ✅ UZGUARD token qo'llab-quvvatlash
- ✅ JRE 17 → JRE 1.8 PFX moslik
Bog'lanish
Muallif: Qobiljon Jumaboyev
- LinkedIn: qobiljon-jumaboyev
- GitHub: @qobiljonDev
Savol, taklif yoki xavfsizlik muammolari uchun yuqoridagi kanallar orqali bog'laning.
Litsenziya
MIT © Qobiljon Jumaboyev
