package web
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"craftdesign.group/quarry/internal/api"
"craftdesign.group/quarry/internal/ops"
)
// linkSessions opens one session for one link, once.
type linkSessions struct {
*betaSessions
spent bool
}
func (l *linkSessions) RedeemSigninLink(link, ip, agent string) (string, time.Time, string, bool) {
if link != "good" || l.spent {
return "", time.Time{}, "", false
}
l.spent = true
return "cookie-from-link", time.Now().Add(time.Hour), "/r/quarry", true
}
func signinServer(t *testing.T, sess Sessions) *httptest.Server {
t.Helper()
r := ops.NewRegistry()
if err := api.RegisterAll(r, api.Deps{Version: "v", Repos: api.NewRepos(map[string]*api.Repo{})}); err != nil {
t.Fatal(err)
}
srv := httptest.NewServer(HandlerWith(r, nil, nil, []Option{WithSessions(sess)},
Verify(func(string, string, string, ops.Auth) api.Decision { return api.Denied })))
t.Cleanup(srv.Close)
return srv
}
func getNoFollow(t *testing.T, url string) *http.Response {
t.Helper()
client := &http.Client{CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse }}
res, err := client.Get(url)
if err != nil {
t.Fatal(err)
}
return res
}
// A SIGN-IN LINK OPENS ONE SESSION AND REDIRECTS AT ONCE WITH NO
// REFERRER; THE SECOND GET, AND ANY UNKNOWN LINK, IS ONE PAGE WITH NO
// REDIRECT.
func TestSigninLinkRedirectsOnceAndSpends(t *testing.T) {
accts := newBetaAccts()
srv := signinServer(t, &linkSessions{betaSessions: &betaSessions{accts: accts}})
res := getNoFollow(t, srv.URL+"/signin/good")
var cookie *http.Cookie
for _, c := range res.Cookies() {
if c.Name == sessionCookie {
cookie = c
}
}
if res.StatusCode != http.StatusSeeOther || res.Header.Get("Location") != "/r/quarry" {
t.Errorf("FAIL: first GET = %d to %q; want 303 to /r/quarry", res.StatusCode, res.Header.Get("Location"))
}
if res.Header.Get("Referrer-Policy") != "no-referrer" {
t.Errorf("FAIL: Referrer-Policy = %q; want no-referrer", res.Header.Get("Referrer-Policy"))
}
if cookie == nil || cookie.Value != "cookie-from-link" || !cookie.HttpOnly {
t.Errorf("FAIL: session cookie = %+v; want the link's, HttpOnly", cookie)
}
for _, path := range []string{"/signin/good", "/signin/unknown"} {
res := getNoFollow(t, srv.URL+path)
if res.StatusCode != http.StatusNotFound || res.Header.Get("Location") != "" || len(res.Cookies()) != 0 {
t.Errorf("FAIL: %s = %d location %q cookies %d; want 404, no redirect, no cookie",
path, res.StatusCode, res.Header.Get("Location"), len(res.Cookies()))
}
if res.Header.Get("Referrer-Policy") != "no-referrer" {
t.Errorf("FAIL: %s lacks Referrer-Policy: no-referrer", path)
}
}
}
// A FORGE WHOSE SESSIONS CANNOT REDEEM ANSWERS EVERY LINK AS SPENT.
func TestSigninLinkWithoutRedeemerIsSpent(t *testing.T) {
srv := signinServer(t, &betaSessions{accts: newBetaAccts()})
res := getNoFollow(t, srv.URL+"/signin/good")
if res.StatusCode != http.StatusNotFound || strings.Contains(res.Header.Get("Set-Cookie"), sessionCookie) {
t.Errorf("FAIL: got %d with cookie %q; want 404 and none", res.StatusCode, res.Header.Get("Set-Cookie"))
}
}