feat(admin): импорт сертификатов через UI + список сертификатов на токенах + URL контуров НРД
После реальной установки КриптоПро CSP добавлены следующие функциональности: cryptocli/client.go: - FindCertificates() — перечисляет CKO_CERTIFICATE объекты на всех подключенных слотах через PKCS#11, парсит X.509, извлекает CN, ИНН (OID 1.2.643.3.131.1.1), серийник, срок действия. Для каждого сертификата проверяет наличие парного приватного ключа (CKO_PRIVATE_KEY с тем же CKA_ID). - Тип Certificate с полями: SubjectCN, IssuerCN, INN, Serial, NotBefore, NotAfter, DER, HasPrivateKey, TokenLabel, SlotID. internal/lkgateway/setup.go: - handler importCertificate (POST /admin/setup/crypto/import-cert, multipart). Принимает .pfx/.p12 (с PIN) или .cer/.crt. Запускает certmgr -inst -pfx или -inst с выбором хранилища (uMy/mroot/uRoot). - listCertsForUI() — вспомогательный метод renderSetup для подгрузки актуального списка сертификатов с подключенных токенов при каждом открытии страницы. internal/lkgateway/web/templates/admin_setup.html: - секция «Сертификаты на токенах» с таблицей (Кому/Кем выдан/ИНН/срок/ токен/есть-ли-приватный-ключ). - форма «Импорт сертификата (.pfx/.cer/.crt)» с полями для PIN и выбора хранилища. - блок «Интеграционный шлюз НРД»: добавлен JS автозаполнения URL ONYX и контейнера по выбору профиля (guest/test3/prod × gost/rsa) — значения из DOC/Ссылки для доступа в тестовые контуры.pdf. internal/lkgateway/web/templates/admin_help_systems.html: - секция «Интеграционный шлюз НРД и контуры тестирования» дополнена полной таблицей URL-ов сервисов GUEST/TEST3 (ONYX, Agate, DCS, Единый кабинет, Корпоративные действия). IP gost.nsd.ru для настройки межсетевого экрана. - новая секция «Сертификаты УЦ НРД (для проверки квитанций)» с пошаговой инструкцией: куда импортировать корневой сертификат УЦ НРД, куда промежуточные, куда наши сертификаты из стороннего УЦ. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -89,6 +89,42 @@
|
||||
<button type="submit" class="btn" style="background:var(--accent);color:white;border:none;padding:8px 16px;border-radius:4px">Загрузить и установить</button>
|
||||
</form>
|
||||
|
||||
<hr style="margin:18px 0;border:none;border-top:1px solid var(--border)">
|
||||
<h3 style="font-size:14px;margin:0 0 8px">Сертификаты на токенах</h3>
|
||||
{{if .Certificates}}
|
||||
<table>
|
||||
<thead><tr><th>Кому</th><th>Кем выдан</th><th>ИНН</th><th>Действителен</th><th>Токен</th><th>Приватный ключ</th></tr></thead>
|
||||
<tbody>
|
||||
{{range .Certificates}}
|
||||
<tr>
|
||||
<td>{{.SubjectCN}}</td>
|
||||
<td class="muted">{{.IssuerCN}}</td>
|
||||
<td><code>{{.INN}}</code></td>
|
||||
<td class="muted">до {{.NotAfter.Format "02.01.2006"}}</td>
|
||||
<td class="muted">«{{.TokenLabel}}» (slot {{.SlotID}})</td>
|
||||
<td>{{if .HasPrivateKey}}<span style="color:var(--ok)">есть</span>{{else}}<span class="muted">нет</span>{{end}}</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}
|
||||
<p class="muted">На подключенных токенах сертификатов не найдено. Загрузите .pfx ниже или подключите Рутокен с сертификатом.</p>
|
||||
{{end}}
|
||||
|
||||
<hr style="margin:18px 0;border:none;border-top:1px solid var(--border)">
|
||||
<h3 style="font-size:14px;margin:0 0 8px">Импорт сертификата (.pfx / .cer / .crt)</h3>
|
||||
<p class="muted">PFX с приватным ключом (с PIN) — для серверной подписи и подписи оператора. CER/CRT без приватного ключа — для проверки чужих подписей (например, сертификаты УЦ НРД для проверки квитанций). Подробно — <a href="/admin/help/cryptopro">/admin/help/cryptopro</a>.</p>
|
||||
<form method="post" action="/admin/setup/crypto/import-cert" enctype="multipart/form-data" style="margin-top:8px;display:grid;gap:8px;grid-template-columns:auto auto auto auto;align-items:center">
|
||||
<input type="file" name="cert" accept=".pfx,.p12,.cer,.crt" required style="padding:6px;background:var(--bg);border:1px solid var(--border);color:var(--text);border-radius:4px">
|
||||
<input type="text" name="pin" placeholder="PIN (только для .pfx/.p12)" style="padding:6px;background:var(--bg);border:1px solid var(--border);color:var(--text);border-radius:4px;font-family:monospace">
|
||||
<select name="store" style="padding:6px;background:var(--bg);border:1px solid var(--border);color:var(--text);border-radius:4px">
|
||||
<option value="uMy">uMy — личный (для подписи)</option>
|
||||
<option value="mroot">mroot — корневой УЦ (для проверки)</option>
|
||||
<option value="uRoot">uRoot — промежуточные УЦ</option>
|
||||
</select>
|
||||
<button type="submit" class="btn" style="background:var(--accent);color:white;border:none;padding:8px 16px;border-radius:4px">Импортировать</button>
|
||||
</form>
|
||||
|
||||
<hr style="margin:18px 0;border:none;border-top:1px solid var(--border)">
|
||||
<h3 style="font-size:14px;margin:0 0 8px">Активация лицензии</h3>
|
||||
<form method="post" action="/admin/setup/crypto/activate" style="margin-top:6px;display:flex;gap:8px;align-items:center;flex-wrap:wrap">
|
||||
@@ -101,34 +137,60 @@
|
||||
|
||||
<!-- nsd-adapter / ИШ НРД -->
|
||||
<div class="card">
|
||||
<h2><span class="dot {{if .Settings.NSD.IGWBaseURL}}ok{{else}}err{{end}}"></span>Интеграционный шлюз НРД</h2>
|
||||
<h2><span class="dot {{if .Settings.NSD.IGWBaseURL}}ok{{else}}err{{end}}"></span>Интеграционный шлюз НРД (ИШ)</h2>
|
||||
<p class="muted">{{if not .Settings.NSD.IGWBaseURL}}Сейчас <code>mock-режим</code> — Decision эмитируется через 3 секунды после Send.{{else}}Профиль <code>{{.Settings.NSD.Profile}}</code>, ИШ <code>{{.Settings.NSD.IGWBaseURL}}</code>.{{end}}</p>
|
||||
<p class="muted">Подключение к стендам: <a href="/admin/help/systems">/admin/help/systems</a> — там полная таблица URL контуров GUEST/TEST3/PROD и инструкция по установке ИШ. Дистрибутив ИШ скачивается с <code>www.nsd.ru/workflow/system/programs/#0-widget-faq-0-4</code>.</p>
|
||||
<details {{if not .Settings.NSD.IGWBaseURL}}open{{end}}>
|
||||
<summary style="cursor:pointer;color:var(--accent);font-size:13px">Изменить параметры ИШ</summary>
|
||||
<form method="post" action="/admin/setup/nsd" style="margin-top:12px;display:grid;gap:10px">
|
||||
<div class="form-row" style="display:grid;grid-template-columns:200px 1fr;gap:12px;align-items:center">
|
||||
<label>Профиль</label>
|
||||
<select name="profile" style="padding:8px;background:var(--bg);border:1px solid var(--border);color:var(--text);border-radius:4px">
|
||||
<option value="" {{if eq .Settings.NSD.Profile ""}}selected{{end}}>— mock (демо) —</option>
|
||||
<option value="guest-gost" {{if eq .Settings.NSD.Profile "guest-gost"}}selected{{end}}>guest-gost</option>
|
||||
<option value="guest-rsa" {{if eq .Settings.NSD.Profile "guest-rsa"}}selected{{end}}>guest-rsa</option>
|
||||
<option value="test3-gost" {{if eq .Settings.NSD.Profile "test3-gost"}}selected{{end}}>test3-gost</option>
|
||||
<option value="test3-rsa" {{if eq .Settings.NSD.Profile "test3-rsa"}}selected{{end}}>test3-rsa</option>
|
||||
<option value="prod-gost" {{if eq .Settings.NSD.Profile "prod-gost"}}selected{{end}}>prod-gost</option>
|
||||
<option value="prod-rsa" {{if eq .Settings.NSD.Profile "prod-rsa"}}selected{{end}}>prod-rsa</option>
|
||||
<select name="profile" id="nsd-profile" style="padding:8px;background:var(--bg);border:1px solid var(--border);color:var(--text);border-radius:4px">
|
||||
<option value="" {{if eq .Settings.NSD.Profile ""}}selected{{end}}>— mock (демо без реального ИШ) —</option>
|
||||
<option value="guest-gost" {{if eq .Settings.NSD.Profile "guest-gost"}}selected{{end}}>guest-gost — контур GUEST, ГОСТ ключи</option>
|
||||
<option value="guest-rsa" {{if eq .Settings.NSD.Profile "guest-rsa"}}selected{{end}}>guest-rsa — контур GUEST, RSA ключи</option>
|
||||
<option value="test3-gost" {{if eq .Settings.NSD.Profile "test3-gost"}}selected{{end}}>test3-gost — контур TEST3, ГОСТ ключи</option>
|
||||
<option value="test3-rsa" {{if eq .Settings.NSD.Profile "test3-rsa"}}selected{{end}}>test3-rsa — контур TEST3, RSA ключи</option>
|
||||
<option value="prod-gost" {{if eq .Settings.NSD.Profile "prod-gost"}}selected{{end}}>prod-gost — продуктивный, ГОСТ</option>
|
||||
<option value="prod-rsa" {{if eq .Settings.NSD.Profile "prod-rsa"}}selected{{end}}>prod-rsa — продуктивный, RSA</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row" style="display:grid;grid-template-columns:200px 1fr;gap:12px;align-items:center">
|
||||
<label>URL ИШ НРД</label>
|
||||
<input type="text" name="igw_base_url" value="{{.Settings.NSD.IGWBaseURL}}" placeholder="http://localhost:8080 (адрес ИШ НРД)" style="padding:8px;background:var(--bg);border:1px solid var(--border);color:var(--text);border-radius:4px">
|
||||
<label>URL ONYX (WSL) НРД</label>
|
||||
<input type="text" name="igw_base_url" id="nsd-url" value="{{.Settings.NSD.IGWBaseURL}}" placeholder="будет заполнено по профилю" style="padding:8px;background:var(--bg);border:1px solid var(--border);color:var(--text);border-radius:4px">
|
||||
</div>
|
||||
<div class="form-row" style="display:grid;grid-template-columns:200px 1fr;gap:12px;align-items:center">
|
||||
<label>Ключевой контейнер</label>
|
||||
<input type="text" name="key_container" value="{{.Settings.NSD.KeyContainer}}" placeholder="GUEST_GOST_CONTAINER" style="padding:8px;background:var(--bg);border:1px solid var(--border);color:var(--text);border-radius:4px">
|
||||
<input type="text" name="key_container" id="nsd-container" value="{{.Settings.NSD.KeyContainer}}" placeholder="GUEST_GOST_CONTAINER (или ваш контейнер УЦ НРД)" style="padding:8px;background:var(--bg);border:1px solid var(--border);color:var(--text);border-radius:4px">
|
||||
</div>
|
||||
<p class="muted">При сохранении выполняется GET <code>{URL}/healthz</code>. Пустой URL = вернуться к mock-режиму.</p>
|
||||
<p class="muted">При смене профиля URL ONYX автозаполнится по таблице НРД (из <code>DOC/Ссылки для доступа в тестовые контуры.pdf</code>). При сохранении проверяется доступность URL.</p>
|
||||
<button type="submit" class="btn" style="background:var(--accent);color:white;border:none;padding:8px 16px;border-radius:4px">Сохранить и проверить</button>
|
||||
</form>
|
||||
<script>
|
||||
// Автозаполнение URL ONYX и дефолтного контейнера по выбранному профилю.
|
||||
(function() {
|
||||
var urls = {
|
||||
"guest-gost": ["https://gost-gt.nsd.ru/onyx-ms/OnyxEdoWSService/OnyxEdo", "GUEST_GOST_CONTAINER"],
|
||||
"guest-rsa": ["https://rsa-gt.nsd.ru/onyx-ms/OnyxEdoWSService/OnyxEdo", "GUEST_RSA_CONTAINER"],
|
||||
"test3-gost": ["https://gost-t3.nsd.ru/onyx-ms/OnyxEdoWSService/OnyxEdo", "TEST3_GOST_CONTAINER"],
|
||||
"test3-rsa": ["https://rsa-t3.nsd.ru/onyx-ms/OnyxEdoWSService/OnyxEdo", "TEST3_RSA_CONTAINER"],
|
||||
"prod-gost": ["https://gost.nsd.ru/onyx-ms/OnyxEdoWSService/OnyxEdo", "PROD_GOST_CONTAINER"],
|
||||
"prod-rsa": ["https://rsa.nsd.ru/onyx-ms/OnyxEdoWSService/OnyxEdo", "PROD_RSA_CONTAINER"]
|
||||
};
|
||||
var profile = document.getElementById("nsd-profile");
|
||||
var urlInput = document.getElementById("nsd-url");
|
||||
var contInput = document.getElementById("nsd-container");
|
||||
profile.addEventListener("change", function() {
|
||||
var p = profile.value;
|
||||
if (urls[p]) {
|
||||
if (!urlInput.value || confirm("Заменить URL и контейнер на дефолт для профиля " + p + "?")) {
|
||||
urlInput.value = urls[p][0];
|
||||
contInput.value = urls[p][1];
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user