v0.259.0 — the claim page and the backup warnings answer in the reader's language (R-596, R-598)
gates / gates (push) Successful in 28s
gates / gates (push) Successful in 28s
The 2026-09-20 English drill ended one screen short: the claim page was English and its answers were Hungarian, so a household who mistyped the code from their e-mail could not tell a typo from a dead code. Fourteen call sites carrying nine messages now go through s.msg; the backup page's two protection warnings — which are promises about whether the customer's files are safe — follow the same route. Hungarian is byte-identical, proved structurally by the go-parity gate against the frozen base capture and red-proofed on a single added full stop. data["Title"] was DEAD (claim.html is standalone; .Title is layout.html's) and is deleted rather than translated — a translated dead field is a permanent false signal about where the page's title comes from. Six existing copy-contract tests were kept, not weakened: each now resolves its key through the real bundle, so it still convicts on a reworded Hungarian sentence. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -278,12 +278,17 @@ func (s *Server) handleClaimPage(w http.ResponseWriter, r *http.Request, errorMs
|
||||
s.logger.Printf("[ERROR] [web] claim: cannot read the persisted claim state while rendering the claim page: %v", cerr)
|
||||
hash = ""
|
||||
if errorMsg == "" {
|
||||
errorMsg = "A beállító állapot most nem olvasható — próbáld újra néhány perc múlva."
|
||||
errorMsg = s.msg(r, "claim.msg.state_unreadable")
|
||||
}
|
||||
}
|
||||
reset := s.authEnabled() // a set password means this is the reset flow, not first-claim
|
||||
// `Title` USED TO BE HERE, carrying the Hungarian "A szerver beállítása", and R-596 named it as
|
||||
// one of the strings an English household reads. It is not: claim.html is a STANDALONE page with
|
||||
// its own <title> (already `claim.jelszo_visszaallitasa` / `claim.a_szerver_beallitasa`), and
|
||||
// `.Title` is consumed only by layout.html, which this page never includes. So the field was dead
|
||||
// — rendered by nothing, in either language. Deleted rather than translated: a translated dead
|
||||
// field would read, for ever after, as evidence that this page's title is handled here.
|
||||
data := map[string]interface{}{
|
||||
"Title": "A szerver beállítása",
|
||||
"CustomerName": s.cfg.Customer.Name,
|
||||
"Domain": s.cfg.Customer.Domain,
|
||||
"Version": s.version,
|
||||
@@ -307,18 +312,18 @@ func (s *Server) handleClaimPage(w http.ResponseWriter, r *http.Request, errorMs
|
||||
func (s *Server) handleClaimSubmit(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
if !s.validClaimCSRF(r) {
|
||||
s.handleClaimPage(w, r, "Érvénytelen űrlap — töltsd újra az oldalt.", "")
|
||||
s.handleClaimPage(w, r, s.msg(r, "claim.msg.invalid_form"), "")
|
||||
return
|
||||
}
|
||||
wasReset := s.authEnabled() // a password already set → this is a reset, not a first-claim
|
||||
ip := clientIP(r)
|
||||
|
||||
if locked, _ := s.claimRateLocked(); locked {
|
||||
s.handleClaimPage(w, r, "Túl sok próbálkozás — próbáld újra 15 perc múlva.", "")
|
||||
s.handleClaimPage(w, r, s.msg(r, "claim.msg.too_many"), "")
|
||||
return
|
||||
}
|
||||
if locked, _ := s.claimSourceLocked(ip); locked {
|
||||
s.handleClaimPage(w, r, "Túl sok próbálkozás — próbáld újra 15 perc múlva.", "")
|
||||
s.handleClaimPage(w, r, s.msg(r, "claim.msg.too_many"), "")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -331,11 +336,11 @@ func (s *Server) handleClaimSubmit(w http.ResponseWriter, r *http.Request) {
|
||||
// FAIL CLOSED: refuse the claim rather than validate against a possibly-superseded cache.
|
||||
// NOT counted as a failed attempt — the customer typed nothing wrong.
|
||||
s.logger.Printf("[ERROR] [web] claim: refusing the submission — the persisted claim state is unreadable: %v", cerr)
|
||||
s.handleClaimPage(w, r, "A beállító állapot most nem olvasható — próbáld újra néhány perc múlva.", "")
|
||||
s.handleClaimPage(w, r, s.msg(r, "claim.msg.state_unreadable"), "")
|
||||
return
|
||||
}
|
||||
if hash == "" {
|
||||
s.handleClaimPage(w, r, "Nincs aktív kód — kérj újat az alábbi gombbal.", "")
|
||||
s.handleClaimPage(w, r, s.msg(r, "claim.msg.no_active_code"), "")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -356,32 +361,32 @@ func (s *Server) handleClaimSubmit(w http.ResponseWriter, r *http.Request) {
|
||||
if !valid {
|
||||
if s.claimRegisterFailure(ip) {
|
||||
s.reportClaimLockout(ip)
|
||||
s.handleClaimPage(w, r, "Túl sok próbálkozás — próbáld újra 15 perc múlva.", "")
|
||||
s.handleClaimPage(w, r, s.msg(r, "claim.msg.too_many"), "")
|
||||
return
|
||||
}
|
||||
s.handleClaimPage(w, r, "Hibás vagy lejárt kód", "")
|
||||
s.handleClaimPage(w, r, s.msg(r, "claim.msg.bad_code"), "")
|
||||
return
|
||||
}
|
||||
|
||||
// Password rules (min length, match).
|
||||
if len(newPassword) < claimMinPassword {
|
||||
s.handleClaimPage(w, r, fmt.Sprintf("A jelszónak legalább %d karakter hosszúnak kell lennie", claimMinPassword), "")
|
||||
s.handleClaimPage(w, r, s.msg(r, "claim.msg.password_too_short", claimMinPassword), "")
|
||||
return
|
||||
}
|
||||
if newPassword != confirm {
|
||||
s.handleClaimPage(w, r, "A két jelszó nem egyezik", "")
|
||||
s.handleClaimPage(w, r, s.msg(r, "claim.msg.password_mismatch"), "")
|
||||
return
|
||||
}
|
||||
|
||||
pwHash, err := bcrypt.GenerateFromPassword([]byte(newPassword), 10)
|
||||
if err != nil {
|
||||
s.logger.Printf("[ERROR] [web] claim: hashing new password: %v", err)
|
||||
s.handleClaimPage(w, r, "Belső hiba a jelszó mentésekor", "")
|
||||
s.handleClaimPage(w, r, s.msg(r, "claim.msg.save_failed"), "")
|
||||
return
|
||||
}
|
||||
if err := s.settings.SetPasswordHash(string(pwHash)); err != nil {
|
||||
s.logger.Printf("[ERROR] [web] claim: saving password: %v", err)
|
||||
s.handleClaimPage(w, r, "Belső hiba a jelszó mentésekor", "")
|
||||
s.handleClaimPage(w, r, s.msg(r, "claim.msg.save_failed"), "")
|
||||
return
|
||||
}
|
||||
// Consume the generation (single-use) + mark claimed (set-only). Order: consume BEFORE
|
||||
@@ -441,11 +446,11 @@ func (s *Server) handleClaimSubmit(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *Server) handleClaimRequestNewCode(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
if !s.validClaimCSRF(r) {
|
||||
s.handleClaimPage(w, r, "Érvénytelen űrlap — töltsd újra az oldalt.", "")
|
||||
s.handleClaimPage(w, r, s.msg(r, "claim.msg.invalid_form"), "")
|
||||
return
|
||||
}
|
||||
go s.requestHubResetCode() // fire-and-forget; the neutral response never reveals the outcome
|
||||
s.handleClaimPage(w, r, "", "Ha az e-mail cím regisztrálva van, elküldtük a kódot.")
|
||||
s.handleClaimPage(w, r, "", s.msg(r, "claim.msg.code_sent"))
|
||||
}
|
||||
|
||||
// requestHubResetCode calls POST /api/v1/claim/reset-request with the box's own report key.
|
||||
|
||||
Reference in New Issue
Block a user