Привет, Хабр! Меня зовут Олеся Лазарева, я работаю старшим разработчиком в команде PIlot.
В этой статье мы рассмотрим создание плагина криптопровайдера для веб-редакции системы управления инженерными данными Pilot-ICE Enterprise. Веб-редакция Pilot-ICE Enterprise работает с плагинами, которые используют формат электронной подписи CADES-BES. Данные плагины поставляются в составе Ascon.Pilot.Web.SDK. Это покрывает потребности большинства российских организаций, работающих в соответствии с требованиями ГОСТ.
Однако на практике могут возникнуть ситуации, когда необходимо:
Использовать альтернативные криптопровайдеры (ruToken, JaCarta, Aktiv и др.);
Поддержать специфические форматы подписи, требуемые заказчиком;
Интегрироваться с корпоративными системами электронного документооборота;
Работать с международными стандартами подписи (PAdES, XAdES и т.д.).
Для таких случаев веб-версия Pilot-ICE Enterprise предоставляет возможность создания собственных плагинов-криптопровайдеров через открытый SDK.
Для демонстрации основных концепций разработки мы реализуем простой плагин для подписания электронной цифровой подписью на базе хеш-функции FNV-1a.
Важно: FNV-1a не является криптостойким алгоритмом и используется здесь исключительно в образовательных целях. Для production-среды необходимо использовать сертифицированные криптографические алгоритмы.

Архитектура плагина
Плагин представляет собой TypeScript-модуль, который подключается к веб-версии Pilot-ICE Enterprise через механизм Module Federation.
Основной класс CryptoProviderFnv1Extension реализует интерфейс ICryptoProvider и предоставляет методы для:
Получения списка сертификатов (
getCertificates)Создания электронной подписи документа (
sign)Проверки подписи (
verify,verifyImportedSignature)Определения поддерживаемых алгоритмов (
canProcessAlgorithms)
Основные компоненты:
CryptoProviderFnv1Extension — главный класс, реализующий интерфейс
ICryptoProviderFileSignatureUpdater — утилита для обновления подписей в объектах документов
Вспомогательные функции — работа с кодировками и преобразованиями данных
Структура проекта
Перед началом разработки рассмотрим организацию файлов в проекте:
cryptoprovider.fnv1.sample/
│
├── src/
│ ├── app/
│ │ ├── cryptoProviderFnv1Extension.ts # Главный класс плагина
│ │ ├── file-signature.updater.ts # Логика обновления подписей
│ │ ├── signature-date-object.interface.ts # Интерфейс данных подписи
│ │ └── utils.ts # Вспомогательные функции
│ │
│ ├── assets/
│ │ └── extensions.config.json # Манифест плагина
│ │
│ └── index.ts # Точка входа (пустой файл)
│
├── dist/ # Директория сборки (генерируется)
│ ├── main.js # Скомпилированный модуль
│ └── extensions.config.json # Скопированный манифест
│
├── package.json # Конфигурация npm и зависимости
├── tsconfig.json # Конфигурация TypeScript
├── webpack.config.js # Конфигурация Webpack (dev)
└── webpack.prod.config.js # Конфигурация Webpack (production)
Назначение ключевых файлов:
Исходный код (src/):
cryptoProviderFnv1Extension.ts— основная логика криптопровайдера, реализация всех методов интерфейсаICryptoProviderfile-signature.updater.ts— класс для работы с Pilot ICE SDK API, модификация объектов документовsignature-date-object.interface.ts— TypeScript-интерфейс для типизации данных подписиutils.ts— функции для преобразования между ArrayBuffer, строками и Base64index.ts— формальная точка входа для Webpack (может быть пустым)
Конфигурация (assets/):
extensions.config.json— манифест, описывающий метаданные плагина и экспортируемые модули
Поток данных в приложении (Data Flow Diagram):
┌──────────────────────┐
│ веб-версия │
│ Pilot-ICE Enterprise│
└──────────┬───────────┘
│
▼
┌──────────────────────────────┐
│ CryptoProviderFnv1 │
│ Extension │
└─────┬────────────────┬───────┘
│ │
▼ ▼
┌─────────────┐ ┌──────────────┐
│ sign() │ │ verify() │
└──────┬──────┘ └──────┬───────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────────┐
│ FNV1a Hash │ │ Декодирование │
│ Calculation │ │ подписи │
└──────┬───────┘ └──────┬───────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────────┐
│ Base64 │ │ Сравнение │
│ Encoding │ │ хешей │
└──────┬───────┘ └──────┬───────────┘
│ │
▼ ▼
┌──────────────────┐ ┌─────────────────┐
│ FileSignature │ │ Результат │
│ Updater │ │ проверки │
└──────┬───────────┘ └─────────────────┘
│
▼
┌──────────────────┐
│ IModifier API │
└──────┬───────────┘
│
▼
┌──────────────────────┐
│ Сохранение в │
│ веб-версии Pilot-ICE │
└──────────────────────┘
Эта структура обеспечивает четкое разделение ответственности: логика криптографии отделена от работы с API системы, а утилиты вынесены в отдельный модуль.
Шаг 1: Инициализация проекта
Создание package.json
Начнем с настройки зависимостей проекта:
Создайте новый angular-проект командой. Чтобы создать angular-расширение, выполните следующие действия:
ng new cryptoprovider.fnv1.sample
Выполните команды в окружении проекта:
npm init
npm install @pilotdev/pilot-web-sdk
npm install @angular-architects/module-federation --save-dev
{
"name": "cryptoprovider.fnv1.sample",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"build": "webpack",
"build-prod": "webpack --config webpack.prod.config.js",
"start": "webpack serve"
},
"dependencies": {
"@pilotdev/pilot-web-sdk": "^25.13.0",
"rxjs": "7.8.1"
},
"devDependencies": {
"@types/jsrsasign": "10.5.15",
"copy-webpack-plugin": "13.0.0",
"ts-loader": "9.5.2",
"typescript": "5.8.2",
"webpack": "5.98.0",
"webpack-cli": "6.0.1"
}
}
-
Ключевые зависимости:
@pilotdev/pilot-web-sdk— SDK для разработки плагиновrxjs— библиотека для работы с асинхронными операциями через реактивное программирование. Используется для обработки потоков данных (Observable), что позволяет элегантно работать с асинхронными операциями подписания и проверки документов. Все методы SDK возвращают Observable, что обеспечивает единообразный подход к обработке асинхронностиwebpack— для сборки модуля
Настройка TypeScript
Создайте tsconfig.json с базовыми настройками:
Добавьте в корневую папку файл tsconfig.json командой
npx tsc --init
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
Шаг 2: Конфигурация Webpack
Webpack используется для создания модуля, который можно загрузить в веб-версию Pilot-ICE Enterprise. Ключевой момент — использование Module Federation Plugin.
webpack.config.js
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const CopyPlugin = require("copy-webpack-plugin");
module.exports = [{
mode: "development",
entry: {main: './src/index.ts'},
module: {
rules: [{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}]
},
resolve: {
extensions: [".tsx", ".ts", ".jsx", ".js", ".json"],
},
output: {
publicPath: 'auto',
uniqueName: 'cryptoprovider_fnv1',
scriptType: 'text/javascript',
filename: '[name].js',
clean: true
},
optimization: {
runtimeChunk: false
},
plugins: [
new ModuleFederationPlugin({
name: 'cryptoprovider_fnv1',
library: { type: 'var', name: '[name]' },
filename: '[name].js',
exposes: [{
ICryptoProvider: './src/app/cryptoProviderFnv1Extension.ts'
}],
shared: {
'@pilotdev/pilot-web-sdk': {
singleton: true,
}
}
}),
new CopyPlugin({
patterns: [
{ from: "./src/assets/extensions.config.json", to: "extensions.config.json" }
],
}),
],
devServer: {
port: 4300,
allowedHosts: 'auto',
headers: {
'Access-Control-Allow-Origin': '*',
"Access-Control-Allow-Credentials": "true",
"Access-Control-Allow-Methods": "GET,HEAD,OPTIONS,POST,PUT",
"Access-Control-Allow-Headers": "Origin, X-Requested-With, Content-Type, Accept, Authorization, x-time-zone-offset"
},
},
}]
Важные моменты конфигурации:
-
ModuleFederationPlugin — позволяет экспортировать модуль для динамической загрузки:
name— уникальное имя модуляexposes— какие модули экспортируются (наш криптопровайдер)shared— общие зависимости с хост-приложением (SDK должен быть singleton)
CopyPlugin — копирует конфигурационный файл
extensions.config.jsonв output-директорию-
devServer — настройки для разработки с CORS-заголовками:
port: 4300— порт, на котором будет запущен dev-сервер для локальной разработкиallowedHosts: 'auto'— автоматически разрешает подключения с любых хостов-
headers— набор HTTP-заголовков для работы Cross-Origin Resource Sharing (CORS):Access-Control-Allow-Origin: '*'— разрешает запросы с любых доменов (для production следует указать конкретный домен)Access-Control-Allow-Credentials: "true"— позволяет передавать cookies и авторизационные данные в кросс-доменных запросахAccess-Control-Allow-Methods— разрешенные HTTP-методы для кросс-доменных запросовAccess-Control-Allow-Headers— список заголовков, которые клиент может отправить в запросе
Эти настройки необходимы, так как плагин будет загружаться с отдельного dev-сервера (localhost:4300) в веб-версию Pilot-ICE Enterprise, работающую на другом порту или домене. Без правильных CORS-заголовков браузер заблокирует загрузку модуля по соображениям безопасности.
Шаг 3: Манифест плагина
Создайте src/assets/extensions.config.json:
{
"$schema": "node_modules/@pilotdev/pilot-web-sdk/extensions.config.schema.json",
"manifestVersion": 1,
"author": "ASCON JSC",
"license": "MIT",
"title": "cryptoprovider.fnv1",
"description": "Educational plugin demonstrating the creation of a custom cryptographic provider using FNV-1a hashing algorithm for document signing and verification.",
"version": "1.0.0",
"extension": {
"name": "cryptoprovider_fnv1",
"entry": "cryptoprovider_fnv1.js",
"modules": [{
"ngModuleName": "CryptoProviderFnv1Extension",
"exposedInterface": "ICryptoProvider"
}]
}
}
Этот файл описывает метаданные плагина и указывает веб-версии Pilot-ICE Enterprise, какой интерфейс реализует модуль.
Шаг 4: Главный класс и вспомогательные файлы
Для полной функциональности плагина необходимо создать вспомогательные модули:
src/app/utils.ts— функции для преобразования между ArrayBuffer, строками и Base64src/app/signature-date-object.interface.ts— TypeScript-интерфейс для типизации данных подписиsrc/app/file-signature.updater.ts— класс для работы с веб-версией Pilot-ICE Enterprise SDK API и модификации объектов документовsrc/app/cryptoProviderFnv1Extension.ts— главный класс плагина с реализацией всех методов интерфейсаICryptoProvider
Полную реализацию этих файлов можно посмотреть в репозитории на GitHub: https://github.com/AlexLazareva/cryptoprovider-fnv1-sample
Шаг 5: Точка входа
Создайте пустой src/index.ts — он нужен как entry point для webpack, но весь функционал находится в cryptoProviderFnv1Extension.ts, который экспортируется через Module Federation.
Шаг 6: Сборка и запуск
Режим разработки
npm install
npm start
Webpack запустит dev-сервер на порту 4300 с hot-reload.
Production-сборка
npm run build-prod
Файлы будут собраны в директорию dist/:
main.js— скомпилированный модульextensions.config.json— манифест плагина
Как это работает
-
Подписание документа:
Пользователь выбирает документ и инициирует подписание
Веб-версия Pilot-ICE Enterprise вызывает
getCertificates()для получения списка сертификатовПосле выбора сертификата вызывается
sign()Метод вычисляет FNV-1a хеш файла
Создается JSON с метаданными (хеш, дата, субъект, издатель)
JSON кодируется в base64
Через
FileSignatureUpdaterсоздается файл подписи и привязывается к документу
-
Проверка подписи:
Веб-версия Pilot-ICE Enterprise вызывает
verify()илиverifyImportedSignature()Декодируется файл подписи
Вычисляется хеш текущего файла
Сравнивается с хешем из подписи
Возвращается результат с статусом и метаданными
Заключение
Мы создали полноценный плагин криптопровайдера для веб-версии Pilot-ICE Enterprise:
✅ Настроили webpack с Module Federation для динамической загрузки
✅ Реализовали все методы интерфейса ICryptoProvider
✅ Использовали SDK API для модификации объектов документов
✅ Создали систему проверки подписей с кастомными состояниями
Этот пример демонстрирует архитектуру плагинов веб-версии Pilot-ICE Enterprise и может служить основой для разработки плагинов для подписания электронной подписью с реальными криптографическими библиотеками (CryptoPro CSP, КриптоПро ЭЦП Browser Plugin, ruToken и др.).
Полный код проекта доступен в репозитории на GitHub: https://github.com/AlexLazareva/cryptoprovider-fnv1-sample
Дальнейшее развитие
Для production-использования необходимо:
Интегрировать сертифицированную криптографическую библиотеку
Добавить обработку ошибок и валидацию сертификатов
Реализовать проверку цепочки доверия
Добавить поддержку различных форматов подписи (CAdES-BES, CAdES-T и т.д.)
Настроить CI/CD для автоматической сборки и тестирования
Ссылки:
SDK Documentation — Центр загрузок АСКОН, "SDK, комплект разработчика"
RxJS Documentation — руководство по операторам и API Reference