hub 0.164.0 (unreleased): bind mail true when no box exists (W3), tries left on a wrong try (W4), use the newer mail hint (W5)
gates / gates (push) Failing after 14m55s
gates / gates (push) Failing after 14m55s
This commit is contained in:
1 parent
3c620f8d2e
commit
f90e22293a
7 files changed
+74
-8
No files matched your search
@@ -102,6 +102,9 @@ type bindPageData struct {
|
||||
State string // "form" | "success" | "expired" | "consumed" | "locked" | "resent" | "oldbox" (R-1203)
|
||||
Token string // echoed into the form action (the capability itself; already in the URL)
|
||||
Failed bool // generic factor-check failure (form state only)
|
||||
// AttemptsLeft (W4, night 2026-10-21) is how many tries the link has before it locks — said beside the failure,
|
||||
// so the household is not surprised by the lock (which only support can open). 0 = not shown.
|
||||
AttemptsLeft int
|
||||
// Lang is the language to render in. It is the CUSTOMER'S CREATION-TIME language and nothing
|
||||
// else: no box has reported yet at bind time, and this page deliberately offers no switch —
|
||||
// the person opening it is a stranger holding a capability URL, exactly like the guest share
|
||||
@@ -249,7 +252,11 @@ func (s *Server) handleBind(w http.ResponseWriter, r *http.Request) {
|
||||
s.renderBind(w, http.StatusOK, bindPageData{State: "locked", Lang: lang})
|
||||
return
|
||||
}
|
||||
s.renderBind(w, http.StatusOK, bindPageData{State: "form", Token: token, Failed: true, Lang: lang})
|
||||
left := store.SelfBindMaxAttempts - attempts
|
||||
if left < 0 {
|
||||
left = 0
|
||||
}
|
||||
s.renderBind(w, http.StatusOK, bindPageData{State: "form", Token: token, Failed: true, AttemptsLeft: left, Lang: lang})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -318,7 +325,7 @@ const bindPageHTML = `<!DOCTYPE html>
|
||||
<h1>{{T "bind.heading"}}</h1>
|
||||
{{if eq .State "form"}}
|
||||
<p class="lead">{{T "bind.lead"}}</p>
|
||||
{{if .Failed}}<div class="banner">{{T "bind.failed"}}</div>{{end}}
|
||||
{{if .Failed}}<div class="banner">{{T "bind.failed"}}{{if .AttemptsLeft}} {{T "bind.attempts_left.pre"}} {{.AttemptsLeft}}{{T "bind.attempts_left.post"}}{{end}}</div>{{end}}
|
||||
<form method="POST" action="/bind/{{.Token}}">
|
||||
<label for="pairing_code">{{T "bind.label.pairing"}}</label>
|
||||
<input class="code" type="text" id="pairing_code" name="pairing_code" autocomplete="off" autocapitalize="characters" spellcheck="false" required autofocus placeholder="{{T "bind.placeholder.pairing"}}">
|
||||
@@ -335,6 +342,7 @@ const bindPageHTML = `<!DOCTYPE html>
|
||||
{{else if eq .State "consumed"}}
|
||||
<p class="lead">{{T "bind.consumed.lead"}}</p>
|
||||
<p>{{T "bind.consumed.body"}}</p>
|
||||
<p class="hint">{{T "bind.resend.newer"}}</p>
|
||||
<form method="POST" action="/bind/{{.Token}}/resend"><p class="hint">{{T "bind.resend.hint"}}</p><button type="submit">{{T "bind.resend.button"}}</button></form>
|
||||
{{else if eq .State "oldbox"}}
|
||||
<p class="lead">{{T "bind.oldbox.lead"}}</p>
|
||||
@@ -348,6 +356,7 @@ const bindPageHTML = `<!DOCTYPE html>
|
||||
{{else}}
|
||||
<p class="lead">{{T "bind.invalid.lead"}}</p>
|
||||
{{if .Token}}<p>{{T "bind.invalid.body_resend"}}</p>
|
||||
<p class="hint">{{T "bind.resend.newer"}}</p>
|
||||
<form method="POST" action="/bind/{{.Token}}/resend"><p class="hint">{{T "bind.resend.hint"}}</p><button type="submit">{{T "bind.resend.button"}}</button></form>
|
||||
{{else}}<p>{{T "bind.invalid.body"}}</p>{{end}}
|
||||
{{end}}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gitea.dooplex.hu/admin/felhom-hub/internal/store"
|
||||
)
|
||||
|
||||
// W4 (rehearsal word table, night 2026-10-21): a wrong try says how many tries are left before the link locks — the
|
||||
// fifth locks it and only support can open it. The count is the same for a wrong code and a wrong passphrase, so the
|
||||
// no-oracle rule (TestSelfBind_B_NoOracle) holds.
|
||||
// RED-PROOF: with AttemptsLeft not set on the failure render the „Még N" sentence is missing → fails at attempt 1.
|
||||
func TestW4_AWrongTrySaysHowManyTriesAreLeft(t *testing.T) {
|
||||
s, st := newTestServer(t)
|
||||
selfBindSetup(t, st, "acme", testCode)
|
||||
token := mintLink(t, st, "acme", selfBindTTL)
|
||||
for i := 1; i < store.SelfBindMaxAttempts; i++ {
|
||||
body := bindPOST(t, s, token, "ZZZ999", "definitely wrong words indeed").Body.String()
|
||||
want := fmt.Sprintf("Még %d próbálkozásod van", store.SelfBindMaxAttempts-i)
|
||||
if !strings.Contains(body, want) {
|
||||
t.Fatalf("attempt %d: the page must say %q", i, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// W5: on a used or expired link the page says to use the newer mail before „Új linket kérek" (a new link kills the
|
||||
// one the household may be about to use — TestSelfBind_C4_SingleActive).
|
||||
func TestW5_AnOldLinkPointsToTheNewerMail(t *testing.T) {
|
||||
s, st := newTestServer(t)
|
||||
selfBindSetup(t, st, "acme", testCode)
|
||||
token := mintLink(t, st, "acme", -1) // already expired
|
||||
body := bindGET(t, s, token).Body.String()
|
||||
if !strings.Contains(body, "újabb leveled") || !strings.Contains(body, "Új linket kérek") {
|
||||
t.Fatalf("an expired link must point to the newer mail above the button: %q", body)
|
||||
}
|
||||
if strings.Index(body, "újabb leveled") > strings.Index(body, "Új linket kérek") {
|
||||
t.Fatal("the newer-mail hint must come BEFORE the button")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user