Статус: карточка ключа организации — контур и пометка «ИСТЁК»; SMB-пароль папок шлюза — генерация и показ
Ключ организации на странице «Статус» теперь строится из своего сертификата в справочнике активного профиля ИШ (ownStoreCerts), включая истёкший: карточка показывает владельца, издателя, контур (боевой/тестовый) и срок. Истёкший ключ виден явной пометкой «ИСТЁК» и отдельным заголовком, а не маскируется под «ключ не подключён». Показать владельца ДО установки ключа нельзя — сертификата нет в файлах флешки, он появляется в справочнике профиля только после установки. Папки шлюза по сети (простой режим): кнопка «Сгенерировать» создаёт надёжный пароль (16 символов, crypto.getRandomValues) прямо в поле, поле теперь видимое; после сохранения пароль показывается один раз с кнопкой «Скопировать» — записать, так как позже bj его не покажет. Пустое поле по-прежнему оставляет прежний пароль при повторном сохранении. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
This commit is contained in:
@@ -68,17 +68,21 @@ var templateFuncs = template.FuncMap{
|
||||
if globalRC == nil {
|
||||
return nil
|
||||
}
|
||||
own := ownValidCerts(storeCertsForUI(globalRC.Snapshot()))
|
||||
// Свой сертификат из справочника активного профиля ИШ — включая истёкший,
|
||||
// чтобы «Статус» показал владельца и пометку «ИСТЁК», а не просто «не подключён».
|
||||
own := ownStoreCerts(globalRC.Snapshot())
|
||||
if len(own) == 0 {
|
||||
return nil
|
||||
}
|
||||
c := own[0]
|
||||
for _, x := range own[1:] { // самый долгий — тот, что в работе
|
||||
if x.NotAfter.After(c.NotAfter) {
|
||||
c = x
|
||||
c, ca := own[0], storeNotAfter(own[0])
|
||||
for _, x := range own[1:] { // самый долгий срок — тот ключ, что в работе
|
||||
if t := storeNotAfter(x); t.After(ca) {
|
||||
c, ca = x, t
|
||||
}
|
||||
}
|
||||
return map[string]any{"Owner": c.SubjectCN, "Issuer": c.IssuerCN, "Until": c.NotAfter.Format("02.01.2006"), "Days": certDaysLeft(c.NotAfter)}
|
||||
contour := map[string]string{"prod": "боевой", "guest": "гостевой", "test3": "тестовый"}[contourOf(currentNSDProfile())]
|
||||
return map[string]any{"Owner": c.SubjectCN, "Issuer": c.IssuerCN, "Until": ca.Format("02.01.2006"),
|
||||
"Days": certDaysLeft(ca), "Expired": !ca.IsZero() && ca.Before(time.Now()), "Contour": contour}
|
||||
},
|
||||
// СКЗИ готова: Валидата установлена и ключ организации подключён (как шаги мастера «Валидата» и «Ключ»)
|
||||
"cryptoReady": func() bool {
|
||||
|
||||
@@ -94,8 +94,9 @@
|
||||
<label style="display:flex;gap:8px;align-items:center;font-weight:500;margin:12px 0 0"><input type="checkbox" name="enabled" style="width:auto"> Открыть папки шлюза по сети</label>
|
||||
<div id="ig-sh-simple" class="ig-sh-grid">
|
||||
<label class="f">Логин<input name="user" value="igate-share" autocomplete="off" spellcheck="false"></label>
|
||||
<label class="f">Пароль (от 8 символов)<input name="password" type="password" autocomplete="new-password" spellcheck="false" placeholder="пусто — прежний"></label>
|
||||
<label class="f">Пароль (от 8 символов)<span style="display:flex;gap:6px"><input name="password" type="text" autocomplete="new-password" spellcheck="false" placeholder="пусто — прежний" style="flex:1;min-width:0"><button type="button" class="btn sm" id="ig-sh-gen" title="Создать надёжный пароль">Сгенерировать</button></span></label>
|
||||
</div>
|
||||
<small id="ig-sh-pwnote" class="muted" style="display:block;font-size:12.5px;margin-top:6px">Пароль вводят в Windows при первом открытии папок. Запишите его: bj передаёт пароль в Samba и показать позже не сможет. Пустое поле при повторном сохранении оставляет прежний пароль.</small>
|
||||
<div id="ig-sh-domain" hidden>
|
||||
<div id="ig-sh-access" class="muted" style="font-size:13px;margin-top:10px"></div>
|
||||
<div id="ig-sh-join" hidden style="margin-top:10px">
|
||||
@@ -214,6 +215,13 @@
|
||||
}
|
||||
function load(){ return fetch('/admin/setup/igate/share',{cache:'no-store'}).then(function(r){return r.json()}).then(show).catch(function(){ stl.textContent='Состояние не получено.'; }); }
|
||||
f.addEventListener('change',function(e){ if(e.target.name==='mode') sync(); });
|
||||
var genbtn=document.getElementById('ig-sh-gen');
|
||||
if(genbtn) genbtn.addEventListener('click',function(){
|
||||
var cs='ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789', a=new Uint32Array(16), s='';
|
||||
crypto.getRandomValues(a); for(var i=0;i<16;i++) s+=cs[a[i]%cs.length];
|
||||
f.password.type='text'; f.password.value=s; f.password.focus(); f.password.select();
|
||||
o.innerHTML='<span class="muted">Пароль создан — запишите его перед сохранением.</span>';
|
||||
});
|
||||
f.addEventListener('submit',function(e){ e.preventDefault();
|
||||
var p=new URLSearchParams(), url='/admin/setup/igate/share', d=mode()==='domain';
|
||||
if(d && !cur.joined){
|
||||
@@ -225,7 +233,13 @@
|
||||
if(!d){ p.set('user',f.user.value.trim()); p.set('password',f.password.value); }
|
||||
o.textContent='Сохраняю… (первый раз — установка Samba, до пары минут)';
|
||||
}
|
||||
post(url,p).then(function(r){ o.innerHTML=r.ok?ok(r.output):bad(r.error); f.password.value=''; f.adminpw.value=''; return load(); }).catch(function(){ o.innerHTML=bad('не сохранено'); }); });
|
||||
var pwSet=(!d)?f.password.value:'';
|
||||
post(url,p).then(function(r){
|
||||
if(r.ok){ o.innerHTML=ok(r.output)+(pwSet?' <b>Пароль:</b> <code>'+esc(pwSet)+'</code> <button type="button" class="btn sm" data-copy="'+esc(pwSet)+'">Скопировать</button> — запишите, посмотреть позже нельзя.':'');
|
||||
var cb=o.querySelector('[data-copy]'); if(cb) cb.onclick=function(){ (window.bjCopy||function(t){navigator.clipboard&&navigator.clipboard.writeText(t)})(cb.dataset.copy); cb.textContent='Скопировано ✓'; };
|
||||
} else o.innerHTML=bad(r.error);
|
||||
f.password.value=''; f.adminpw.value=''; return load();
|
||||
}).catch(function(){ o.innerHTML=bad('не сохранено'); }); });
|
||||
load();
|
||||
})();
|
||||
var st=null;
|
||||
|
||||
@@ -19,14 +19,14 @@
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{define "cryptoStatus"}}{{$kc := orgKeyCert}}{{$ok := and cryptoReady $kc}}
|
||||
{{define "cryptoStatus"}}{{$kc := orgKeyCert}}{{$exp := and $kc (index $kc "Expired")}}{{$ok := and cryptoReady $kc (not $exp)}}
|
||||
<div class="card" id="sec-crypto-status">
|
||||
<div class="stc {{if $ok}}{{if lt (index $kc "Days") 30}}stc-err{{else}}stc-ok{{end}}{{else}}stc-warn{{end}}"><span class="stc-ic"></span>
|
||||
<div class="stc-b"><b>{{if $ok}}{{if lt (index $kc "Days") 30}}Ключ организации скоро закончится{{else}}Подпись работает{{end}}{{else}}Ключ организации не подключён{{end}}</b>
|
||||
<small>{{if $ok}}СКЗИ «Валидата» установлена, ключ организации подключён — документы для НРД подписываются.{{if lt (index $kc "Days") 30}} Получите новый ключ в Удостоверяющем центре и установите его.{{end}}{{else}}Пошаговая установка: флешка с ключом или архив ключа от НРД с паролем → справочник сертификатов → проверка подписи.{{end}}</small></div>
|
||||
{{if or (not $ok) (lt (index $kc "Days") 30)}}<a class="btn" href="/admin/setup/keywizard" style="flex:none">{{if $ok}}Установить новый ключ →{{else}}Установить ключ →{{end}}</a>{{end}}</div>
|
||||
<div class="stc {{if $exp}}stc-err{{else if $ok}}{{if lt (index $kc "Days") 30}}stc-err{{else}}stc-ok{{end}}{{else}}stc-warn{{end}}"><span class="stc-ic"></span>
|
||||
<div class="stc-b"><b>{{if $exp}}Ключ организации истёк{{else if $ok}}{{if lt (index $kc "Days") 30}}Ключ организации скоро закончится{{else}}Подпись работает{{end}}{{else}}Ключ организации не подключён{{end}}</b>
|
||||
<small>{{if $exp}}Ключ «{{index $kc "Owner"}}» истёк {{index $kc "Until"}} — подпись для НРД не проходит. Получите новый ключ в Удостоверяющем центре и установите его.{{else if $ok}}СКЗИ «Валидата» установлена, ключ организации подключён — документы для НРД подписываются.{{if lt (index $kc "Days") 30}} Получите новый ключ в Удостоверяющем центре и установите его.{{end}}{{else}}Пошаговая установка: флешка с ключом или архив ключа от НРД с паролем → справочник сертификатов → проверка подписи.{{end}}</small></div>
|
||||
{{if or (not $ok) (lt (index $kc "Days") 30)}}<a class="btn" href="/admin/setup/keywizard" style="flex:none">{{if or $ok $exp}}Установить новый ключ →{{else}}Установить ключ →{{end}}</a>{{end}}</div>
|
||||
<dl class="kv">
|
||||
{{if $kc}}<dt>Ключ организации</dt><dd>«{{index $kc "Owner"}}» · выдан {{index $kc "Issuer"}} · действует до <b>{{index $kc "Until"}}</b> <span class="muted">(осталось {{index $kc "Days"}} дн.)</span> · <a href="/admin/setup/keywizard">заменить ключ</a></dd>{{end}}
|
||||
{{if $kc}}<dt>Ключ организации</dt><dd>«{{index $kc "Owner"}}» · выдан {{index $kc "Issuer"}} · контур {{index $kc "Contour"}} · {{if $exp}}действовал до <b>{{index $kc "Until"}}</b> <span style="color:var(--err)">· ИСТЁК</span>{{else}}действует до <b>{{index $kc "Until"}}</b> <span class="muted">(осталось {{index $kc "Days"}} дн.)</span>{{end}} · <a href="/admin/setup/keywizard">заменить ключ</a></dd>{{end}}
|
||||
{{with .Versions.Get "validata"}}<dt>СКЗИ «Валидата Клиент L»</dt><dd>{{if .Version}}{{if cryptoReady}}<span class="kv-ok">✓</span> {{end}}{{.Version}}{{else}}<span class="kv-no">✗</span> не определена{{end}}{{with .Detail}} <span class="muted">· {{.}}</span>{{end}}</dd>{{end}}
|
||||
{{with .Versions.Get "crypto-service.jar"}}<dt>Проверка подписи (bj-crypto)</dt><dd>{{if .Version}}{{.Version}}{{else}}не определена{{end}}{{with .Err}} <span style="color:var(--err)">· {{.}}</span>{{end}}</dd>{{end}}
|
||||
<dt>Сертификаты НРД в справочнике шлюза</dt><dd>{{if .NSDCerts.Pending}}<span class="kv-warn">⚠</span> есть изменения к применению ({{.NSDCerts.Pending}}){{else if .NSDCerts.LastRun.IsZero}}ещё не сверялись{{else}}<span class="kv-ok">✓</span> сверены {{msk .NSDCerts.LastRun}}{{end}} <span class="muted">· bj сверяет сам при запуске и раз в 6 часов</span></dd>
|
||||
|
||||
Reference in New Issue
Block a user