package authz
import (
"encoding/json"
"net/http"
"net/http/httptest"
"os"
"testing"
"sourcecraft.dev/bigbes/sr-ht-core/crypto"
"sourcecraft.dev/bigbes/sr-ht-ecore/ecoretest"
)
// TestMain installs ecore's fixed test keyset into core-go's process-global
// crypto, so Encrypt/Decrypt work offline. The keys are constants and the call
// is idempotent, which is what lets this package and web/ both initialise
// without the second rotating what the first sealed with.
func TestMain(m *testing.M) {
ecoretest.InitCrypto()
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)
}
}