feat(admin): копирование контейнеров КриптоПро с флешки в HDIMAGE + уточнение PKI по докам НРД

Сканирование смонтированных USB-носителей (/run/media/$USER, /media,
/mnt) на папки вида name.000 с *.key — это «контейнер КриптоПро на
флешке». В шаге 3 wizard'а и в /admin/setup появилась таблица
найденных контейнеров с кнопкой «Скопировать в локальное хранилище»
(копирует папку в /var/opt/cprocsp/keys/$USER/, после чего контейнер
виден как \\.\HDIMAGE\name и работает без вставленной флешки).

Дедуп по AlreadyImported — если папка уже есть в HDIMAGE, кнопка не
показывается. Сертификат из контейнера импортируется отдельно через
certmgr -inst -cont (это пока вне UI, подсказка в текст flash-сообщения).

Кроме того — переписан help-блок в шаге 3 wizard'a на основании
«Инструккия M2M.pdf» (стр. 11, 16-19): явно расписано, что в режиме
ИШ подписывает сам ИШ (наш ключ в ИШ), а в режиме прямого ONYX —
bj-server. Таблица «что куда грузить»: УЦ МБ в mroot, УЦ НРД в
mroot+uRoot, наш сертификат в uMy только если без ИШ. Сертификаты
с Рутокена явно отмечены как «не грузить — сами появятся».
This commit is contained in:
fontvielle
2026-05-14 16:12:37 +03:00
parent 2142c4f586
commit f1e05c0ca3
4 changed files with 292 additions and 25 deletions
+25 -18
View File
@@ -74,6 +74,9 @@ func registerSetup(mux *http.ServeMux, a *admin, rc *RuntimeConfig, svc *Service
mux.HandleFunc("/admin/setup/cacerts", h.saveCACerts)
mux.HandleFunc("/admin/setup/cacerts/fetch", h.fetchCACertsNow)
// Копирование контейнера КриптоПро с флешки в локальное хранилище.
mux.HandleFunc("/admin/setup/crypto/copy-container", h.copyContainer)
// Пошаговый мастер настройки для нетехнических пользователей.
mux.HandleFunc("/admin/wizard", h.renderWizard)
}
@@ -84,6 +87,7 @@ type WizardData struct {
Step int
Settings Settings
Certs []cryptocli.Certificate
FlashContainers []FlashContainer
Flash string
CryptoProInstalled bool
CryptoProVersion string
@@ -106,10 +110,11 @@ func (h *setupHandlers) renderWizard(w http.ResponseWriter, r *http.Request) {
}
s := h.rc.Snapshot()
d := WizardData{
page: nowPage("Мастер настройки", "wizard"),
Settings: s,
Certs: h.listCertsForUI(),
Flash: r.URL.Query().Get("flash"),
page: nowPage("Мастер настройки", "wizard"),
Settings: s,
Certs: h.listCertsForUI(),
FlashContainers: scanFlashContainers(),
Flash: r.URL.Query().Get("flash"),
}
d.Done.Postgres = s.Postgres.DSN != ""
d.Done.Crypto = s.Crypto.Provider != "" && s.Crypto.Provider != "stub" && s.Crypto.JCPPath != ""
@@ -401,13 +406,14 @@ func (h *setupHandlers) checkCrypto(w http.ResponseWriter, r *http.Request) {
// SetupData — данные для шаблона admin_setup.html.
type SetupData struct {
page
Settings Settings
Readiness []Readiness
ReadyCount int
TotalCount int
Certificates []cryptocli.Certificate
Flash string
Error string
Settings Settings
Readiness []Readiness
ReadyCount int
TotalCount int
Certificates []cryptocli.Certificate
FlashContainers []FlashContainer
Flash string
Error string
}
func (h *setupHandlers) renderSetup(w http.ResponseWriter, _ *http.Request, flash string) {
@@ -420,13 +426,14 @@ func (h *setupHandlers) renderSetup(w http.ResponseWriter, _ *http.Request, flas
}
}
data := SetupData{
page: nowPage("Настройка", "setup"),
Settings: s,
Readiness: r,
ReadyCount: ready,
TotalCount: len(r),
Certificates: h.listCertsForUI(),
Flash: flash,
page: nowPage("Настройка", "setup"),
Settings: s,
Readiness: r,
ReadyCount: ready,
TotalCount: len(r),
Certificates: h.listCertsForUI(),
FlashContainers: scanFlashContainers(),
Flash: flash,
}
if errVal := errMsgFromQuery(_q(w)); errVal != "" {
data.Error = errVal