v0.249.0: i18n slice 1 release B — backup pages in English, Hungarian byte-identical (R-556)
gates / gates (push) Successful in 20s

Seven backup pages + the restore-progress JS converted against fixtures captured unconverted
(f8ebc47); recovery renders through executeTemplateLang; English retrieval claims registered;
the Fut comparison left unconverted (R-563).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-09-17 18:01:09 +02:00
parent f8ebc47728
commit 11b790e314
24 changed files with 2921 additions and 433 deletions
@@ -7,8 +7,8 @@
<div class="page-header">
<div style="display:flex;align-items:center;gap:.5rem">
<a href="/backups/remote" class="btn btn-sm btn-outline">← Vissza</a>
<h2>Helyreállítási kód</h2>
<a href="/backups/remote" class="btn btn-sm btn-outline">{{T "backups_escrow.vissza"}}</a>
<h2>{{T "backups_escrow.helyreallitasi_kod"}}</h2>
</div>
<span class="domain-badge">{{.Domain}}</span>
</div>
@@ -20,7 +20,7 @@
polls and reloads itself when the agent says ready. -->
<div class="settings-card" id="escrow-not-ready">
<div class="alert alert-info">{{.EscrowNotReadyMessage}}</div>
<p class="form-hint">Ehhez nem kell semmit tenned. Ha fél óra múlva is ezt látod, szólj az üzemeltetőnek.</p>
<p class="form-hint">{{T "backups_escrow.ehhez_nem_kell_semmit_tenned"}}</p>
</div>
<script>
(function(){
@@ -34,96 +34,91 @@
})();
</script>
{{else if not .AgentSupported}}
<div class="alert alert-info">A funkcióhoz az ügynök frissítése szükséges — a frissítés automatikusan megérkezik. Próbálja újra később.</div>
<div class="alert alert-info">{{T "backups_escrow.a_funkciohoz_az_ugynok_frissitese"}}</div>
{{else}}
<!-- 1. Preflight -->
<div class="settings-card" id="pf-card">
<h3>1. Előfeltételek ellenőrzése</h3>
<h3>{{T "backups_escrow.1_elofeltetelek_ellenorzese"}}</h3>
<div id="pf-error" class="alert alert-error" style="display:none;margin-bottom:1rem"></div>
<div id="pf-list"><p class="form-hint">Ellenőrzés folyamatban…</p></div>
<div id="pf-list"><p class="form-hint">{{T "backups_escrow.ellenorzes_folyamatban"}}</p></div>
</div>
<!-- 2. Warning + 3. Re-auth (revealed when preflight is green) -->
<div class="settings-card" id="warn-card" style="display:none">
<h3>2. Fontos tudnivalók</h3>
<h3>{{T "backups_escrow.2_fontos_tudnivalok"}}</h3>
<div class="alert alert-warning" style="margin-bottom:.75rem">
A helyreállítási kód a mentései utolsó kulcsa. Pontosan egyszer jelenik meg — a rendszer
sehol nem tárolja, és a Felhom sem ismeri. Ha a szerver megsemmisül, a távoli mentések CSAK
ezzel a kóddal állíthatók vissza. Írja fel papírra vagy mentse jelszókezelőbe — de NE ezen a
szerveren tárolja.
{{T "backups_escrow.a_helyreallitasi_kod_a_mentesei"}}
</div>
{{if .Receremony}}
<div class="alert alert-info" style="margin-bottom:.75rem">
Az új kód létrehozásával a korábbi kód a jövőbeli mentésekre érvényét veszti; a már meglévő
mentési előzményekhez érvényes marad.
{{T "backups_escrow.az_uj_kod_letrehozasaval_a"}}
</div>
{{end}}
<h3 style="margin-top:1.25rem">3. Megerősítés</h3>
<h3 style="margin-top:1.25rem">{{T "backups_escrow.3_megerosites"}}</h3>
<form id="start-form" onsubmit="return startCeremony(event)">
<div class="form-group">
<label for="reauth-password">A folytatáshoz adja meg a bejelentkezési jelszavát</label>
<label for="reauth-password">{{T "backups_escrow.a_folytatashoz_adja_meg_a"}}</label>
<input type="password" id="reauth-password" class="form-control" autocomplete="current-password" required style="max-width:280px">
</div>
<div id="start-error" class="alert alert-error" style="display:none;margin-bottom:.75rem"></div>
<div class="form-actions">
<button type="submit" class="btn btn-primary" id="start-btn">Kód létrehozása</button>
<a href="/backups/remote" class="btn btn-outline">Mégsem</a>
<button type="submit" class="btn btn-primary" id="start-btn">{{T "backups_escrow.kod_letrehozasa"}}</button>
<a href="/backups/remote" class="btn btn-outline">{{T "backups_escrow.megsem"}}</a>
</div>
</form>
</div>
<!-- 4. Progress -->
<div class="settings-card" id="progress-card" style="display:none">
<h3>4. Létrehozás</h3>
<p class="form-hint" id="progress-line">A kód létrehozása folyamatban… (általában néhány másodperc)</p>
<h3>{{T "backups_escrow.4_letrehozas"}}</h3>
<p class="form-hint" id="progress-line">{{T "backups_escrow.a_kod_letrehozasa_folyamatban_altalaban"}}</p>
<div id="progress-error" class="alert alert-error" style="display:none"></div>
</div>
<!-- 5. Reveal + 6. Typed-back + 7. Finish -->
<div class="settings-card" id="reveal-card" style="display:none">
<h3>5. A helyreállítási kód</h3>
<h3>{{T "backups_escrow.5_a_helyreallitasi_kod"}}</h3>
<div id="reveal-gate">
<p class="form-hint">A kód pontosan egyszer jeleníthető meg. Készítsen elő papírt és tollat, mielőtt megnyomja a gombot.</p>
<button class="btn btn-primary" id="reveal-btn" onclick="claimCode()">Kód megjelenítése</button>
<p class="form-hint">{{T "backups_escrow.a_kod_pontosan_egyszer_jelenitheto"}}</p>
<button class="btn btn-primary" id="reveal-btn" onclick="claimCode()">{{T "backups_escrow.kod_megjelenitese"}}</button>
<div id="reveal-error" class="alert alert-error" style="display:none;margin-top:.75rem"></div>
</div>
<div id="reveal-shown" style="display:none">
<div class="alert alert-warning" style="margin-bottom:.5rem">Ez mostantól az élő helyreállítási kód — a korábbi kód érvényét vesztette. Mentse el most: a kód többé nem jeleníthető meg.</div>
<div class="alert alert-warning" style="margin-bottom:.5rem">{{T "backups_escrow.ez_mostantol_az_elo_helyreallitasi"}}</div>
<pre class="mono" id="code-block" style="white-space:pre-wrap;word-break:break-all;background:var(--bg-0);border:1px solid var(--line);border-radius:var(--radius);padding:1rem;font-size:1.05rem"></pre>
<button type="button" class="btn btn-ghost btn-sm" id="code-blur-toggle" onclick="toggleCodeBlur()">Elrejtés</button>
<h3 style="margin-top:1.25rem">6. Ellenőrzés</h3>
<button type="button" class="btn btn-ghost btn-sm" id="code-blur-toggle" onclick="toggleCodeBlur()">{{T "backups_escrow.elrejtes"}}</button>
<h3 style="margin-top:1.25rem">{{T "backups_escrow.6_ellenorzes"}}</h3>
<div class="form-group">
<label id="verify-label" for="verify-w1">Megerősítés: írja be a kód szavait</label>
<label id="verify-label" for="verify-w1">{{T "backups_escrow.megerosites_irja_be_a_kod"}}</label>
<div style="display:flex;gap:.5rem">
<input type="text" id="verify-w1" class="form-control" autocomplete="off" style="max-width:180px">
<input type="text" id="verify-w2" class="form-control" autocomplete="off" style="max-width:180px">
</div>
<div id="verify-error" class="alert alert-error" style="display:none;margin-top:.5rem">A megadott szavak nem egyeznek — ellenőrizze a felírt kódot.</div>
<div id="verify-error" class="alert alert-error" style="display:none;margin-top:.5rem">{{T "backups_escrow.a_megadott_szavak_nem_egyeznek"}}</div>
</div>
<button class="btn btn-sm" id="verify-btn" onclick="verifyWords()">Szavak ellenőrzése</button>
<button class="btn btn-sm" id="verify-btn" onclick="verifyWords()">{{T "backups_escrow.szavak_ellenorzese"}}</button>
<div id="finish-block" style="display:none;margin-top:1rem">
<h3>7. Befejezés</h3>
<h3>{{T "backups_escrow.7_befejezes"}}</h3>
{{/* v0.138.0: the "what happens next" note — the wizard finishes to /backups/remote,
where the interim "awaiting hub confirmation" card shows until the flip. Setting
expectations here avoids surprise at that card. */}}
<div class="alert alert-info" style="margin-bottom:.75rem">
<strong>Mi történik ezután?</strong> A helyreállítási kód elkészült, és a rendszer elküldi a központba megerősítésre — ez általában néhány másodperc, legfeljebb 15 perc. Addig a Távoli mentés oldalon a „megerősítésre vár" üzenet látható; a megerősítés után indítható az első távoli mentés.
{{T "backups_escrow.mi_tortenik_ezutan_a_helyreallitasi"}}
</div>
<label class="toggle" style="margin-bottom:.75rem">
<input type="checkbox" id="finish-check" onchange="document.getElementById('finish-btn').disabled=!this.checked">
<span class="toggle-label">Felírtam a kódot, és biztonságos helyen — nem ezen a szerveren — tárolom.</span>
<span class="toggle-label">{{T "backups_escrow.felirtam_a_kodot_es_biztonsagos"}}</span>
</label>
<div><button class="btn btn-primary" id="finish-btn" disabled onclick="finishWizard()">Befejezés</button></div>
<div><button class="btn btn-primary" id="finish-btn" disabled onclick="finishWizard()">{{T "backups_escrow.befejezes"}}</button></div>
</div>
</div>
</div>
<!-- Void / unclaimed state -->
<div class="settings-card" id="void-card" style="display:none">
<div class="alert alert-warning">A kód létrejött, de nem lett megjelenítve — biztonsági okból újra nem kérhető le.
Indítsa újra a folyamatot: az új kód a régit érvényteleníti.</div>
<a href="/backup/escrow" class="btn btn-sm btn-primary">Újraindítás</a>
<div class="alert alert-warning">{{T "backups_escrow.a_kod_letrejott_de_nem"}}</div>
<a href="/backup/escrow" class="btn btn-sm btn-primary">{{T "backups_escrow.ujrainditas"}}</a>
</div>
<script>
@@ -131,12 +126,12 @@ function esc(s){ return String(s==null?'':s).replace(/[&<>"]/g,function(c){retur
// Hungarian labels for the agent preflight row ids.
var PF_LABELS = {
pbs_storage_id: 'Mentési tároló (PBS) beállítva',
dr_tier: 'Helyreállítási (DR) szint aktív',
age_binary: 'Titkosító eszköz telepítve',
hub_upload: 'Központi feltöltés beállítva',
staged_secret: 'Távoli mentés jelszava előkészítve',
sudo_grant: 'Rendszerjogosultság engedélyezve'
pbs_storage_id: '{{T "backups_escrow.mentesi_tarolo_pbs_beallitva"}}',
dr_tier: '{{T "backups_escrow.helyreallitasi_dr_szint_aktiv"}}',
age_binary: '{{T "backups_escrow.titkosito_eszkoz_telepitve"}}',
hub_upload: '{{T "backups_escrow.kozponti_feltoltes_beallitva"}}',
staged_secret: '{{T "backups_escrow.tavoli_mentes_jelszava_elokeszitve"}}',
sudo_grant: '{{T "backups_escrow.rendszerjogosultsag_engedelyezve"}}'
};
// Hungarian DETAIL mapping (v0.127.1): the agent's `detail` strings are operator-English by
@@ -144,17 +139,17 @@ var PF_LABELS = {
// (storage id / binary path); boolean-OK rows render no detail at all. Not-OK rows get the
// Hungarian explanation; unknown/future ids fall back to the raw detail (never blank a failure).
var PF_FAIL_DETAILS = {
pbs_storage_id: 'nincs beállítva mentési tároló',
age_binary: 'a titkosító eszköz (age) nem található',
dr_tier: 'a DR-szint nincs alkalmazva ezen a gépen',
hub_upload: 'a központi feltöltés nincs beállítva',
sudo_grant: 'a rendszerjogosultság hiányzik — az ügynök frissítése szükséges',
staged_secret: 'nincs előkészített jelszó — a varázsló indításkor automatikusan előkészíti, ha a távoli mentés be van állítva'
pbs_storage_id: '{{T "backups_escrow.nincs_beallitva_mentesi_tarolo"}}',
age_binary: '{{T "backups_escrow.a_titkosito_eszkoz_age_nem"}}',
dr_tier: '{{T "backups_escrow.a_dr_szint_nincs_alkalmazva"}}',
hub_upload: '{{T "backups_escrow.a_kozponti_feltoltes_nincs_beallitva"}}',
sudo_grant: '{{T "backups_escrow.a_rendszerjogosultsag_hianyzik_az_ugynok"}}',
staged_secret: '{{T "backups_escrow.nincs_elokeszitett_jelszo_a_varazslo"}}'
};
function pfDetail(it){
if(it.ok){
if(it.id==='pbs_storage_id' || it.id==='age_binary'){ return it.detail||''; } // the VALUE
if(it.id==='staged_secret'){ return 'előkészítve'; }
if(it.id==='staged_secret'){ return '{{T "backups_escrow.elokeszitve"}}'; }
return ''; // dr_tier / hub_upload / sudo_grant: the check mark + label is complete
}
return PF_FAIL_DETAILS[it.id] || (it.detail||'');
@@ -163,7 +158,7 @@ function pfDetail(it){
async function loadPreflight(){
try{
var r = await fetch('/api/escrow/preflight'); var j = await r.json();
if(!j.ok && !j.data){ throw new Error(j.error||'Hiba'); }
if(!j.ok && !j.data){ throw new Error(j.error||'{{T "backups_escrow.hiba"}}'); }
var d = j.data||{};
var html='<ul style="list-style:none;padding:0;margin:0">';
(d.items||[]).forEach(function(it){
@@ -182,7 +177,7 @@ async function loadPreflight(){
html+='<li style="padding:.35rem 0;border-bottom:1px solid var(--line-soft)">'+line+'</li>';
});
if(!d.agent_supported){
html+='<li style="padding:.35rem 0"><span style="color:var(--crit)">&#10007;</span> A funkcióhoz az ügynök frissítése szükséges — a frissítés automatikusan megérkezik.</li>';
html+='<li style="padding:.35rem 0"><span style="color:var(--crit)">&#10007;</span> {{T "backups_escrow.a_funkciohoz_az_ugynok_frissitese_2"}}</li>';
}
html+='</ul>';
document.getElementById('pf-list').innerHTML=html;
@@ -190,11 +185,11 @@ async function loadPreflight(){
document.getElementById('warn-card').style.display='block';
} else {
document.getElementById('pf-list').insertAdjacentHTML('beforeend',
'<p class="form-hint" style="margin-top:.75rem">A folyamat a piros feltételek teljesüléséig nem indítható.</p>');
'<p class="form-hint" style="margin-top:.75rem">{{T "backups_escrow.a_folyamat_a_piros_feltetelek"}}</p>');
}
}catch(e){
var el=document.getElementById('pf-error'); el.style.display='block';
el.textContent='Az előfeltételek ellenőrzése nem sikerült: '+e.message;
el.textContent='{{T "backups_escrow.az_elofeltetelek_ellenorzese_nem_sikerul"}} '+e.message;
}
}
@@ -207,12 +202,12 @@ async function startCeremony(ev){
var r=await fetch('/api/escrow/start',{method:'POST',
headers:Object.assign({'Content-Type':'application/x-www-form-urlencoded'},csrfHeaders()),body:body});
var j=await r.json();
if(!j.ok){ errEl.textContent=j.error||'A folyamat indítása nem sikerült.'; errEl.style.display='block'; btn.disabled=false; return false; }
if(!j.ok){ errEl.textContent=j.error||'{{T "backups_escrow.a_folyamat_inditasa_nem_sikerult"}}'; errEl.style.display='block'; btn.disabled=false; return false; }
document.getElementById('reauth-password').value='';
document.getElementById('warn-card').style.display='none';
document.getElementById('progress-card').style.display='block';
pollStatus();
}catch(e){ errEl.textContent='Hiba: '+e.message; errEl.style.display='block'; btn.disabled=false; }
}catch(e){ errEl.textContent='{{T "backups_escrow.hiba_2"}} '+e.message; errEl.style.display='block'; btn.disabled=false; }
return false;
}
@@ -230,7 +225,7 @@ function pollStatus(){
} else if(d.phase==='failed'){
clearInterval(pollTimer);
var el=document.getElementById('progress-error'); el.style.display='block';
el.textContent='A létrehozás nem sikerült.'+(d.detail?(' Részletek: '+d.detail):'');
el.textContent='{{T "backups_escrow.a_letrehozas_nem_sikerult"}}'+(d.detail?(' {{T "backups_escrow.reszletek"}} '+d.detail):'');
} else if(d.phase==='unclaimed_void' || d.phase==='none'){
clearInterval(pollTimer);
document.getElementById('progress-card').style.display='none';
@@ -252,7 +247,7 @@ async function claimCode(){
var r=await fetch('/api/escrow/claim',{method:'POST',headers:csrfHeaders()});
var j=await r.json();
if(r.status===410){ document.getElementById('reveal-card').style.display='none'; document.getElementById('void-card').style.display='block'; return; }
if(!j.ok || !j.data || !j.data.recovery_code){ errEl.textContent=j.error||'A kód lekérése nem sikerült.'; errEl.style.display='block'; btn.disabled=false; return; }
if(!j.ok || !j.data || !j.data.recovery_code){ errEl.textContent=j.error||'{{T "backups_escrow.a_kod_lekerese_nem_sikerult"}}'; errEl.style.display='block'; btn.disabled=false; return; }
claimedR=j.data.recovery_code;
// Typed-back positions FIRST (v0.127.1: the rendering below highlights them): two random
// distinct 1-based word positions of the dash-separated code.
@@ -276,8 +271,8 @@ async function claimCode(){
});
document.getElementById('reveal-gate').style.display='none';
document.getElementById('reveal-shown').style.display='block';
document.getElementById('verify-label').textContent='Megerősítés: írja be a kód '+verifyIdx[0]+'. és '+verifyIdx[1]+'. szavát';
}catch(e){ errEl.textContent='Hiba: '+e.message; errEl.style.display='block'; btn.disabled=false; }
document.getElementById('verify-label').textContent='{{T "backups_escrow.megerosites_irja_be_a_kod_2"}} '+verifyIdx[0]+'{{T "backups_escrow.es"}} '+verifyIdx[1]+'{{T "backups_escrow.szavat"}}';
}catch(e){ errEl.textContent='{{T "backups_escrow.hiba_2"}} '+e.message; errEl.style.display='block'; btn.disabled=false; }
}
// Manual hide toggle (v0.127.2 — Viktor's live finding reversed the v0.127.1 auto-blur: blurring
@@ -289,7 +284,7 @@ var codeBlurred=false;
function setCodeBlur(on){
codeBlurred=on;
document.getElementById('code-block').style.filter=on?'blur(6px)':'';
document.getElementById('code-blur-toggle').textContent=on?'Megjelenítés':'Elrejtés';
document.getElementById('code-blur-toggle').textContent=on?'{{T "backups_escrow.megjelenites"}}':'{{T "backups_escrow.elrejtes"}}';
}
function toggleCodeBlur(){ setCodeBlur(!codeBlurred); }