Skip to content
quarry Artifact [dc57450929]
Login

Artifact [dc57450929]

Artifact dc574509291d8bbba02c4467c8957dfad9fb8d73a350962f33453245e6bee9b2:


package web

import (
	"context"
	"io"
	"net/http"
	"net/http/httptest"
	"path/filepath"
	"regexp"
	"strings"
	"testing"
	"time"

	"craftdesign.group/quarry/internal/api"
	"craftdesign.group/quarry/internal/index"
	"craftdesign.group/quarry/internal/ops"
)

// The front page is public, and so is everything it asks for once it
// has loaded. Datastar follows a redirect by NAVIGATING, so a refresh
// endpoint that answers a stranger with 303 to the login form turns a
// public page into a sign-in wall a moment after it paints — which is
// what gating the listing's refresh as an admin view did to every
// signed-out visitor. The listing is answered as the reader, so a
// private repository stays out of it for a stranger.
func TestTheFrontPageStaysOpenForAStranger(t *testing.T) {
	ix, err := index.Open(filepath.Join(t.TempDir(), "index.db"))
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { ix.Close() })
	r := ops.NewRegistry()
	if err := api.RegisterAll(r, api.Deps{Version: "v",
		Repos: api.NewRepos(map[string]*api.Repo{"alpha": {Index: ix}, "secret": {Index: ix}}),
		CanRead: func(ctx context.Context, repo string) bool {
			return repo != "secret" || ops.User(ctx) == "dan"
		},
	}); err != nil {
		t.Fatal(err)
	}
	// As the forge answers: a stranger may do what anyone may, and no more.
	verify := Verify(func(_, user, _ string, need ops.Auth) api.Decision {
		if need <= ops.Anonymous || user != "" {
			return api.Allowed
		}
		return api.Denied
	})
	srv := httptest.NewServer(HandlerWith(r, &fakeNotifier{ch: make(chan struct{}, 1)}, nil, []Option{
		WithSessions(fakeSessions{user: "dan", roles: map[string]ops.Auth{"alpha": ops.Admin}}),
	}, verify))
	t.Cleanup(srv.Close)
	client := *srv.Client()
	client.CheckRedirect = func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse }

	page, err := client.Get(srv.URL + "/")
	if err != nil {
		t.Fatal(err)
	}
	body, _ := io.ReadAll(page.Body)
	page.Body.Close()
	if page.StatusCode != http.StatusOK {
		t.Fatalf("FAIL: the front page answered a stranger %d", page.StatusCode)
	}
	asks := regexp.MustCompile(`@get\('([^']+)'`).FindAllStringSubmatch(string(body), -1)
	if len(asks) == 0 {
		t.Fatal("FAIL: the front page asks for nothing live — this test has lost what it guards")
	}
	seen := map[string]bool{}
	for _, a := range asks {
		u := a[1]
		if seen[u] {
			continue
		}
		seen[u] = true
		req, _ := http.NewRequest("GET", srv.URL+u, nil)
		req.Header.Set("Datastar-Request", "true")
		ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
		resp, err := client.Do(req.WithContext(ctx))
		if err != nil {
			cancel()
			t.Fatalf("FAIL: %s: %v", u, err)
		}
		if resp.StatusCode != http.StatusOK {
			t.Errorf("FAIL: the front page asks for %s, which answers a stranger %d %s", u,
				resp.StatusCode, resp.Header.Get("Location"))
		}
		if strings.HasSuffix(u, ".frag") {
			b, _ := io.ReadAll(resp.Body)
			if !strings.Contains(string(b), `id="explore"`) {
				t.Errorf("FAIL: %s did not answer with the listing", u)
			}
			if strings.Contains(string(b), "secret") {
				t.Errorf("FAIL: %s named a private repository to a stranger", u)
			}
		}
		resp.Body.Close()
		cancel()
	}
}