Skip to content

SignService 1.2.0: сведение PR #3 и UX, перенос из PR #2, исправления ревью, сборка релиза - #4

Merged
zaynullinmi merged 11 commits into
mainfrom
claude/ecp-document-signing-service-dbbut0
Oct 7, 2026
Merged

zaynullinmi merged 11 commits into
mainfrom
claude/ecp-document-signing-service-dbbut0

Conversation

@zaynullinmi

Copy link
Copy Markdown
Owner

Зачем

Релиз v1.1.0 был выпущен из невлитого PR #3, поэтому main не совпадал с выпущенной версией. PR #2 и PR #3 конфликтуют между собой, а переработка интерфейса (85ae135) не попала ни в один из них. Этот PR сводит всё в одну ветку, исправляет найденные при ревью ошибки и готовит выпуск 1.2.0 из main.

Что внутри

Сведение

Перенесено из PR #2. Проверка на CryptoAPI (CmsVerifier) и его логика МЧД не перенесены.

  • «Разделить групповую подпись» и «Исключить подписанта»: в меню «Инструменты» и в контекстном меню.
  • Повторная постановка файла в очередь после приложенной подписи или смены сертификата.
  • Помощник автообновления с резервной копией и откатом.
  • Изолированные настройки и папка PFX для тестов.
  • Тесты на Windows в CI.

Исправления ревью (на каждое есть регрессионный тест; тест проверен на старом поведении)

  1. МЧД: сертификат руководителя, истёкший после выдачи МЧД, теперь даёт предупреждение, а не ошибку. Истёкший до выдачи или ещё не действовавший — по-прежнему ошибка.
  2. МЧД: ИНН организации (1.2.643.100.4 или «00» + ИНН ЮЛ) больше не сравнивается с ИНН физлица.
  3. Исключение BouncyCastle при проверке означает «не определено», а не «ошибка». Законный соподписант больше не выпадает из объединения.
  4. Обновление списка сертификатов не сбрасывает подписанные файлы: сравниваются отпечатки.
  5. Замена занятого exe при автообновлении повторяется; лишние резервные копии не остаются.
  6. Отсутствующий файл доверенного корня пропускается и попадает в лог. Сохранённая МЧД больше не теряется. Учитывается настройка сетевых запросов.
  7. МЧД проверяется в фоне и один раз на пакет; хранилища ОС кешируются.
  8. Документ хешируется один раз на алгоритм; при объединении нет двойного преобразования attach/detach.
  9. Удалён мёртвый код сверки по messageDigest.
  • Дополнительно найдено смоук-тестом: команды контекстного меню файла не были привязаны, потому что $parent[ItemsControl] не работает из всплывающего меню. Исправлено и закрыто headless-тестом интерфейса.

Релиз

  • Версия 1.2.0. В CHANGELOG раздел v1.1.0 восстановлен в выпущенном виде.
  • CI собирает архив: exe, README.txt, CHANGELOG, LICENSE, лицензии компонентов, SHA256SUMS, файл .sha256 и описание релиза из CHANGELOG.
  • Тег обязан совпадать с версией. SignService.exe остаётся отдельным ассетом для автообновления 1.0/1.1.

Проверка

  • dotnet build: 0 предупреждений.
  • dotnet run --project tests/SignService.Tests -c Release — ALL TESTS PASSED: 76 проверок верификатора, регрессии ревью, смоук интерфейса (Avalonia.Headless).
  • Помощник обновления прогнан под pwsh: успех, отказ, откат и повтор до разблокировки.
  • Скрипт упаковки прогнан на кросс-публикации win-x64; суммы сверены через sha256sum -c.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BtHSRXSuM8qTBTUBe29624


Generated by Claude Code

claude and others added 11 commits August 25, 2026 20:13
- лог операций всегда виден, дублирующая статусная строка убрана
  (все сообщения идут в лог с отметкой времени);
- диалог параметров штампа перед подписанием и операцией «Штамп»:
  страницы — последняя/первая/все/указанные («1,3-5», как в печати),
  дата, логотип, «подписывать копию со штампом»; на каждой выбранной
  странице — отдельная плашка на КАЖДОГО подписанта, колонками
  из правого нижнего угла (PdfStamper.StampOptions/ResolvePages);
- окно «Подписанты и проверка ЭЦП» (SignatureVerifier): по каждому
  подписанту — сертификат, срок, время подписания, штамп времени,
  соответствие документу (messageDigest, для ГОСТ — Стрибог) и
  криптопроверка значения подписи; вызов из ПКМ, из «Инструментов»
  (для внешних .sig) и для прикреплённых контейнеров без документа;
- штамп времени (CAdES-T) и адрес TSA вынесены в окно «Настройки…»;
- контекстное меню файлов списка: подписанты/проверка, приложить
  подписи, штамп, извлечь, собрать контейнер, открыть папку, убрать;
- «Штамп на PDF» без подписания берёт подписантов из «имя.sig» рядом;
- инструмент «Проверить подпись…» в меню.

Тесты: разбор страниц (диапазоны, ошибки), рендер 3 подписанта × все
страницы, проверка ЭЦП (2 валидных, протухший помечается, прикреплённый
контейнер без документа, формат отчёта).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BtHSRXSuM8qTBTUBe29624
База — PR #3: проверка подписей через BouncyCastle (ГОСТ без КриптоПро),
цепочка доверия, CRL/OCSP, TSA, атомарная запись, проверка МЧД.
Поверх неё — переработка интерфейса из 85ae135:
- окно «Проверка ЭЦП» из PR #3 открывается из меню, ПКМ по файлу
  и кнопки «Подписанты» (с подстановкой .sig и документа);
- собственный упрощённый SignatureVerifier и SignersDialog удалены
  в пользу верификатора PR #3;
- диалог параметров штампа, отдельная копия со штампом и постоянный
  лог сохранены;
- тесты штампа и проверки переписаны на API PR #3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BtHSRXSuM8qTBTUBe29624
…ое автообновление

- «Разделить групповую подпись» и «Исключить подписанта» — в меню
  «Инструменты» и в контекстном меню файла (для «имя.sig» рядом);
  подписанты различаются по SignerIdentifier даже при одинаковых ФИО,
  последнего подписанта исключить нельзя, исходный файл не меняется.
- Приложенная подпись другого лица или смена сертификата возвращают
  подписанный файл в очередь (смена определяется по отпечатку —
  обновление списка сертификатов статусы не сбрасывает).
- Автообновление: помощник PowerShell с резервной копией, повторами
  замены занятого exe и откатом при неудачном запуске.
- Настройки и хранилище PFX можно открыть в отдельной папке (тесты
  больше не пишут в %AppData%).
- Контекстные команды недоступны во время подписания.
- CI: тесты на Windows перед сборкой exe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BtHSRXSuM8qTBTUBe29624
…верия, кеши

МЧД:
- сертификат руководителя, истёкший уже после выдачи МЧД, больше не
  отклоняет доверенность: проверка повторяется на дату выдачи и даёт
  предупреждение; истёкший до выдачи или ещё не действовавший — ошибка
  (при доверенной метке TSA решает время метки);
- личный ИНН представителя берётся только из 1.2.643.3.131.1.1 (12 цифр);
  ИНН организации (1.2.643.100.4, «00» + ИНН ЮЛ) с ИННФЛ не сравнивается,
  совпадения по СНИЛС достаточно; для руководителя прежняя запись «00» +
  ИНН ЮЛ распознаётся как ИНН организации;
- МЧД проверяется один раз на пакет, в каталоги копируется проверенный
  снимок; при запуске и добавлении проверка идёт в фоне.

Проверка ЭЦП и объединение:
- исключение библиотеки при проверке значения подписи, messageDigest или
  привязки сертификата — «не определено», а не «ошибка»: законный
  соподписант остаётся в объединении (в списке непроверенных);
- документ хешируется один раз на алгоритм (общий кеш хешей, проверка
  BouncyCastle по готовому хешу), вложенный документ входов не копируется
  при проверке каждого подписанта;
- объединение сразу собирает результат в нужном виде (прикреплённый или
  откреплённый) — без повторного преобразования;
- хранилища сертификатов ОС кешируются на 2 минуты;
- удалён неиспользуемый код сверки по messageDigest.

Настройки доверия:
- недоступный или повреждённый файл доверенного корня пропускается с
  записью в лог/отчёт (раньше ронял проверку и молча сбрасывал МЧД);
- разрешение сетевых запросов CRL/OCSP берётся из настроек.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BtHSRXSuM8qTBTUBe29624
Неудачная попытка File.Replace может создать копию прежнего exe под
именем резервной; между повторами и при окончательной неудаче она
удаляется (прежний exe при этом на месте).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BtHSRXSuM8qTBTUBe29624
Меню — всплывающее окно вне дерева элементов списка, поэтому привязка
$parent[ItemsControl] в нём не находила модель окна, и все пункты меню
оставались без команд. Элемент очереди теперь знает модель окна (Owner),
пункты меню и кнопки строки привязаны к ней через собственный
DataContext элемента.

Добавлен смоук интерфейса без экрана (Avalonia.Headless): главное окно,
контекстное меню файла (команды привязаны и выполняются для файла),
меню «Инструменты» и все диалоги.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BtHSRXSuM8qTBTUBe29624
…а релиза

- CHANGELOG: раздел v1.1.0 восстановлен в выпущенном виде (при слиянии
  в него попали невыпущенные изменения), добавлен раздел v1.2.0.
- README (RU/EN): контекстное меню, разделение подписи и исключение
  подписанта, диалог штампа, правила МЧД, настройки, автообновление,
  структура проекта.
- CI собирает архив релиза: exe, README.txt, CHANGELOG, LICENSE, лицензии
  компонентов (из графа NuGet и .github/release/licenses), SHA256SUMS,
  файл .sha256 и описание релиза из раздела версии в CHANGELOG. Тег
  релиза обязан совпадать с версией проекта. SignService.exe остаётся
  отдельным файлом релиза — его скачивает автообновление 1.0/1.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BtHSRXSuM8qTBTUBe29624
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants