Skip to content
quarry Artifact [5e15613373]
Login

Artifact [5e15613373]

Artifact 5e1561337300518b65cb7b9e95fe3009e0cb4db64b8070bf775f8923038b9708:


package main

import (
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"net/http/httptest"
	"path/filepath"
	"strings"
	"testing"

	"craftdesign.group/quarry/internal/api"
	"craftdesign.group/quarry/internal/oltp"
	"craftdesign.group/quarry/internal/web"
)

// pickupAsk files an approved request for repo bound to a fresh key and
// holding a secret, and returns the key.
func pickupAsk(t *testing.T, g siteRig, repo string, n int) string {
	t.Helper()
	raw := make([]byte, 32)
	if _, err := rand.Read(raw); err != nil {
		t.Fatal(err)
	}
	s, err := g.db.RequestSignOff(oltp.SignOff{Agent: "bot", Owner: "alice", Op: "ci.worker.token.new", Repo: repo,
		Input: fmt.Sprintf(`{"n":%d}`, n), Summary: "x", Pickup: api.PickupCodeOf(raw)})
	if err != nil {
		t.Fatal(err)
	}
	if _, err := g.db.DecideSignOff(s.ID, "alice", true); err != nil {
		t.Fatal(err)
	}
	if err := g.db.FinishSignOff(s.ID, `{}`, `{"value":"the-credential"}`); err != nil {
		t.Fatal(err)
	}
	return base64.RawURLEncoding.EncodeToString(raw)
}

// Both pickup routes reach the collector through the real handler, for
// a private repository, a namespaced path and one that does not exist,
// before any visibility gate: a wrong key and no key answer all of them
// with the one JSON 404, and the right key is served (or, for a
// repository the credential does not reach, told so with a 409).
func TestThePickupRoutesAreReachedBeforeAnyGate(t *testing.T) {
	g := newSiteRig(t)
	calls := 0
	do := func(path, auth string) (int, string, string) {
		calls++
		req := httptest.NewRequest("POST", path, nil)
		req.RemoteAddr = fmt.Sprintf("192.0.2.%d:1", calls)
		if auth != "" {
			req.Header.Set("Authorization", auth)
		}
		w := httptest.NewRecorder()
		g.h.ServeHTTP(w, req)
		return w.Code, w.Body.String(), w.Header().Get("Content-Type")
	}
	fresh := func() string {
		raw := make([]byte, 32)
		rand.Read(raw)
		return "Pickup " + base64.RawURLEncoding.EncodeToString(raw)
	}
	paths := []string{"/api/v1/pickups/collect", "/r/pub/pickup", "/r/secret/pickup", "/r/alice/secret/pickup", "/r/alice/pub/pickup", "/r/nonexistent/pickup", "/r/alice/nonexistent/pickup"}
	var wantStatus int
	var wantBody string
	for i, path := range paths {
		// A request without the Pickup scheme is not the collector's
		// (see TestOnlyAPickupSchemeReachesTheCollector).
		for _, auth := range []string{fresh()} {
			st, body, ct := do(path, auth)
			if !strings.Contains(ct, "json") {
				t.Errorf("FAIL: %s with %q answered %q, not the collector's JSON", path, auth, ct)
			}
			if i == 0 {
				wantStatus, wantBody = st, body
			}
			if st != wantStatus || body != wantBody || st != 404 {
				t.Errorf("FAIL: %s with %q answered %d %s, want the one 404 %s", path, auth, st, body, wantBody)
			}
		}
	}
	for i, c := range []struct {
		path, repo string
		want       int
	}{
		{"/api/v1/pickups/collect", "secret", 200},
		{"/r/secret/pickup", "secret", 200},
		{"/r/alice/secret/pickup", "secret", 200},
		{"/r/alice/pub/pickup", "pub", 200},
		{"/r/nonexistent/pickup", "secret", 409},
		{"/r/alice/nonexistent/pickup", "secret", 409},
	} {
		key := pickupAsk(t, g, c.repo, i)
		st, body, _ := do(c.path, "Pickup "+key)
		if st != c.want || (st == 200 && !strings.Contains(body, "the-credential")) {
			t.Errorf("FAIL: right key at %s answered %d %s", c.path, st, body)
		}
		if st == 409 {
			if again, _, _ := do("/r/secret/pickup", "Pickup "+key); again != 200 {
				t.Errorf("FAIL: a 409 consumed the secret: %d", again)
			}
		}
	}
	if !t.Failed() {
		t.Log("ok")
	}
}

// The forge's own sign-in limiter, as the collect route is given it:
// six wrong keys from one address answer 404, and from then on its wrong
// keys are held with 429.
func TestThePickupRouteHoldsAnAddressAfterWrongKeys(t *testing.T) {
	db, err := oltp.Open(filepath.Join(t.TempDir(), "o.db"))
	if err != nil {
		t.Fatal(err)
	}
	defer db.Close()
	var lim api.PickupLimiter = web.NewLoginLimiter()
	c := api.NewPickupCollector(api.Deps{SignOffs: signOffStore{db}}, lim, nil)
	key := func(c byte) string { return "Pickup " + strings.Repeat(string(rune(c)), 43) }
	do := func(auth string) int {
		req := httptest.NewRequest("POST", "/api/v1/pickups/collect", nil)
		req.Header.Set("Authorization", auth)
		req.RemoteAddr = "192.0.2.9:1"
		w := httptest.NewRecorder()
		c.ServeHTTP(w, req)
		return w.Code
	}
	for i := 0; i < 6; i++ {
		if st := do(key(byte('A' + i))); st != 404 {
			t.Fatalf("FAIL: wrong key %d answered %d", i, st)
		}
	}
	if st := do(key('Z')); st != 429 {
		t.Errorf("FAIL: a held address answered %d", st)
	}
	if !t.Failed() {
		t.Log("ok")
	}
}