Skip to content
quarry Artifact [a8be0f9cf4]
Login

Artifact [a8be0f9cf4]

Artifact a8be0f9cf44eddcea321547fae157a8ac182b9c74062ea4e565e264dfe97e569:


package main

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"path/filepath"
	"strings"
	"sync"
	"testing"

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

// The networked CLI is a forge door like the web: it can ask for a
// reset link to go to the owner, and it cannot set anybody's password.
func TestTheNetworkedCLIAsksForAResetAndSetsNoPassword(t *testing.T) {
	var mu sync.Mutex
	var hits []string
	var bodies []map[string]any
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var b map[string]any
		_ = json.NewDecoder(r.Body).Decode(&b)
		mu.Lock()
		hits, bodies = append(hits, r.URL.Path), append(bodies, b)
		mu.Unlock()
		w.Header().Set("Content-Type", "application/json")
		_, _ = w.Write([]byte(`{"name":"jo","emailed":true}`))
	}))
	defer srv.Close()

	if err := accountAPICmd([]string{"passwd", "--server", srv.URL, "--as", "root", "--as-password", "pw",
		"--user", "jo", "--password", "chosen-by-root"}); err == nil {
		t.Error("FAIL: `quarry accounts passwd` still answers")
	}
	for _, h := range hits {
		if strings.Contains(h, "passwd") {
			t.Fatalf("FAIL: the CLI reached %s", h)
		}
	}

	if err := accountAPICmd([]string{"reset", "--server", srv.URL, "--as", "root", "--as-password", "pw",
		"--user", "jo"}); err != nil {
		t.Fatal(err)
	}
	if len(hits) != 1 || hits[0] != "/api/v1/accounts/reset" {
		t.Fatalf("FAIL: want one call to /api/v1/accounts/reset, got %v", hits)
	}
	if bodies[0]["name"] != "jo" || len(bodies[0]) != 1 {
		t.Errorf("FAIL: reset body = %v", bodies[0])
	}
	t.Log("ok: the CLI asks for a reset link and has no passwd")
}

// Recovering an account on the box stays possible — it is the host
// operator's act, not the forge admin's — and it is journalled.
func TestTheHostOperatorsPasswdIsJournalled(t *testing.T) {
	dir := t.TempDir()
	if err := accountCmd([]string{"add", "--data", dir, "--user", "jo", "--password", "jos-password"}); err != nil {
		t.Fatal(err)
	}
	if err := accountCmd([]string{"passwd", "--data", dir, "--user", "jo", "--password", "a-recovered-password"}); err != nil {
		t.Fatal(err)
	}
	db, err := oltp.Open(filepath.Join(dir, "oltp.db"))
	if err != nil {
		t.Fatal(err)
	}
	defer db.Close()
	acts, err := db.AccountActs("jo", 10)
	if err != nil {
		t.Fatal(err)
	}
	if len(acts) != 1 || acts[0].Op != "account passwd" || acts[0].Owner != "jo" || !strings.HasPrefix(acts[0].Actor, "host:") {
		t.Fatalf("FAIL: journal = %+v", acts)
	}
	if strings.Contains(acts[0].Actor+acts[0].Op+acts[0].Repo+acts[0].Owner, "a-recovered-password") {
		t.Fatal("FAIL: the password is in the journal")
	}
	t.Log("ok: the host operator's recovery is journalled")
}