connect: a guest session is not signed in for /signin's shortcut
Calls' anonymous per-meeting guests hold a session with method "guest", so the already-signed-in check sent them to / instead of the exchange, and / 404s for guests. Only HomeMethod, magiclink and keymail count now; anything else starts the exchange as before (#74 review, finding 3).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 files changed,
+28
−5
connect/routes.go+16 −3connect/routes_test.go+12 −2
CI failed — run details
CI log
amadan: .amadan/timeout: this job's budget is 15m0s (this runner allows up to 30m0s) === vet === CGO_ENABLED=0 go vet ./... go: downloading amadan.net/carlos/platform.git/launchctx v0.0.0-20260911135504-fb577f96f7d1 go: downloading amadan.net/oficina/estilo.git v0.0.0-20260911182719-0bcb9287988d internal/home/credits.go:8:2: amadan.net/oficina/estilo.git@v0.0.0-20260911182719-0bcb9287988d: invalid version: git fetch -f --end-of-options origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /home/paulca/.local/state/amadan/runner/repos/oficina__home/cache/go-mod/cache/vcs/bf4984e7a537af013cffcd0a654026b503a4e1566cddf740e3c37d2f6ae937e4: exit status 128: error: RPC failed; HTTP 429 curl 22 The requested URL returned error: 429 fatal: expected flush after ref listing internal/home/app.go:25:2: amadan.net/oficina/estilo.git@v0.0.0-20260911182719-0bcb9287988d: invalid version: git fetch -f --end-of-options origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /home/paulca/.local/state/amadan/runner/repos/oficina__home/cache/go-mod/cache/vcs/bf4984e7a537af013cffcd0a654026b503a4e1566cddf740e3c37d2f6ae937e4: exit status 128: error: RPC failed; HTTP 429 curl 22 The requested URL returned error: 429 fatal: expected flush after ref listing internal/operator/command_linux.go:10:2: amadan.net/carlos/platform.git/launchctx@v0.0.0-20260911135504-fb577f96f7d1: invalid version: git fetch -f --end-of-options origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /home/paulca/.local/state/amadan/runner/repos/oficina__home/cache/go-mod/cache/vcs/55cd75de7b117f7c5cd43edfd800f8d47521af42d6b939d46f385b6d34c14c9a: exit status 128: fatal: unable to access 'https://amadan.net/carlos/platform/': The requested URL returned error: 429 internal/operator/command_linux.go:11:2: amadan.net/carlos/platform.git/launchctx@v0.0.0-20260911135504-fb577f96f7d1: invalid version: git fetch -f --end-of-options origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /home/paulca/.local/state/amadan/runner/repos/oficina__home/cache/go-mod/cache/vcs/55cd75de7b117f7c5cd43edfd800f8d47521af42d6b939d46f385b6d34c14c9a: exit status 128: fatal: unable to access 'https://amadan.net/carlos/platform/': The requested URL returned error: 429 make: *** [Makefile:69: test-vet] Error 1 amadan: step vet failed: exit status 2 amadan: job failed at step vet — its output is above, not at the tail of this log
diff --git a/connect/routes.go b/connect/routes.go| index 9e95ebe..038b21f 100644 |
| --- a/connect/routes.go |
| +++ b/connect/routes.go |
| @@ -127,14 +127,27 @@ func (h *Routes) Signin(w http.ResponseWriter, r *http.Request) { |
| http.Redirect(w, r, handoff.StartPath+"?"+url.Values{"return_to": {path}}.Encode(), http.StatusSeeOther) |
| } |
| -// signedIn reports a live app session: exactly one session cookie, which |
| -// ReadSession resolves. An ambiguous pair or a revoked cookie is not one. |
| +// signedIn reports a live, signed-in app session: exactly one session |
| +// cookie, which ReadSession resolves to a person who signed in, through |
| +// Home (HomeMethod) or a local link (magiclink, keymail). An ambiguous |
| +// pair or a revoked cookie is not one, and neither is any other method: |
| +// Calls' anonymous per-meeting guests ("guest") are sessions but not |
| +// sign-ins, and sending one to the root instead of the exchange ends on a |
| +// 404 (the #74 review, finding 3). An unknown method falls back to the |
| +// exchange, which is what /signin did before this check existed. |
| func (h *Routes) signedIn(r *http.Request) bool { |
| if cookieCount(r, h.cfg.SessionCookie) != 1 { |
| return false |
| } |
| s, err := h.cfg.ReadSession(r) |
| - return err == nil && s != nil && s.Subject != "" |
| + if err != nil || s == nil || s.Subject == "" { |
| + return false |
| + } |
| + switch s.Method { |
| + case HomeMethod, "magiclink", "keymail": |
| + return true |
| + } |
| + return false |
| } |
| func (h *Routes) SignedOut(w http.ResponseWriter, r *http.Request) { |
diff --git a/connect/routes_test.go b/connect/routes_test.go| index 48899d9..2c7fc26 100644 |
| --- a/connect/routes_test.go |
| +++ b/connect/routes_test.go |
| @@ -125,10 +125,15 @@ func TestSigninWhenAlreadySignedIn(t *testing.T) { |
| _, n := navigationFixture(t) |
| locals := 0 |
| h := &Routes{bridge: &Bridge{render: func(w http.ResponseWriter, r *http.Request, state, label string, status int) { w.WriteHeader(status) }}, navigation: n, cfg: RoutesConfig{Origin: navigationOrigin, SessionCookie: "__Host-rastrillo_session", ReadSession: func(r *http.Request) (*Session, error) { |
| - if c, err := r.Cookie("__Host-rastrillo_session"); err != nil || c.Value != "verified" { |
| + c, err := r.Cookie("__Host-rastrillo_session") |
| + if err != nil || (c.Value != "verified" && c.Value != "guest") { |
| return nil, nil |
| } |
| - return &Session{Subject: "pr_live", Method: HomeMethod, At: time.Now()}, nil |
| + method := HomeMethod |
| + if c.Value == "guest" { |
| + method = "guest" |
| + } |
| + return &Session{Subject: "pr_live", Method: method, At: time.Now()}, nil |
| }}} |
| h.cfg.LocalSignin = func(w http.ResponseWriter, r *http.Request) { locals++; w.WriteHeader(299) } |
| live := &http.Cookie{Name: "__Host-rastrillo_session", Value: "verified"} |
| @@ -149,6 +154,11 @@ func TestSigninWhenAlreadySignedIn(t *testing.T) { |
| {"?return_to=%2Fd%2F42", nil, 303, handoff.StartPath + "?return_to=%2Fd%2F42"}, |
| {"?return_to=%2Fd%2F42", []*http.Cookie{stale}, 303, handoff.StartPath + "?return_to=%2Fd%2F42"}, |
| {"?return_to=%2Fd%2F42", []*http.Cookie{live, live}, 303, handoff.StartPath + "?return_to=%2Fd%2F42"}, |
| + // A Calls guest (an anonymous, per-meeting session) is not signed |
| + // in for this purpose: it still starts the exchange, as before, |
| + // rather than bouncing to a root that 404s for guests. |
| + {"?return_to=%2Fd%2F42", []*http.Cookie{{Name: "__Host-rastrillo_session", Value: "guest"}}, 303, handoff.StartPath + "?return_to=%2Fd%2F42"}, |
| + {"", []*http.Cookie{{Name: "__Host-rastrillo_session", Value: "guest"}}, 303, handoff.StartPath + "?return_to=%2F"}, |
| // Explicit local states still reach the local page. |
| {"?force=1", []*http.Cookie{live}, 299, ""}, |
| {"?err=removed", []*http.Cookie{live}, 299, ""}, |