Skip to content
quarry Artifact [7c217cf062]
Login

Artifact [7c217cf062]

Artifact 7c217cf062ecec7d0a80b262506e285bded2e4dedc26250aade80f644ee39016:


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"))
	}
}