Offer explicit local sign-in recovery after refused Home handoff
2 files changed,
+32
−2
connect/routes_test.go+30 −0connect/view.go+2 −2
CI passed — run details
diff --git a/connect/routes_test.go b/connect/routes_test.go| index 4fe0ba5..cbfbef7 100644 |
| --- a/connect/routes_test.go |
| +++ b/connect/routes_test.go |
| @@ -2,8 +2,10 @@ package connect |
| import ( |
| "amadan.net/oficina/home/handoff" |
| + "html/template" |
| "net/http" |
| "net/http/httptest" |
| + "strings" |
| "testing" |
| ) |
| @@ -70,3 +72,31 @@ func TestSignoutEndsLocallyAndClearsHandoffPointers(t *testing.T) { |
| } |
| } |
| } |
| + |
| +func TestStaleSessionStillRefusesAndOffersExplicitLocalRecovery(t *testing.T) { |
| + f := newBridgeFixture(t) |
| + templates := template.Must(template.ParseFS(Templates(), "templates/*.html")) |
| + f.b.render = func(w http.ResponseWriter, r *http.Request, state, label string, status int) { |
| + w.WriteHeader(status) |
| + if err := templates.ExecuteTemplate(w, "home-connect", Page(state, label)); err != nil { |
| + t.Fatal(err) |
| + } |
| + } |
| + token, err := f.sessions.Mint(Session{Subject: "retired-session", Method: "magiclink"}) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + delete(f.sessions.values, token) |
| + r := bridgeRequest("GET", "/auth/start", []*http.Cookie{{Name: f.sessions.cookie, Value: token}}) |
| + w := httptest.NewRecorder() |
| + f.b.Start(w, r) |
| + if w.Code != 403 || w.Header().Get("Location") != "" { |
| + t.Fatal("stale cookie guard relaxed", w.Code) |
| + } |
| + if !strings.Contains(w.Body.String(), `href="/signin/local"`) || !strings.Contains(w.Body.String(), English["local_action"]) { |
| + t.Fatal("no explicit local recovery", w.Body.String()) |
| + } |
| + if len(w.Result().Cookies()) != 0 || len(f.sessions.values) != 0 { |
| + t.Fatal("failure changed session state") |
| + } |
| +} |
diff --git a/connect/view.go b/connect/view.go| index 5ea1f5f..712ded2 100644 |
| --- a/connect/view.go |
| +++ b/connect/view.go |
| @@ -38,8 +38,8 @@ func Page(state, label string, translate ...func(string) string) PageData { |
| p.ActionLabel = t("documents_action") |
| default: |
| state = "failed" |
| - p.Action = "/account/home" |
| - p.ActionLabel = t("menu_action") |
| + p.Action = "/signin/local" |
| + p.ActionLabel = t("local_action") |
| } |
| p.Title = t(state + "_title") |
| p.Body = t(state + "_body") |