From 2ca07d1b831af9949c432e286ba67c6d4277bf1f Mon Sep 17 00:00:00 2001 From: aiekseu Date: Tue, 27 Feb 2024 16:26:32 +0300 Subject: [PATCH] =?UTF-8?q?feat(cryptopro-cades):=20=D0=94=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D1=84=D1=83=D0=BD=D0=BA?= =?UTF-8?q?=D1=86=D0=B8=D1=8F=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=B4=D0=BE=D1=81=D1=82=D1=83=D0=BF=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D1=81=D1=87=D0=B8=D1=82=D1=8B=D0=B2=D0=B0=D1=82=D0=B5?= =?UTF-8?q?=D0=BB=D0=B5=D0=B9=20(#41)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(cryptopro-cades): Добавлена функция получения доступных считывателей * Update packages/cryptopro-cades/README.md --------- Co-authored-by: Andrey Potyomkin --- packages/cryptopro-cades/README.md | 1 + .../cryptopro-cades/src/api/getReaders.ts | 80 +++++++++++++++++++ packages/cryptopro-cades/src/api/index.ts | 2 + .../cryptopro-cades/src/constants/cades.ts | 6 ++ .../cryptopro-cades/src/errors/errorCodes.ts | 1 + .../src/types/cadesplugin/CCspInformation.ts | 23 ++++++ .../src/types/cadesplugin/CReaderMode.ts | 36 +++++++++ .../src/types/cadesplugin/CReaderModes.ts | 20 +++++ .../src/types/cadesplugin/index.ts | 6 ++ 9 files changed, 175 insertions(+) create mode 100644 packages/cryptopro-cades/src/api/getReaders.ts create mode 100644 packages/cryptopro-cades/src/types/cadesplugin/CCspInformation.ts create mode 100644 packages/cryptopro-cades/src/types/cadesplugin/CReaderMode.ts create mode 100644 packages/cryptopro-cades/src/types/cadesplugin/CReaderModes.ts diff --git a/packages/cryptopro-cades/README.md b/packages/cryptopro-cades/README.md index faaebc3..b11a777 100644 --- a/packages/cryptopro-cades/README.md +++ b/packages/cryptopro-cades/README.md @@ -57,3 +57,4 @@ npm install @astral/cryptopro-cades - getCryptoProviders - получение списка криптопровайдеров установленных на компьютере пользователя. Название, тип, версия. - getSystemInfo - получение информации о системе пользователя - версия КриптоПро ЭЦП Browser plug-in, версия CSP (VipNet или CryptoPro) - pluginConfig - возможность включить вывод отладочной информации, подписываться на все создаваемые исключения, отключать проверку корректности системы, ограничивать тип криптопровайдера которым можно пользоваться, его версии. +- getReaders - получение списка доступных считывателей (в т.ч. вставленных токенов) с помощью CryptoPro CSP. diff --git a/packages/cryptopro-cades/src/api/getReaders.ts b/packages/cryptopro-cades/src/api/getReaders.ts new file mode 100644 index 0000000..0b63f36 --- /dev/null +++ b/packages/cryptopro-cades/src/api/getReaders.ts @@ -0,0 +1,80 @@ +import { CRYPTO_OBJECTS, DEFAULT_CRYPTO_PROVIDER } from '../constants'; +import { CryptoError } from '../errors'; +import { + type CCspInformation, + type CReaderMode, + type CReaderModes, +} from '../types'; +import { outputDebug } from '../utils'; + +import { createObject } from './createObject'; +import { getSystemInfo } from './getSystemInfo'; +import { afterPluginLoaded } from './internal/afterPluginLoaded'; +import { unwrap } from './internal/unwrap'; + +/** + * Кэш из доступных считывателей. + */ +let readersCache: CReaderMode[] | null; + +/** + * Получить список доступных считывателей (в т.ч. вставленных токенов) с помощью CryptoPro CSP. + * @throws {CryptoError} в случае ошибки. + * @returns {Promise} Информация о доступных считывателях. + */ +export function getReaders( + resetCache: boolean = false, +): Promise { + if (readersCache && !resetCache) { + return Promise.resolve(readersCache); + } + + return afterPluginLoaded(async () => { + if (readersCache && !resetCache) { + return Promise.resolve(readersCache); + } + + // Получить список считывателей можно только с помощью КриптоПро CSP + const systemInfo = await getSystemInfo(); + + if (!systemInfo.cryptoProInstalled) { + throw CryptoError.create( + 'CBP-12', + 'Ошибка получения списка доступных считывателей', + null, + ); + } + + const logData = []; + const readers: CReaderMode[] = []; + + try { + const cspInformation: CCspInformation = await createObject( + CRYPTO_OBJECTS.cspInformation, + ); + + await cspInformation.InitializeFromName( + DEFAULT_CRYPTO_PROVIDER.Default.ProviderName, + ); + + const readerModes: CReaderModes = await unwrap( + cspInformation.GetReaderModes(), + ); + const readersCount = await unwrap(readerModes.Count); + + for (let i = 0; i < readersCount; i++) { + const reader = await unwrap(readerModes.ItemByIndex(i)); + + readers.push(reader); + } + + return (readersCache = readers); + } catch (error) { + logData.push({ error }); + throw error; + } finally { + logData.push({ readers }); + outputDebug('getReaders >>', logData); + } + })(); +} diff --git a/packages/cryptopro-cades/src/api/index.ts b/packages/cryptopro-cades/src/api/index.ts index 415479b..af90c3b 100644 --- a/packages/cryptopro-cades/src/api/index.ts +++ b/packages/cryptopro-cades/src/api/index.ts @@ -29,3 +29,5 @@ export { findCertificateByThumbprint } from './findCertificateByThumbprint'; export { findCertificateBySkid } from './findCertificateBySkid'; export { checkPlugin } from './checkPlugin'; + +export { getReaders } from './getReaders'; diff --git a/packages/cryptopro-cades/src/constants/cades.ts b/packages/cryptopro-cades/src/constants/cades.ts index 7014b8b..2a2e64c 100644 --- a/packages/cryptopro-cades/src/constants/cades.ts +++ b/packages/cryptopro-cades/src/constants/cades.ts @@ -960,4 +960,10 @@ export const enum CRYPTO_OBJECTS { * @see https://docs.cryptopro.ru/cades/plugin/certenroll/ccspinformations?id=ccspinformations */ cspInformations = 'X509Enrollment.CCspInformations', + + /** + * Объект CCspInformation позволяет получить информацию о криптопровайдере. + * @see https://docs.cryptopro.ru/cades/plugin/certenroll/ccspinformation + */ + cspInformation = 'X509Enrollment.CCspInformation', } diff --git a/packages/cryptopro-cades/src/errors/errorCodes.ts b/packages/cryptopro-cades/src/errors/errorCodes.ts index 773a95e..b04408a 100644 --- a/packages/cryptopro-cades/src/errors/errorCodes.ts +++ b/packages/cryptopro-cades/src/errors/errorCodes.ts @@ -161,6 +161,7 @@ export const PLUGIN_ERRORS = Object.freeze({ 'CBP-9': 'Неизвестный алгоритм ключа.', 'CBP-10': 'Не удалось прочитать данные сертификата.', 'CBP-11': 'Потеряно соединение с КриптоПро ЭЦП Browser plug-in.', + 'CBP-12': 'Для получения списка считывателей необходим КриптоПро CSP', }); /** diff --git a/packages/cryptopro-cades/src/types/cadesplugin/CCspInformation.ts b/packages/cryptopro-cades/src/types/cadesplugin/CCspInformation.ts new file mode 100644 index 0000000..3025acb --- /dev/null +++ b/packages/cryptopro-cades/src/types/cadesplugin/CCspInformation.ts @@ -0,0 +1,23 @@ +import type { WithOptionalPromise } from '../WithOptionalPromise'; + +import { CReaderModes } from './CReaderModes'; + +/** + * Объект CCspInformation позволяет получить информацию о криптопровайдере. + * @see https://docs.cryptopro.ru/cades/plugin/certenroll/ccspinformation + */ +export interface CCspInformation { + /** + * Инициализирует объект по имени криптопровайдера + * @param {string} cryptoProviderName – + */ + InitializeFromName(cryptoProviderName: string): WithOptionalPromise; + + /** + * Возвращает коллекцию доступных считывателей + */ + GetReaderModes(): WithOptionalPromise; + + // есть еще другие методы и свойства (см. по ссылке выше), + // но для получения информации о вставленных токенах нужны только эти +} diff --git a/packages/cryptopro-cades/src/types/cadesplugin/CReaderMode.ts b/packages/cryptopro-cades/src/types/cadesplugin/CReaderMode.ts new file mode 100644 index 0000000..57c772e --- /dev/null +++ b/packages/cryptopro-cades/src/types/cadesplugin/CReaderMode.ts @@ -0,0 +1,36 @@ +import type { WithOptionalPromise } from '../WithOptionalPromise'; + +/** + * Объект, содержащий информацию о режимах работы доступного считывателя. + * @see https://docs.cryptopro.ru/cades/reference/cadescom/cadescom_class/creadermode + */ +export type CReaderMode = { + /** + * Возвращает имя для данного режима работы считывателя, с порядковым номером + * @example HDIMAGE + * @example Aktiv Rutoken lite + * @example Aktiv Rutoken lite 01 – если вставлен еще один токен + */ + Name: WithOptionalPromise; + + /** + * Возвращает никнейм для данного режима работы считывателя, не уникальное значение + * @example HDD key storage + * @example Rutoken lite + * @example Rutoken ECP + */ + NickName: WithOptionalPromise; + + /** + * Возвращает медиа для данного режима работы считывателя, уникальное значение для токенов + * @example NO_UNIQUE, NO_MEDIA – для диска или облака + * @example pkcs11_rutoken_ecp_435461fa + * @example rutoken_lt_40a6544f + */ + Media: WithOptionalPromise; + + /** + * Возвращает результат побитового сложения флагов для данного режима работы считывателя + */ + CarrierFlags: WithOptionalPromise; +}; diff --git a/packages/cryptopro-cades/src/types/cadesplugin/CReaderModes.ts b/packages/cryptopro-cades/src/types/cadesplugin/CReaderModes.ts new file mode 100644 index 0000000..50ae208 --- /dev/null +++ b/packages/cryptopro-cades/src/types/cadesplugin/CReaderModes.ts @@ -0,0 +1,20 @@ +import type { WithOptionalPromise } from '../WithOptionalPromise'; + +import { CReaderMode } from './CReaderMode'; + +/** + * Объект, содержащий информацию о режимах работы доступного считывателя. + * @see https://docs.cryptopro.ru/cades/reference/cadescom/cadescom_interface/icpreadermodes + */ +export type CReaderModes = { + /** + * Возвращает считыватель с заданным индексом из коллекции. + * @param index Порядковый номер + */ + ItemByIndex(index: number): WithOptionalPromise; + + /** + * Возвращает количество считывателей. + */ + Count: WithOptionalPromise; +}; diff --git a/packages/cryptopro-cades/src/types/cadesplugin/index.ts b/packages/cryptopro-cades/src/types/cadesplugin/index.ts index 7022330..6dd888e 100644 --- a/packages/cryptopro-cades/src/types/cadesplugin/index.ts +++ b/packages/cryptopro-cades/src/types/cadesplugin/index.ts @@ -21,3 +21,9 @@ export type { ISignedXml } from './ISignedXml'; export type { IStore } from './IStore'; export type { IVersion } from './IVersion'; + +export type { CCspInformation } from './CCspInformation'; + +export type { CReaderMode } from './CReaderMode'; + +export type { CReaderModes } from './CReaderModes';