82b3186b95
В карточке «СКЗИ» страницы /admin/setup добавлены два новых блока: 1. «Установка КриптоПро CSP» — multipart-форма с input type=file. Принимает .tar/.tgz/.tar.gz/.rpm (формат с cryptopro.ru). После загрузки на сервер (лимит 256 МБ): - сохраняет архив в /tmp/bj-cryptopro/ - распаковывает (tar -xzf или tar -xf) - находит все .rpm в распакованной директории - выполняет sudo rpm -Uvh --replacepkgs --nosignature на найденные пакеты - возвращает результат с количеством установленных пакетов и выводом rpm 2. «Активация лицензии» — поле для ввода серийника и кнопка. Вызывает /opt/cprocsp/sbin/amd64/cpconfig -license -set <серийник>. Если cpconfig не найден — показывает подсказку про /admin/help/cryptopro. После успеха сохраняет серийник в runtime-конфиге. internal/lkgateway/setup.go: - handler installCryptoPro (multipart form, parse, untar, find rpms, sudo rpm) - handler activateLicense (cpconfig -license -set, сохранение в RuntimeConfig) - общие хелперы runCmd / runCmdInDir для exec через context internal/lkgateway/web/templates/admin_setup.html: - секция «Установка КриптоПро CSP» с формой загрузки - секция «Активация лицензии» с полем + кнопкой - ссылки на /admin/help/cryptopro и cryptopro.ru/products/csp/downloads Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
173 lines
16 KiB
HTML
173 lines
16 KiB
HTML
{{define "content"}}
|
||
{{if .Flash}}<div style="padding:12px 16px;background:rgba(63,191,108,0.1);border-left:3px solid var(--ok);border-radius:4px;margin-bottom:16px">{{.Flash}}</div>{{end}}
|
||
|
||
<div class="card">
|
||
<h2>Готовность системы: {{.ReadyCount}} из {{.TotalCount}}</h2>
|
||
<div style="display:flex;gap:8px;margin-top:8px">
|
||
{{range .Readiness}}
|
||
<div style="flex:1;text-align:center;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:4px">
|
||
<span class="dot {{if .Configured}}ok{{else}}err{{end}}"></span>
|
||
<strong>{{.Name}}</strong><br>
|
||
<span class="muted" style="font-size:11px">{{if .Configured}}настроено{{else}}не настроено{{end}}</span>
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- PostgreSQL -->
|
||
<div class="card">
|
||
<h2><span class="dot {{if .Settings.Postgres.DSN}}ok{{else}}err{{end}}"></span>PostgreSQL</h2>
|
||
<p class="muted">Принимающая БД (fansy-store) и журнал сделок m2m-core. Сейчас:
|
||
{{if .Settings.Postgres.DSN}}<code>настроено</code>{{else}}<code>in-memory</code> (M2-демо){{end}}.</p>
|
||
<details {{if not .Settings.Postgres.DSN}}open{{end}}>
|
||
<summary style="cursor:pointer;color:var(--accent);font-size:13px">Изменить параметры подключения</summary>
|
||
<form method="post" action="/admin/setup/postgres" style="margin-top:12px">
|
||
<div class="form-row" style="display:grid;grid-template-columns:200px 1fr;gap:12px;align-items:center">
|
||
<label>DSN</label>
|
||
<input type="text" name="dsn" value="{{.Settings.Postgres.DSN}}" placeholder="postgres://bj:secret@127.0.0.1:5432/bj?sslmode=disable" style="width:100%;padding:8px;background:var(--bg);border:1px solid var(--border);color:var(--text);border-radius:4px">
|
||
</div>
|
||
<p class="muted" style="margin-top:8px">При сохранении выполняется Ping. Если драйвер pgx ещё не подключён в коде, тест упадёт — это ожидаемо до M2-шага-3.</p>
|
||
<button type="submit" class="btn" style="background:var(--accent);color:white;border:none;padding:8px 16px;border-radius:4px;margin-top:8px">Сохранить и проверить</button>
|
||
</form>
|
||
</details>
|
||
</div>
|
||
|
||
<!-- СКЗИ через PKCS#11: КриптоПро CSP / Рутокен / Валидата / ViPNet -->
|
||
<div class="card">
|
||
<h2><span class="dot {{if and .Settings.Crypto.JCPPath .Settings.Crypto.LicenseKey}}ok{{else}}err{{end}}"></span>СКЗИ (КриптоПро CSP, Рутокен и др. через PKCS#11)</h2>
|
||
<p class="muted">Go-клиент подключается к СКЗИ напрямую через стандартный PKCS#11 интерфейс. Поддерживаются КриптоПро CSP, Рутокен ЭЦП 2.0, Валидата, ViPNet — один клиент, разные .so модули. Подробно — раздел <a href="/admin/help/cryptopro">«КриптоПро»</a> в инструкциях.</p>
|
||
<table style="margin-bottom:12px">
|
||
<tr><td style="width:220px" class="muted">Текущий провайдер</td><td><code>{{.Settings.Crypto.Provider}}</code></td></tr>
|
||
<tr><td class="muted">Путь к модулю PKCS#11</td><td><code>{{if .Settings.Crypto.JCPPath}}{{.Settings.Crypto.JCPPath}}{{else}}—{{end}}</code></td></tr>
|
||
<tr><td class="muted">UDS-сокет (legacy)</td><td><code>{{.Settings.Crypto.SocketPath}}</code></td></tr>
|
||
<tr><td class="muted">Лицензия введена</td><td>{{if .Settings.Crypto.LicenseKey}}<span style="color:var(--ok)">да</span>{{else}}<span style="color:var(--err)">нет</span>{{end}}</td></tr>
|
||
</table>
|
||
<details {{if or (eq .Settings.Crypto.Provider "stub") (not .Settings.Crypto.JCPPath)}}open{{end}}>
|
||
<summary style="cursor:pointer;color:var(--accent);font-size:13px">Изменить параметры СКЗИ</summary>
|
||
<form method="post" action="/admin/setup/crypto" style="margin-top:12px;display:grid;gap:10px">
|
||
<div class="form-row" style="display:grid;grid-template-columns:220px 1fr;gap:12px;align-items:center">
|
||
<label>Провайдер СКЗИ</label>
|
||
<select name="provider" style="padding:8px;background:var(--bg);border:1px solid var(--border);color:var(--text);border-radius:4px">
|
||
<option value="stub" {{if eq .Settings.Crypto.Provider "stub"}}selected{{end}}>stub — без криптографии (демо)</option>
|
||
<option value="cryptopro" {{if eq .Settings.Crypto.Provider "cryptopro"}}selected{{end}}>КриптоПро CSP (через PKCS#11)</option>
|
||
<option value="rutoken" {{if eq .Settings.Crypto.Provider "rutoken"}}selected{{end}}>Рутокен ЭЦП 2.0 (для подписи оператора)</option>
|
||
<option value="validata" {{if eq .Settings.Crypto.Provider "validata"}}selected{{end}}>Валидата</option>
|
||
<option value="vipnet" {{if eq .Settings.Crypto.Provider "vipnet"}}selected{{end}}>ViPNet</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-row" style="display:grid;grid-template-columns:220px 1fr;gap:12px;align-items:center">
|
||
<label>Путь к модулю PKCS#11</label>
|
||
<input type="text" name="jcp_path" value="{{.Settings.Crypto.JCPPath}}" placeholder="/opt/cprocsp/lib/amd64/libcppkcs11.so" 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:220px 1fr;gap:12px;align-items:center">
|
||
<label>UDS-сокет (legacy)</label>
|
||
<input type="text" name="socket_path" value="{{.Settings.Crypto.SocketPath}}" placeholder="/run/bj/crypto.sock (только для совместимости со старым Java crypto-service)" 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:220px 1fr;gap:12px;align-items:flex-start">
|
||
<label>Серийный номер лицензии</label>
|
||
<textarea name="license_key" rows="3" placeholder="XXXX-XXXXX-XXXXX-XXXXX-XXXXX (серийный номер КриптоПро CSP)" style="padding:8px;background:var(--bg);border:1px solid var(--border);color:var(--text);border-radius:4px;font-family:monospace;font-size:12px">{{.Settings.Crypto.LicenseKey}}</textarea>
|
||
</div>
|
||
<p class="muted">
|
||
<strong>КриптоПро CSP</strong>: установить пакеты <code>rpm -i cprocsp-*.rpm</code>, активировать лицензию командой <code>cpconfig -license -set XXXX-...</code>, указать <code>/opt/cprocsp/lib/amd64/libcppkcs11.so</code>.<br>
|
||
<strong>Рутокен</strong>: подключить токен USB, указать <code>/usr/lib64/librtpkcs11ecp.so</code>.<br>
|
||
Полная инструкция: <a href="/admin/help/cryptopro">/admin/help/cryptopro</a>. При сохранении проверим, что файл модуля существует.
|
||
</p>
|
||
<div style="display:flex;gap:8px">
|
||
<button type="submit" class="btn" style="background:var(--accent);color:white;border:none;padding:8px 16px;border-radius:4px">Сохранить</button>
|
||
</div>
|
||
</form>
|
||
<form method="post" action="/admin/setup/crypto/check" style="margin-top:12px">
|
||
<button type="submit" class="btn" style="background:var(--border);color:var(--text);border:none;padding:8px 16px;border-radius:4px">Проверить подключение СКЗИ</button>
|
||
<span class="muted" style="margin-left:8px">Загрузит PKCS#11 модуль, опросит список токенов, покажет результат сверху страницы.</span>
|
||
</form>
|
||
|
||
<hr style="margin:18px 0;border:none;border-top:1px solid var(--border)">
|
||
<h3 style="font-size:14px;margin:0 0 8px">Установка КриптоПро CSP</h3>
|
||
<p class="muted">Дистрибутив с <a href="https://www.cryptopro.ru/products/csp/downloads" target="_blank" rel="noopener">cryptopro.ru</a> (например, <code>linux-amd64.tgz</code> или <code>linux-amd64.tar</code> для РЕД ОС/ALT/ROSA). Загрузите файл здесь — он будет распакован и установлен через <code>sudo rpm -Uvh</code>. Установка длится ~30 секунд.</p>
|
||
<form method="post" action="/admin/setup/crypto/install" enctype="multipart/form-data" style="margin-top:12px;display:flex;gap:8px;align-items:center;flex-wrap:wrap">
|
||
<input type="file" name="dist" accept=".tar,.tgz,.gz,.rpm" required style="padding:6px;background:var(--bg);border:1px solid var(--border);color:var(--text);border-radius:4px;flex:1;min-width:300px">
|
||
<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">
|
||
<input type="text" name="license_key" value="{{.Settings.Crypto.LicenseKey}}" placeholder="XXXX-XXXXX-XXXXX-XXXXX-XXXXX (серийный номер КриптоПро CSP)" style="padding:8px;background:var(--bg);border:1px solid var(--border);color:var(--text);border-radius:4px;font-family:monospace;font-size:12px;min-width:340px">
|
||
<button type="submit" class="btn" style="background:var(--ok);color:#0a0f1a;border:none;padding:8px 16px;border-radius:4px;font-weight:600">Активировать лицензию</button>
|
||
</form>
|
||
<p class="muted" style="margin-top:8px">Вызовет <code>cpconfig -license -set</code> и сохранит серийник. Если КриптоПро CSP ещё не установлен — покажет инструкцию.</p>
|
||
</details>
|
||
</div>
|
||
|
||
<!-- nsd-adapter / ИШ НРД -->
|
||
<div class="card">
|
||
<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>
|
||
<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>
|
||
</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">
|
||
</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">
|
||
</div>
|
||
<p class="muted">При сохранении выполняется GET <code>{URL}/healthz</code>. Пустой URL = вернуться к mock-режиму.</p>
|
||
<button type="submit" class="btn" style="background:var(--accent);color:white;border:none;padding:8px 16px;border-radius:4px">Сохранить и проверить</button>
|
||
</form>
|
||
</details>
|
||
</div>
|
||
|
||
<!-- LK callback -->
|
||
<div class="card">
|
||
<h2><span class="dot {{if .Settings.LK.CallbackURL}}ok{{else}}err{{end}}"></span>Callback в ЛК</h2>
|
||
<p class="muted">{{if .Settings.LK.CallbackURL}}Callback URL: <code>{{.Settings.LK.CallbackURL}}</code>{{else}}Сейчас используется встроенный lk-emulator (он сам зарегистрировал свой адрес при старте).{{end}}</p>
|
||
<details {{if not .Settings.LK.CallbackURL}}open{{end}}>
|
||
<summary style="cursor:pointer;color:var(--accent);font-size:13px">Указать URL реального ЛК</summary>
|
||
<form method="post" action="/admin/setup/lk" style="margin-top:12px">
|
||
<div class="form-row" style="display:grid;grid-template-columns:200px 1fr;gap:12px;align-items:center">
|
||
<label>Callback URL</label>
|
||
<input type="text" name="callback_url" value="{{.Settings.LK.CallbackURL}}" placeholder="http://lk.example.com" style="width:100%;padding:8px;background:var(--bg);border:1px solid var(--border);color:var(--text);border-radius:4px">
|
||
</div>
|
||
<p class="muted" style="margin-top:8px">URL до базового хоста ЛК (без /api). При сохранении выполняется GET <code>{URL}/healthz</code>.</p>
|
||
<button type="submit" class="btn" style="background:var(--accent);color:white;border:none;padding:8px 16px;border-radius:4px;margin-top:8px">Сохранить и проверить</button>
|
||
</form>
|
||
</details>
|
||
</div>
|
||
|
||
<!-- Тестовый прогон -->
|
||
<div class="card">
|
||
<h2>Тестовый прогон сквозной заявки</h2>
|
||
<p class="muted">Создаст заявку с предзаполненными данными (инвестор Иванов И.И., 1500 акций Газпрома, ИИС T03), отправит её через всю цепочку и дождётся финального статуса. Если ИШ НРД настроен — пойдёт в реальный ИШ; иначе через mock с задержкой 3 сек.</p>
|
||
<form method="post" action="/admin/setup/test-run" style="margin-top:12px">
|
||
<button type="submit" class="btn" style="background:var(--accent);color:white;border:none;padding:10px 20px;border-radius:4px;font-weight:600">Запустить тестовую заявку</button>
|
||
</form>
|
||
{{if .Settings.LastTest}}
|
||
<div style="margin-top:16px;padding:12px;background:var(--bg);border:1px solid var(--border);border-radius:4px">
|
||
<strong>Последний прогон:</strong>
|
||
<table style="margin-top:8px">
|
||
<tr><td style="width:160px" class="muted">Статус</td><td>{{if .Settings.LastTest.OK}}<span style="color:var(--ok)">✓ успешно</span>{{else}}<span style="color:var(--err)">✗ не прошёл</span>{{end}}</td></tr>
|
||
<tr><td class="muted">Финальный FSM-статус</td><td><code>{{.Settings.LastTest.FinalStatus}}</code></td></tr>
|
||
<tr><td class="muted">ClaimID</td><td><code>{{.Settings.LastTest.ClaimID}}</code> {{if .Settings.LastTest.ClaimID}}<a href="/admin/claims/{{.Settings.LastTest.ClaimID}}">→ открыть карточку</a>{{end}}</td></tr>
|
||
<tr><td class="muted">Когда</td><td>{{.Settings.LastTest.StartedAt.Format "02.01.2006 15:04:05"}} — длительность {{.Settings.LastTest.FinishedAt.Sub .Settings.LastTest.StartedAt}}</td></tr>
|
||
<tr><td class="muted">Сообщение</td><td>{{.Settings.LastTest.Message}}</td></tr>
|
||
</table>
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
{{end}}
|