c7446f2d6a
R-225 — an unread store said '0 pillanatkép / 0 / 50 GB' above a card stating it held backups under another key. An SFTP listing found snapshot f3d9cd67 and 12 535 KB really there; snapshot_count and repo_size_bytes were simply ABSENT and the zero value spoke for them. StatsKnown is now NAMED, for the same reason OffsiteInventory.Empty is: zero is what an unread store and an empty one both look like, and on the wire 'absent' and '0' are the same bytes. The fill bar renders only when the fill is known — a 0%-wide bar is a picture of emptiness, and a picture is a claim. A measured zero still says zero. R-227 — WHICH LAYER ANSWERS: traefik, and this repo generates its config. But traefik v3 serves no static files, so a branded proxy page needs a new always-up container for every 502 on the box — out of proportion, and scoped in the report rather than built. Shipped instead: the unlock posts via fetch and answers a gateway failure in Hungarian without leaving the page. Progressive enhancement — with no JS the plain POST is unchanged and still shows the proxy's error, which the report says plainly rather than implying otherwise. R-228 — the set-aside history was recorded in orphaned_renamed_to and read by nobody: a census found zero references in any template or handler, while 12 535 KB sat at that path. It is surfaced as two facts and stops. It does NOT promise the history can be reopened, because it cannot be by anyone today (R-199's inventory is unbuilt) — and the set-aside CONFIRMATION copy was corrected for the same reason: 'a helyreállítási kód nélkül többé nem lesznek megnyithatók' implied that WITH the code they could be. The field's own comment called it 'recovery-code-recoverable', which was the same over-promise in the code. Tests: scenarios F, G, H as render tests per branch of each gate. Red-proofs, each demonstrated failing then restored: remove the StatsKnown guards (F, 'R-225 RETURNED: an unread store reports a snapshot COUNT of zero'), delete the set-aside block (H). The F assertion on the fill bar is scoped to the bar's own container — a bare width:0% search matched unrelated elements and would have passed for the wrong reason. 28 packages ok, vet clean, all controller gates OK (the emoji gate caught a warning sign in a template comment).
205 lines
11 KiB
HTML
205 lines
11 KiB
HTML
{{define "recovery"}}
|
|
<!DOCTYPE html>
|
|
<html lang="hu">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta name="robots" content="noindex, nofollow">
|
|
<title>Adatok visszaszerzése — Felhom</title>
|
|
<link rel="stylesheet" href="/static/style.css">
|
|
</head>
|
|
<body class="login-body">
|
|
<div class="login-card" style="max-width:46rem">
|
|
<img src="/static/felhom-logo.svg" alt="Felhom.eu" class="login-logo">
|
|
|
|
{{if .Unlocked}}
|
|
<!-- ── AFTER THE UNLOCK: what is in there. Read-only — nothing was restored. ────────────── -->
|
|
<h1 class="login-title">A mentéseid <span class="title-accent">elérhetők</span></h1>
|
|
{{if .Flash}}<div class="alert alert-info">{{.Flash}}</div>{{end}}
|
|
{{if .Error}}<div class="alert alert-error">{{.Error}}</div>{{end}}
|
|
|
|
{{if .InvUnavailable}}
|
|
<!-- R-217: the unlock SUCCEEDED but the repository could not be read. It renders NO listing and
|
|
claims nothing about the contents — the .Error above already says what is pending. This
|
|
branch exists because the previous code passed a zero-value OffsiteInventory here, whose
|
|
Empty=false fell through to .InvUntagged and asserted the store had opened with content. -->
|
|
{{else if .InvEmpty}}
|
|
<div class="alert alert-warning">
|
|
A tároló megnyílt, de <strong>nincs benne egyetlen mentés sem</strong>. Ez azt jelenti, hogy a
|
|
kulcs jó volt, de ehhez a géphez nem tartozik korábbi mentés. Ha korábban biztosan készültek
|
|
mentések, keresd a Felhom ügyfélszolgálatát, mielőtt bármit tennél.
|
|
</div>
|
|
{{else if .InvUntagged}}
|
|
<div class="alert alert-warning">
|
|
A tároló megnyílt, és van benne tartalom, de nem tudtuk alkalmazásokhoz rendelni. A Biztonsági
|
|
mentés oldalon nézheted meg részletesen.
|
|
</div>
|
|
{{else}}
|
|
<p class="login-subtitle" style="margin-bottom:1rem">
|
|
Ezek a <strong>te</strong> mentéseid, a lent jelzett időpontokból. Nézd át, hogy tényleg azt
|
|
találod-e itt, amire számítasz — <strong>semmit nem állítottunk vissza és semmi nem változott.</strong>
|
|
</p>
|
|
<table class="data-table" style="width:100%;margin-bottom:1rem">
|
|
<thead><tr><th>Alkalmazás</th><th>Legutóbbi mentés</th><th>Méret</th></tr></thead>
|
|
<tbody>
|
|
{{range .InvApps}}
|
|
<tr>
|
|
<td>{{.App}}</td>
|
|
<td>{{fmtTime .LatestAt}}</td>
|
|
<td>{{if gt .SizeBytes 0}}{{humanBytes .SizeBytes}}{{else}}—{{end}}</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
{{end}}
|
|
|
|
<p class="form-hint">
|
|
A visszaállítás alkalmazásonként történik, a <strong>Biztonsági mentés → Visszaállítás</strong>
|
|
oldalon. Ott választhatod ki, melyik alkalmazás mit hozzon vissza.
|
|
</p>
|
|
<div class="form-actions">
|
|
<a href="/backups/restore" class="btn btn-primary">Tovább a visszaállításhoz</a>
|
|
<a href="/launcher" class="btn btn-outline">Vissza a kezdőlapra</a>
|
|
</div>
|
|
|
|
{{else}}
|
|
<!-- ── BEFORE ANY CODE: explain, then take the code. ───────────────────────────────────── -->
|
|
<h1 class="login-title">Adatok <span class="title-accent">visszaszerzése</span></h1>
|
|
<p class="login-subtitle">{{.CustomerName}}</p>
|
|
|
|
{{if .Flash}}<div class="alert alert-info">{{.Flash}}</div>{{end}}
|
|
{{if .Error}}<div class="alert alert-error">{{.Error}}</div>{{end}}
|
|
|
|
<p>
|
|
Ezt a gépet újratelepítették. A korábbi, <strong>házon kívüli mentéseid megvannak</strong> — a
|
|
Felhom központi rendszere őriz hozzájuk egy lezárt csomagot{{with .SealedAt}}, amelyet
|
|
<strong>{{.}}</strong> zártunk le{{end}}. A csomagot csak a <strong>te helyreállítási
|
|
kódoddal</strong> lehet kinyitni.
|
|
</p>
|
|
|
|
<div class="alert alert-warning">
|
|
<strong>A helyreállítási kódot senki nem tudja pótolni</strong> — sem a Felhom, sem az
|
|
ügyfélszolgálat, sem az üzemeltető. Ez szándékos: így a mentéseidet rajtad kívül senki nem
|
|
tudja megnyitni. Ha a kód elveszett, a korábbi mentések nem nyithatók meg többé.
|
|
</div>
|
|
|
|
<p>
|
|
Ha megadod a kódot, <strong>feloldjuk a mentéseid zárolását és megmutatjuk, mi van bennük</strong>
|
|
— melyik alkalmazás, mikorról, mekkora. <strong>Ebben a lépésben semmit nem állítunk vissza és
|
|
semmi nem változik.</strong> A visszaállítást utána, alkalmazásonként külön választhatod.
|
|
</p>
|
|
|
|
<div id="unlock-gateway-error" class="alert alert-error" style="display:none" role="alert"></div>
|
|
|
|
<form id="unlock-form" method="POST" action="/recovery/unlock" autocomplete="off">
|
|
{{.CSRFField}}
|
|
<label for="recovery_code">Helyreállítási kód (tíz szó)</label>
|
|
<input type="password" id="recovery_code" name="recovery_code"
|
|
autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false"
|
|
placeholder="tíz szó, szóközökkel elválasztva" required>
|
|
<div class="form-actions">
|
|
<button type="submit" class="btn btn-primary">Mentések feloldása</button>
|
|
<form method="POST" action="/recovery/postpone" style="display:inline">
|
|
{{.CSRFField}}
|
|
<button type="submit" class="btn btn-outline">Most nem</button>
|
|
</form>
|
|
</div>
|
|
</form>
|
|
|
|
{{/* R-227 — A RESTART MID-UNLOCK MUST NOT SHOW A RAW ENGLISH GATEWAY ERROR.
|
|
|
|
Measured 2026-08-05 (CAMPAIGN-11 F8): the controller was restarted 0.7 s into an unlock and
|
|
the customer got traefik's `Bad Gateway` — a raw upstream error, in English, naming no reason
|
|
and saying nothing about whether the key was installed. The state was clean; only the page
|
|
was not. It breaches I3 (every refusal names a reason a person can act on, in Hungarian, with
|
|
no raw error).
|
|
|
|
WHICH LAYER ANSWERS: traefik, and its config IS generated by this repo
|
|
(internal/infra/templates/traefik*.tmpl). A fully branded proxy error page is therefore
|
|
possible here — but traefik v3 serves no static files itself, so it would need a new
|
|
always-up container purely to hold an error page, for every 502 on the box. That is out of
|
|
proportion to this finding and is scoped in the report rather than built.
|
|
|
|
What ships instead is the second sanctioned option: the unlock posts via fetch, so a gateway
|
|
error or a dropped connection is caught in the page and answered in Hungarian, without
|
|
leaving it. PROGRESSIVE ENHANCEMENT — with no JS the plain POST is unchanged, and that path
|
|
still shows the proxy's own error. Said plainly rather than implied. */}}
|
|
<script>
|
|
(function () {
|
|
var form = document.getElementById('unlock-form');
|
|
var box = document.getElementById('unlock-gateway-error');
|
|
if (!form || !box || !window.fetch) { return; }
|
|
form.addEventListener('submit', function (ev) {
|
|
ev.preventDefault();
|
|
box.style.display = 'none';
|
|
var btn = form.querySelector('button[type=submit]');
|
|
if (btn) { btn.disabled = true; btn.textContent = 'Feloldás folyamatban…'; }
|
|
fetch(form.action, {
|
|
method: 'POST',
|
|
body: new FormData(form),
|
|
credentials: 'same-origin',
|
|
redirect: 'follow'
|
|
}).then(function (resp) {
|
|
if (resp.status >= 500) { throw new Error('gateway'); }
|
|
return resp.text().then(function (html) {
|
|
document.open(); document.write(html); document.close();
|
|
});
|
|
}).catch(function () {
|
|
// A 5xx from the proxy, or no response at all: the machine is very likely restarting.
|
|
// NOTHING is claimed about the code — we do not know whether it was used.
|
|
if (btn) { btn.disabled = false; btn.textContent = 'Mentések feloldása'; }
|
|
box.textContent = 'A gép éppen újraindul, ezért most nem tudtuk befejezni a műveletet. '
|
|
+ 'Semmi nem változott. Várj néhány másodpercet, és próbáld újra — a kódodra továbbra is szükséged lesz, '
|
|
+ 'úgyhogy tartsd kéznél.';
|
|
box.style.display = '';
|
|
});
|
|
});
|
|
})();
|
|
</script>
|
|
|
|
<p class="form-hint">
|
|
A „Most nem” csak azt jelenti, hogy nem zavarunk vele többet a kezdőlapon. A mentéseid ettől
|
|
megmaradnak, és ez az oldal a <strong>Biztonsági mentés → Távoli mentés</strong> oldalról
|
|
bármikor újra elérhető.
|
|
</p>
|
|
|
|
<!-- ── THE EXCEPTIONAL PATH. Deliberately not an equal third button. ───────────────────── -->
|
|
<hr style="margin:1.5rem 0;border:none;border-top:1px solid var(--border,#2a3142)">
|
|
{{if .ConfirmSetAside}}
|
|
<div class="alert alert-error">
|
|
<p><strong>Biztosan nem kéred vissza a korábbi mentéseket?</strong></p>
|
|
<p>Ha megerősíted:</p>
|
|
<ul>
|
|
<li>a korábbi mentéseket <strong>félretesszük — nem töröljük</strong>;</li>
|
|
<li>a félretett mentések <strong>innen többé nem nyithatók meg</strong> — sem kóddal, sem anélkül;</li>
|
|
<li>a gép <strong>új, üres mentési tárolót kezd</strong>, és mostantól oda ment;</li>
|
|
<li>ez az oldal <strong>többé nem jelenik meg</strong>.</li>
|
|
</ul>
|
|
<p>Ha csak most nincs kéznél a kódod, válaszd inkább a „Most nem” lehetőséget.</p>
|
|
</div>
|
|
<div class="form-actions">
|
|
<form method="POST" action="/backup/offbox/reset">
|
|
{{.CSRFField}}
|
|
<input type="hidden" name="confirm" value="1">
|
|
<button type="submit" class="btn btn-danger">Igen, félretehetitek a korábbi mentéseket</button>
|
|
</form>
|
|
<a href="/recovery" class="btn btn-outline">Mégsem</a>
|
|
</div>
|
|
{{else}}
|
|
<p class="form-hint">
|
|
Ha a helyreállítási kódod véglegesen elveszett, és tudomásul veszed, hogy a korábbi mentések
|
|
így nem nyithatók meg többé:
|
|
{{if .CanSetAside}}
|
|
<a href="/recovery?setaside=1">nem kérem vissza a korábbi adatokat</a>.
|
|
{{else}}
|
|
ez a lehetőség akkor válik elérhetővé, ha a gép már újra kapcsolódott a házon kívüli
|
|
tárhelyhez. Addig a mentéseid érintetlenül megmaradnak.
|
|
{{end}}
|
|
</p>
|
|
{{end}}
|
|
{{end}}
|
|
</div>
|
|
</body>
|
|
</html>
|
|
{{end}}
|