fb2fc15569
- Мастер смотрел не на итог установщика, а ставил галочки подряд: при «ошибке пересборки» и несформированном профиле ИШ показывал «Готово». Теперь этап с ошибкой — красный, причина — в сообщении, «Готово» — только когда справочник собран, профиль ИШ создан и ключ подписывает (оба пути — флешка и архив). - Подготовленная флешка: справочник на ней уже совместимый (пересобран при первой установке) — если пересборка не удалась, берётся как есть (gdbm cf9a5713; архивный НРД ce9a5713 — только с пересборкой). - В конце установки — проверка под igate: ключ подписывает проверочный документ профилем ИШ; не подписывает — понятная ошибка («вставлена ли флешка?»). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
178 lines
15 KiB
HTML
178 lines
15 KiB
HTML
{{/* Установка ключа Валидаты: загрузка архива НРД → носитель → справочник → проверка ИШ. Один и тот же блок —
|
||
на шаге «Ключ подписи» мастера и на отдельной странице /admin/setup/keywizard (данные — keyWizardData). */}}
|
||
{{define "keyWizRet"}}{{if .InWizard}}<input type="hidden" name="ret" value="wizard">{{end}}{{if .WantContour}}<input type="hidden" name="want" value="{{.WantContour}}">{{end}}{{end}}
|
||
|
||
{{define "keyWizBody"}}
|
||
{{$s := .State}}
|
||
|
||
<style>
|
||
.kw-tiles{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-top:6px}
|
||
.kw-tile{display:flex;gap:10px;align-items:flex-start;padding:12px 14px;border:1px solid var(--border);border-radius:12px;cursor:pointer;font-weight:400;margin:0}
|
||
.kw-tile:has(input:checked){border-color:var(--accent);background:var(--accent-weak)}
|
||
.kw-tile input{margin-top:3px;flex:none;width:auto}
|
||
.kw-tile b{display:block;font-size:14.5px}
|
||
.kw-tile small{display:block;color:var(--muted);font-size:13px;line-height:1.4;margin-top:3px}
|
||
.kw-panel{margin-top:16px}
|
||
.kw-drive{display:flex;gap:10px;align-items:flex-start;padding:10px;border:1px solid var(--border,#ddd);border-radius:8px;cursor:pointer;margin:0}
|
||
@media (max-width:600px){.kw-tiles{grid-template-columns:minmax(0,1fr)}}
|
||
</style>
|
||
{{/* ===== Лента шагов — когда путь выбран (флешка с ключом или новая флешка из архива) ===== */}}
|
||
{{if or $s.StagingID $s.Done}}
|
||
<div class="card">
|
||
<ol style="list-style:none;padding:0;margin:0;display:grid;gap:12px">
|
||
{{range $i, $step := $s.Steps}}
|
||
<li style="display:flex;gap:12px;align-items:flex-start">
|
||
<span style="flex:0 0 28px;height:28px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:13px;
|
||
{{if eq $step.Status "ok"}}background:var(--ok-weak);color:var(--ok)
|
||
{{else if eq $step.Status "error"}}background:var(--err-weak);color:var(--err)
|
||
{{else if eq $step.Status "active"}}background:var(--accent-weak);color:var(--accent)
|
||
{{else}}background:var(--surface-2,#eee);color:var(--muted,#999){{end}}">
|
||
{{if eq $step.Status "ok"}}✓{{else if eq $step.Status "error"}}{{else}}{{add $i 1}}{{end}}
|
||
</span>
|
||
<div style="flex:1">
|
||
<div style="font-weight:600">{{$step.Title}}</div>
|
||
{{if $step.Detail}}<div class="muted" style="font-size:13px;margin-top:2px">{{$step.Detail}}</div>{{end}}
|
||
</div>
|
||
</li>
|
||
{{end}}
|
||
</ol>
|
||
</div>
|
||
|
||
{{/* ===== Действие в зависимости от состояния ===== */}}
|
||
{{end}}
|
||
{{if $s.Done}}
|
||
<div class="card" style="background:var(--ok-weak)">
|
||
<h2>✓ Готово</h2>
|
||
<p>{{if $s.MediaDevice}}Ключ с флешки подключён к шлюзу НРД как есть и подписывает — флешка не менялась.{{else}}Ключ записан на флешку, справочник сертификатов сформирован, ключ подписывает.{{end}}</p>
|
||
{{if $s.Backup}}<p class="muted">Бэкап прежнего носителя: <code>{{$s.Backup}}</code></p>{{end}}
|
||
<div style="display:flex;gap:8px;margin-top:12px;flex-wrap:wrap">
|
||
{{if devOn}}<form method="post" action="/admin/setup/test-nsd" style="margin:0">
|
||
<input type="hidden" name="scenario" value="2001">
|
||
<button type="submit" class="btn btn-ok">→ Отправить тестовый документ роботу</button>
|
||
</form>{{else if not .InWizard}}<a href="/admin/wizard?step=8" class="btn btn-ok">→ Вернуться в мастер настройки</a> <a href="/admin/status" class="btn btn-secondary">Проверить подключения</a>{{end}}
|
||
<form method="post" action="/admin/setup/keywizard/reset" style="margin:0">{{template "keyWizRet" .}}
|
||
<button type="submit" class="btn btn-secondary">Установить ещё один ключ</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
{{else if and $s.StagingID $s.MediaDevice}}
|
||
{{/* ключ с подготовленной флешки — используется как есть, на флешку ничего не пишется */}}
|
||
<div class="card">
|
||
<h2>Шаг 2 — использовать ключ с флешки</h2>
|
||
<p class="muted">На флешке уже подготовленный ключ: <code>{{fallbackTpl $s.VDK "—"}}</code>{{if $s.MediaProfile}}, профиль <code>{{$s.MediaProfile}}</code>{{end}}.
|
||
bj подключит его к шлюзу НРД <b>как есть</b>: на флешку ничего не записывается — справочник для ИШ собирается на диске сервера, флешка подключается только для чтения.</p>
|
||
<form method="post" action="/admin/setup/keywizard/install" style="margin-top:12px;display:grid;gap:12px;max-width:640px"
|
||
onsubmit="this.querySelector('button[type=submit]').disabled=true;this.querySelector('button[type=submit]').textContent='Подключаю… (до пары минут)';">
|
||
{{template "keyWizRet" .}}
|
||
<input type="hidden" name="as_is" value="1">
|
||
<div>
|
||
<label style="font-weight:600;display:block;margin-bottom:6px">Для какого контура НРД этот ключ</label>
|
||
{{$c := .SuggestContour}}{{if not $c}}{{$c = .WantContour}}{{end}}{{if not $c}}{{$c = currentContour}}{{end}}
|
||
{{if .SuggestIssuer}}<p class="muted" style="font-size:12px;margin:0 0 4px">Сертификат от «{{.SuggestIssuer}}» — это {{if eq .SuggestContour "test3"}}тестовый{{else}}боевой{{end}} контур.</p>{{end}}
|
||
<label style="display:flex;gap:8px;align-items:center;font-weight:400"><input type="radio" name="contour" value="test3" style="width:auto" {{if ne $c "prod"}}checked{{end}}> Тестовый TEST3</label>
|
||
<label style="display:flex;gap:8px;align-items:center;font-weight:400"><input type="radio" name="contour" value="prod" style="width:auto" {{if eq $c "prod"}}checked{{end}}> Боевой</label>
|
||
</div>
|
||
<button type="submit" class="btn btn-ok">Использовать ключ с флешки</button>
|
||
</form>
|
||
<form method="post" action="/admin/setup/keywizard/reset" style="margin-top:8px">{{template "keyWizRet" .}}
|
||
<button type="submit" class="btn btn-secondary">Отмена</button>
|
||
</form>
|
||
</div>
|
||
{{else if $s.StagingID}}
|
||
{{/* Архив загружен — выбор флешки + запись */}}
|
||
<div class="card">
|
||
<h2>Шаг 2 — вставьте новую флешку и запишите ключ</h2>
|
||
<p class="muted">Архив распакован. Ключ: <code>{{fallbackTpl $s.VDK "—"}}</code>.
|
||
Вставьте в сервер чистую флешку — на неё запишется ключ и справочник сертификатов, затем bj
|
||
подключит её к шлюзу и перезапустит ИШ. Копия прежнего содержимого флешки сохраняется на сервере.
|
||
Не используйте флешку с рабочим ключом другого сервера.</p>
|
||
{{if not .Drives}}<p style="margin:10px 0 0">Флешка не найдена — вставьте её в сервер и <a href="javascript:location.reload()">обновите страницу</a>.</p>{{else}}
|
||
<form method="post" action="/admin/setup/keywizard/install" style="margin-top:12px;display:grid;gap:12px;max-width:640px"
|
||
onsubmit="this.querySelector('button[type=submit]').disabled=true;this.querySelector('button[type=submit]').textContent='Устанавливаю… (до нескольких минут)';">
|
||
{{template "keyWizRet" .}}
|
||
|
||
<div>
|
||
<label style="font-weight:600;display:block;margin-bottom:6px">Целевая флешка</label>
|
||
{{if .Drives}}
|
||
{{range $i, $d := .Drives}}
|
||
<label style="display:flex;gap:10px;align-items:flex-start;padding:10px;border:1px solid var(--border,#ddd);border-radius:8px;margin-bottom:8px;cursor:pointer">
|
||
<input type="radio" name="target_device" value="{{$d.Device}}" {{if $s.MediaDevice}}{{if eq $d.Device $s.MediaDevice}}checked{{end}}{{else if $d.IsKeymedia}}checked{{else if and (eq $i 0) (not (anyKeymedia $.Drives))}}checked{{end}} style="margin-top:3px">
|
||
<span>
|
||
<b>{{fallbackTpl $d.Model "USB-носитель"}}</b> · {{$d.Size}} · {{$d.FSType}}
|
||
{{if $d.Label}}· метка «{{$d.Label}}»{{end}}<br>
|
||
<span class="muted" style="font-size:12px">{{$d.Device}}{{if $d.Mountpoint}} · {{$d.Mountpoint}}{{end}}
|
||
{{if $d.IsKeymedia}}<b style="color:var(--accent)">← текущий ключевой носитель ИШ (рекомендуется)</b>{{end}}</span>
|
||
</span>
|
||
</label>
|
||
{{end}}
|
||
{{end}}
|
||
</div>
|
||
|
||
<div>
|
||
<label style="font-weight:600;display:block;margin-bottom:6px">Для какого контура НРД этот ключ</label>
|
||
{{$c := .SuggestContour}}{{if not $c}}{{$c = .WantContour}}{{end}}{{if not $c}}{{$c = currentContour}}{{end}}
|
||
{{if .SuggestIssuer}}<p class="muted" style="font-size:12px;margin:0 0 4px">В архиве сертификат от «{{.SuggestIssuer}}» — это {{if eq .SuggestContour "test3"}}тестовый{{else}}боевой{{end}} ключ.</p>{{end}}
|
||
<label style="display:flex;gap:8px;align-items:center;font-weight:400"><input type="radio" name="contour" value="test3" style="width:auto" {{if ne $c "prod"}}checked{{end}}> Тестовый TEST3 <span class="muted" style="font-size:12px">— сертификат от «Тестовый УЦ»</span></label>
|
||
<label style="display:flex;gap:8px;align-items:center;font-weight:400"><input type="radio" name="contour" value="prod" style="width:auto" {{if eq $c "prod"}}checked{{end}}> Боевой <span class="muted" style="font-size:12px">— выдан УЦ Московской биржи для работы</span></label>
|
||
<span class="muted" style="font-size:12px">У тестового и боевого контуров разные ключи: ключ подключается только к каналу ИШ своего контура.</span>
|
||
</div>
|
||
|
||
<div>
|
||
<label style="font-weight:600;display:block;margin-bottom:6px">Имя профиля в справочнике (необязательно)</label>
|
||
<input type="text" name="profile_name" value="{{$s.MediaProfile}}" placeholder="Авто из архива (напр. PrUser1046)" autocomplete="off"
|
||
pattern="[A-Za-z0-9_-]*" style="width:100%">
|
||
<span class="muted" style="font-size:12px">Пусто = имя берётся из архива автоматически.</span>
|
||
</div>
|
||
|
||
<button type="submit" class="btn btn-ok">Записать ключ на флешку</button>
|
||
</form>{{end}}
|
||
<form method="post" action="/admin/setup/keywizard/reset" style="margin-top:8px">{{template "keyWizRet" .}}
|
||
<button type="submit" class="btn btn-secondary">Отмена</button>
|
||
</form>
|
||
</div>
|
||
{{else}}
|
||
{{/* Начало: где ключ — на подготовленной флешке или в архиве НРД (тогда — на новую флешку) */}}
|
||
<div class="card">
|
||
<h2>Где ваш ключ?</h2>
|
||
<div class="kw-tiles">
|
||
<label class="kw-tile"><input type="radio" name="kwmode" value="media" {{if .Drives}}checked{{end}}><span><b>Подключить флешку с ключом</b><small>Флешка уже подготовлена (например, с другого сервера bj): bj найдёт на ней ключ и подключит к шлюзу как есть — ничего на неё не записывая.</small></span></label>
|
||
<label class="kw-tile"><input type="radio" name="kwmode" value="new" {{if not .Drives}}checked{{end}}><span><b>Сформировать ключ на новой флешке</b><small>Есть архив ключа от НРД и пароль: bj распакует его и запишет ключ на чистую флешку.</small></span></label>
|
||
</div>
|
||
|
||
<div class="kw-panel" id="kw-media">
|
||
{{if .Drives}}
|
||
<form method="post" action="/admin/setup/keywizard/from-media" style="display:grid;gap:8px;max-width:640px">
|
||
{{template "keyWizRet" .}}
|
||
<p class="muted" style="margin:0">Флешка с ключом:</p>
|
||
{{range $i, $d := .Drives}}
|
||
<label class="kw-drive">
|
||
<input type="radio" name="source_device" value="{{$d.Device}}" {{if eq $i 0}}checked{{end}} style="margin-top:3px;width:auto">
|
||
<span><b>{{fallbackTpl $d.Model "USB-носитель"}}</b> · {{$d.Size}} · {{$d.FSType}}{{if $d.Label}} · метка «{{$d.Label}}»{{end}}<br>
|
||
<span class="muted" style="font-size:12px">{{$d.Device}}{{if $d.IsKeymedia}} · <b style="color:var(--accent)">сейчас ключевой носитель ИШ</b>{{end}}</span></span>
|
||
</label>
|
||
{{end}}
|
||
<button type="submit" class="btn btn-ok" onclick="this.textContent='Ищу ключ на флешке…'">Подключить флешку</button>
|
||
</form>
|
||
{{else}}<p style="margin:0">Флешка не найдена — вставьте флешку с ключом в сервер и <a href="javascript:location.reload()">обновите страницу</a>.</p>{{end}}
|
||
</div>
|
||
|
||
<div class="kw-panel" id="kw-new" hidden>
|
||
<p class="muted" style="margin:0 0 8px">Шаг 1 — архив ключа от НРД (.7z) и пароль архива. Флешку bj попросит после распаковки.</p>
|
||
<form method="post" action="/admin/setup/keywizard/upload" enctype="multipart/form-data"
|
||
style="display:grid;gap:10px;max-width:560px">
|
||
{{template "keyWizRet" .}}
|
||
<input type="file" name="archive" accept=".7z,.zip" required>
|
||
<input type="password" name="password" placeholder="Пароль архива (например 11)" autocomplete="off">
|
||
<button type="submit" class="btn btn-ok">Загрузить и распаковать</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<script>(function(){
|
||
var r=document.querySelectorAll('input[name=kwmode]');
|
||
function sync(){ var m=document.querySelector('input[name=kwmode]:checked'); m=m?m.value:'media';
|
||
document.getElementById('kw-media').hidden=m!=='media'; document.getElementById('kw-new').hidden=m!=='new'; }
|
||
r.forEach(function(x){ x.addEventListener('change', sync); }); sync();
|
||
})();</script>
|
||
{{end}}
|
||
{{end}}
|