fix(R-1218, R-1219): stage the off-site password when its file exists; no recovery ceremony during a recovery offer

R-1218: escrowStart stages when OffboxRepoPasswordOnBox() (not OffboxConfigured()). R-1219: the top bar hides during an
offer; the start handler answers 409 (api.escrow.recovery_offer_open, hu+en) before staging. Red-proved. Commit only.
This commit is contained in:
admin committed 2026-10-26 20:20:59 +01:00
1 parent 7e15a374b2
commit 1170b48e59
8 files changed
+163 -2

No files matched your search

+14 -2
View File
@@ -213,8 +213,20 @@ func (s *Server) escrowStartAPIHandler(w http.ResponseWriter, r *http.Request) {
return
}
// (2) Re-stage-first (only when offsite is configured — Scenario C boxes skip it).
if s.backupMgr != nil && s.backupMgr.OffboxConfigured() {
// (1c) R-1219: no ceremony during a recovery offer — a new code would replace the key that opens the old off-site
// copy (R-199). The page hides the form; a direct POST (or the old top-bar link) is refused here, before anything is
// staged or started. Pinned by TestR1219_NoCeremonyDuringARecoveryOffer.
if s.recoveryOffer() {
s.logger.Printf("[INFO] [web] escrow start refused: a recovery offer is open (R-1219)")
escrowJSON(w, http.StatusConflict, nil, s.msg(r, "api.escrow.recovery_offer_open"))
return
}
// (2) Re-stage-first whenever the repository password FILE is on the box (R-1218) — not only when off-site is
// configured: a cleared or switched-off target keeps the file, and a ceremony that seals no password makes the hub
// demote the household's good package. A box with no password (Scenario C, R-241's awaiting key) skips it.
// Pinned by TestR1218_TheCeremonyStagesWhenThePasswordFileExists.
if s.backupMgr != nil && s.backupMgr.OffboxRepoPasswordOnBox() {
if err := s.escrowStage(r.Context()); err != nil {
s.logger.Printf("[WARN] [web] escrow start: re-stage failed (ceremony NOT started): %v", err) // err carries no secret
escrowJSON(w, http.StatusBadGateway, nil, s.msg(r, "api.escrow.stage_failed"))