Как команда it-animals в финале Цифрового Прорыва выиграла

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Данная статья написана в соавторстве с тимлидом @Restlin

Выбор кейса и наше видение его решения

Изначально выбор пал на кейс МВД: Разработка автономного программного решения лингвистического анализа и преобразования в тексте лица повествования.

Формулировка кейса:

Учитывая специфику деятельности определенных служб МВД России, при подготовке документов требуется преобразование в тексте лица повествования от первого лица в третье с учетом рода. Например, фраза в исходном тексте «Я увидел, что Иванов пошёл ко мне» в итоговом тексте должна быть преобразована в «Он увидел, что Иванов пошёл к нему». Разработанное программное решение позволит в автоматическом режиме проводить процесс конвертации лица повествования, что позволит сотрудникам уделить больше времени на иные аспекты служебной деятельности. Кейс подготовлен Департаментом информационных технологий, связи и защиты информации МВД России. 

Нам он был близок по специализации, и было четкое представление как красиво можно решить данную задачу.

Планировалось, что мы создадим веб-сервис, который умеет автоматически  преобразовывать показания свидетеля из первого лица в третье.

 Все складывалось как нельзя лучше до того момента, как мы не посмотрели видео с презентацией кейса от кейсодержателя, что на выходе они ждут: 

1) локальное решение, работающее без доступа в сеть; 

2) интегрированные офисные пакеты посредством макросов.

Наша команда разделилась на 2 лагеря: половина настаивала на четком соблюдении требований кейсодержателя, в противном случае смене кейса, вторая настаивала на первичном варианте решения ( оффтоп: подобное решение выстрелило у других ребят и они выиграли).

Долгое время споры не утихали по данному поводу, все же решили сменить первоначальный выбор на кейс Почты России: Разработка прототипа системы обработки и подписания документов с использованием электронной подписи, применяемой для работы с обращениями граждан.

Формулировка кейса:

Согласно действующему законодательству «Почта России» обязана официально отвечать на поступающие запросы граждан, связанные с работой компании и качеством оказания услуг. Обращения поступают в профильное подразделение, где, после подготовки ответа, подписываются, сканируются и отправляются в соответствующий филиал или автору обращения. Процесс является трудоемким и ресурсоемким с точки зрения ручных операций и расходных материалов (бумага, расходы на оргтехнику). Участникам хакатона предлагается разработать программное решение - модуль подписания документов с помощью электронной подписи, который расширит функциональность существующей системы работы с обращениями (Террасофт Creatio). Модуль должен формировать электронную подпись для каждого файла отдельно и перед подписанием проверять срок действия сертификата электронной подписи уполномоченного сотрудника.

Почему он? У нас было понимание как работать с электронной подписью на Open source решениях: OpenSSL. Пригодился опыт Ильи в разработке СЭД - он знал о существовании php библиотеки tcpdf для генерации файла pdf с возможностью встроить электронную подпись. Плюс на текущем проекте pirs.online мы уже копали эту тему, и оттого данной задачей заниматься было приятно вдвойне.

Вся наша подготовка к финалу заключалась в обсуждениях плана решения и договоренности с родными, что мы опять пропадем на работе на все выходные.

Панические атаки и ведро валерьянки

В пятницу вечером мы остались в офисе,  получили подробное техническое задание кейса и приступили к решению. Последнее вранье - мы начали неистово паниковать, так как в технических ограничениях к решению значилось требование в реализации на ASP.NET. 

Написали в чат поддержки ЦП (хвала за неиссякаемое терпение Ирине с вопросом: что нам делать и можно ли сменить кейс? К счастью, организаторам удалось переубедить представителей Почты России снять это ограничение и только тогда мы смогли приступить к решению. 

А что потом? Технические подробности

Дальше пошло по накатанной: первый чекпоинт и наши идеи по реализации, полученное одобрение экспертов и практически бессонная ночь работы.

Нам повезло: роли между командой у нас распределены четко, и каждый занимается своей задачей. Марина - презентация и вычитка спитча Ильи. Илья отвечает за спитч, архитектуру, бэк. Дима и Кирилл - фуллстеки.

С точки зрения технической реализации функционал прототипа выглядел просто:

  • вход пользователя под одной из двух ролей: гость и администратор;

  • формирование обращения администратору (почте РФ);

  • рассмотрение обращения и формирование ответа;

  • можно прикрепить файлы к обращению и ответу;

  • создать сертификат пользователя в личном кабинете;

  • подписать файлы ответа электронной подписью;

  • выгрузить обращение с электронной подписью;

  • проверить электронную подпись в обращении.

Структура базы данных прототипа уместилась всего в 3 таблицы, размещенных в PostgreSQL: 

  1. user - таблица пользователей с реквизитами и типами;

  2. message - таблица обращений и ответов. По сути это переписка клиента и администратора;

  3. file - таблица файлов, прикрепленных к обращениям и ответам.

Благодаря большому опыту команды с php-фреймворком Yii2 мы в короткие сроки разработали основной функционал приложения. А вот задача интеграции функционала по работе с электронными подписями была трудоемкой и нетривиальной.

Для работы с электронными подписями мы решили использовать OpenSSL, как открытый стандарт де-факто по работе с электронными подписями.

Как и ожидалось библиотека очень мощная, но из коробки не поддерживает отечественные алгоритмы шифрования. Какое-то время ушло на интеграцию и настройку криптографического движка (libengine-gost-openssl 1.1) на алгоритмы ГОСТ, в частности ГОСТ-2012. Затем мы создали и настроили удостоверяющий центр.

Второй чекпоинт: показали первичный вид презентации. Первый провал - ошиблись с формулировкой проблематики кейса, близко, но не то. Вот почему важно презентацию хотя бы раз показать экспертам! 

Пилим прототип дальше

PHP содержит функции для работы с openssl по созданию сертификатов и подписи файлов, но после тщательного изучения документации, выяснилось, что переключить openssl engine на ГОСТ невозможно.

Поэтому команда принимает решение перейти к работе с openssl через консоль. Решение выглядит менее изящным, зато предоставляет доступ ко всей функциональности openssl.

Создание сертификата пользователя:

exec("openssl req -nodes -newkey gost2012_512 -keyout $eSignPath/client.key -pkeyopt paramset:A -out $eSignPath/client.csr -subj \"/C=RU/ST=Udm/L=Izhevsk/O=IT/OU=animals/CN=user-{$user->id}\" -config $caPath/openssl.cnf ");

exec("openssl ca -engine gost -keyfile $caPath/ca.key -cert $caPath/ca.crt -in $eSignPath/client.csr -out $eSignPath/client.crt -batch -config $caPath/openssl.cnf 2>&1", $output);

где $eSignPath - путь до папки с ключами пользователей, а $caPath - путь до папки удостоверяющего центра.

Удаление сертификата пользователя:

exec("openssl ca -config $caPath/openssl.cnf -keyfile $caPath/ca.key -cert $caPath/ca.crt -revoke $eSignPath/client.crt 2>&1", $output);

exec("openssl ca -gencrl -config $caPath/openssl.cnf -keyfile $caPath/ca.key -cert $caPath/ca.crt -out $caPath/crl.pem 2>&1", $output);

где $eSignPath - путь до папки с ключами пользователей, а $caPath - путь до папки удостоверяющего центра.

Подписание файла сертификатом пользователя:

exec("openssl smime -engine gost -sign -in $fp -out $fp.sig -nodetach -binary -signer $clientKeysPath/client.crt -inkey $clientKeysPath/client.key -outform SMIME 2>&1", $output);

где $fp - путь до файла, $clientKeysPath - путь до папки с ключами пользователя.

Проверка подписи файла:

$output = exec("openssl cms -engine gost -verify -in $sigPath -inform SMIME -CAfile $pathCA/ca.crt -out $fp -certsout $clientKeysPath/client.crt 2>&1");

где $fp - путь до файла, $clientKeysPath - путь до папки с ключами пользователя, $sigPath - путь до электронной подписи.

Долгие часы настройки openssl и его интеграции в веб-приложение увенчались успехом. К  третьему чекпоинту прототип уже мог создавать сертификат пользователя, подписывать сертификатом обращение, а затем проверять подпись. Решение было рабочим, но чутье подсказывало: не хватает какой-то главной фишки.

Появилась идея: Илья вспоминает, что в одной не самой популярной библиотеке tcpdf по формированию pdf файлов была возможность встраивания электронной подписи в pdf файл. А это значит, что можно из обращения создать pdf файл и сразу встроить в него электронную подпись.

Ночь субботы подходит к концу: мы голодные и злые все еще работаем в офисе. Тошнит от доставок, работы вагон, но мы верим в команду и в то, что победа близка. Договариваемся ехать домой, и доделывать уже там.

Начинаем реализовывать и понимаем на сколько в библиотеке tcpdf захардкодена работа с openssl. Вылазят проблемы невозможности смены движка и другие конфликты библиотеки с нашим решением. Создаем потомка библиотеки и заменяем всю генерацию подписи с хардкода openssl на наш костыль (херак-херак, и в продакшн) через локальный метод api:

$fields = [

'r' => 'api/sign',

'filePath' => $tempdoc,

'userId' => $user->id,

];

$query = http_build_query($fields);

$ch = curl_init();

$host = \Yii::$app->params['apiHost'] ?? '';

curl_setopt($ch, CURLOPT_URL, $host . '/index.php?' . $query);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$signature = curl_exec($ch);

/*if (empty($this->signature_data['extracerts'])) {

openssl_pkcs7_sign($tempdoc, $tempsign, $this->signature_data['signcert'], array($this->signature_data['privkey'], $this->signature_data['password']), array(), PKCS7_BINARY | PKCS7_DETACHED);

} else {

openssl_pkcs7_sign($tempdoc, $tempsign, $this->signature_data['signcert'], array($this->signature_data['privkey'], $this->signature_data['password']), array(), PKCS7_BINARY | PKCS7_DETACHED, $this->signature_data['extracerts']);

}*/

И все же мы успеваем в последний момент и к утру воскресенья прототип полностью работает!

Последний рывок и мы у цели

В середине дня воскресенья Илья подключается по Zoom к защите решения, жюри неумалимы, ну а мы ждем результатов. 

Было страшновато: осознание, что ты соревнуешься с лучшими  (в финал попали топ 5 команд из отборочных региональных туров) подстегивало выкладываться на полную. 

Неожиданно результатов пришлось ждать до вечера, хотя на Северо-Западном хабе объявили победителей чуть ли не через час после защит. Время тянулось как доставка Почты России.

Офтоп: мы победители! 750 тысяч на команду, Карл! 750 за 2 дня, Карл! А значит едем на грандфинал Цифрового прорыва в Москву!

Репозиторий нашего решения

Источник: https://habr.com/ru/post/558962/


Интересные статьи

Интересные статьи

Привет, Хабр! Где-то года три назад мы начали переходить с обычного вотерфольного процесса, присущего большинству продуктов энтерпрайз-сегмента, на «гибкие подходы». Стар...
Часто от программистов PHP можно услышать: «О нет! Только не „Битрикс“!». Многие специалисты не хотят связываться фреймворком, считают его некрасивым и неудобным. Однако вакансий ...
Всем привет. Когда я искал информацию о журналировании (аудите событий) в Bitrix, на Хабре не было ни чего, в остальном рунете кое что было, но кто же там найдёт? Для пополнения базы знаний...
Как быстро определить, что на отдельно взятый сайт забили, и им никто не занимается? Если в подвале главной страницы в копирайте стоит не текущий год, а старый, то именно в этом году опека над са...
Несмотря на то, что “в коробке” с Битриксом уже идут модули как для SOAP (модуль “Веб сервисы” в редакции “Бизнес” и старше), так и для REST (модуль “Rest API” во всех редакциях, начиная с...