package api import ( "net/http" "net/http/httptest" "path/filepath" "testing" "time" "hamlab/internal/auth" "hamlab/internal/config" "hamlab/internal/store" ) // A guest login is an ordinary account with a clock on it, so the clock is the thing worth // testing: one whose time is up is stopped at the door, whether or not the minute-by-minute // sweep has reached their account yet, and their session is dropped on the way — so the // console they left open goes back to the login form rather than carrying on. func TestExpiredGuestIsRefusedAndSignedOut(t *testing.T) { for _, tc := range []struct { name string expires time.Time wantOK bool }{ {"still has time", time.Now().Add(10 * time.Minute), true}, {"time is up", time.Now().Add(-time.Second), false}, {"no expiry at all", time.Time{}, false}, } { t.Run(tc.name, func(t *testing.T) { dir := t.TempDir() cfg := config.Default(filepath.Join(dir, "config.json")) if err := cfg.Update(func(c *config.Config) { c.Users = []config.User{{Name: "guest-abcd", Hash: "x", Guest: true, Expires: tc.expires}} }); err != nil { t.Fatal(err) } st, err := store.Open(filepath.Join(dir, "state.json")) if err != nil { t.Fatal(err) } s := &Server{cfg: cfg, store: st, sessions: auth.NewSessions(st)} tok, err := s.sessions.Create("guest-abcd", "10.0.0.5", "curl") if err != nil { t.Fatal(err) } r := httptest.NewRequest("GET", "/api/me", nil) r.AddCookie(&http.Cookie{Name: cookieName, Value: tok}) w := httptest.NewRecorder() a, ok, answered := s.cookieActor(w, r) if ok != tc.wantOK { t.Fatalf("ok = %v, want %v", ok, tc.wantOK) } if tc.wantOK { if !a.Guest || a.User != "guest-abcd" { t.Errorf("actor = %+v, want the guest account marked as one", a) } if answered { t.Error("answered the caller for a guest that still has time") } return } if !answered || w.Code != 401 { t.Errorf("answered = %v, code = %d, want true and 401", answered, w.Code) } if _, live := s.sessions.Lookup(tok, "10.0.0.5"); live { t.Error("the session of an expired guest is still live") } }) } }