~bigbes/sr-ht-compare

ref: c1ae0fc527c571bcbdfce0af2296f404e4e9dadc sr-ht-compare/authz/identity_test.go -rw-r--r-- 3.7 KiB
c1ae0fc5 — bigbes go.mod: tidy and complete the README 30 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package authz

import (
	"crypto/rand"
	"encoding/base64"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"

	"git.sr.ht/~sircmpwn/core-go/crypto"
	"github.com/fernet/fernet-go"
	"github.com/vaughan0/go-ini"
)

// testConf holds the crypto keys shared by every test. api-origin is filled in
// per-test (it points at an ephemeral httptest server).
var testConf ini.File

// TestMain synthesizes an in-memory config with a fresh Fernet network-key and
// an ed25519 webhook seed, then runs crypto.InitCrypto so Encrypt/Decrypt work.
func TestMain(m *testing.M) {
	var fk fernet.Key
	if err := fk.Generate(); err != nil {
		panic("generate fernet key: " + err.Error())
	}
	seed := make([]byte, 32)
	if _, err := rand.Read(seed); err != nil {
		panic("generate webhook seed: " + err.Error())
	}

	testConf = ini.File{
		"sr.ht":         ini.Section{"network-key": fk.Encode()},
		"webhooks":      ini.Section{"private-key": base64.StdEncoding.EncodeToString(seed)},
		"compare.sr.ht": ini.Section{"origin": "http://localhost"},
	}
	crypto.InitCrypto(testConf)

	os.Exit(m.Run())
}

// sealCookie builds a valid unified-login cookie value carrying the given name.
func sealCookie(t *testing.T, name string) string {
	t.Helper()
	payload, err := json.Marshal(map[string]string{"name": name})
	if err != nil {
		t.Fatalf("marshal claims: %v", err)
	}
	return string(crypto.Encrypt(payload))
}

func TestUsernameFromRequest_RoundTrip(t *testing.T) {
	r := httptest.NewRequest(http.MethodGet, "/", nil)
	r.AddCookie(&http.Cookie{Name: CookieName, Value: sealCookie(t, "bigbes")})
	if got := UsernameFromRequest(r); got != "bigbes" {
		t.Fatalf("username = %q, want %q", got, "bigbes")
	}
}

func TestUsernameFromRequest_StripsTilde(t *testing.T) {
	r := httptest.NewRequest(http.MethodGet, "/", nil)
	r.AddCookie(&http.Cookie{Name: CookieName, Value: sealCookie(t, "~bigbes")})
	if got := UsernameFromRequest(r); got != "bigbes" {
		t.Fatalf("username = %q, want %q", got, "bigbes")
	}
}

func TestUsernameFromRequest_GarbageCookie(t *testing.T) {
	r := httptest.NewRequest(http.MethodGet, "/", nil)
	r.AddCookie(&http.Cookie{Name: CookieName, Value: "not-a-valid-fernet-token"})
	if got := UsernameFromRequest(r); got != "" {
		t.Fatalf("username = %q, want empty", got)
	}
}

func TestUsernameFromRequest_MissingCookie(t *testing.T) {
	r := httptest.NewRequest(http.MethodGet, "/", nil)
	if got := UsernameFromRequest(r); got != "" {
		t.Fatalf("username = %q, want empty", got)
	}
}

func TestUsernameFromRequest_NonJSONPayload(t *testing.T) {
	r := httptest.NewRequest(http.MethodGet, "/", nil)
	// A well-formed Fernet token whose plaintext is not JSON.
	r.AddCookie(&http.Cookie{Name: CookieName, Value: string(crypto.Encrypt([]byte("plain text")))})
	if got := UsernameFromRequest(r); got != "" {
		t.Fatalf("username = %q, want empty", got)
	}
}

func TestMiddlewareAndForContext(t *testing.T) {
	var seen string
	h := Middleware()(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		seen = ForContext(r.Context())
	}))

	r := httptest.NewRequest(http.MethodGet, "/", nil)
	r.AddCookie(&http.Cookie{Name: CookieName, Value: sealCookie(t, "bigbes")})
	h.ServeHTTP(httptest.NewRecorder(), r)
	if seen != "bigbes" {
		t.Fatalf("ForContext = %q, want %q", seen, "bigbes")
	}

	// Anonymous request: middleware still runs, ForContext yields "".
	seen = "sentinel"
	h.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest(http.MethodGet, "/", nil))
	if seen != "" {
		t.Fatalf("anonymous ForContext = %q, want empty", seen)
	}
}

func TestForContext_NoValue(t *testing.T) {
	if got := ForContext(httptest.NewRequest(http.MethodGet, "/", nil).Context()); got != "" {
		t.Fatalf("ForContext on bare context = %q, want empty", got)
	}
}