package authn
import (
"testing"
"sourcecraft.dev/bigbes/sr-ht-core/crypto"
)
func TestUsernameFromRequest_ValidCookieRoundTrips(t *testing.T) {
got := UsernameFromRequest(request(sealCookie(t, "bigbes"), nil))
if got != "bigbes" {
t.Fatalf("username = %q, want %q", got, "bigbes")
}
}
func TestUsernameFromRequest_StripsTilde(t *testing.T) {
got := UsernameFromRequest(request(sealCookie(t, "~bigbes"), nil))
if got != "bigbes" {
t.Fatalf("username = %q, want %q", got, "bigbes")
}
}
// A cookie whose ciphertext has been altered must fail the Fernet HMAC and read
// as anonymous — not as an error, and certainly not as an identity.
func TestUsernameFromRequest_TamperedCookieIsAnonymous(t *testing.T) {
got := UsernameFromRequest(request(tamper(t, sealCookie(t, "bigbes")), nil))
if got != "" {
t.Fatalf("tampered cookie yielded %q, want anonymous", got)
}
}
func TestUsernameFromRequest_AbsentCookieIsAnonymous(t *testing.T) {
if got := UsernameFromRequest(request("", nil)); got != "" {
t.Fatalf("absent cookie yielded %q, want anonymous", got)
}
}
func TestUsernameFromRequest_GarbageIsAnonymous(t *testing.T) {
for name, value := range map[string]string{
"not base64": "not-a-valid-fernet-token",
"empty": "",
"truncated fernet": sealCookie(t, "bigbes")[:10],
} {
t.Run(name, func(t *testing.T) {
if got := UsernameFromCookie(value); got != "" {
t.Fatalf("garbage cookie yielded %q, want anonymous", got)
}
})
}
}
// A cookie sealed under a key we no longer hold — the shape of both a rotated
// network key and an outright forgery. It must expire the session, not the
// request.
func TestUsernameFromCookie_ForeignKeyIsAnonymous(t *testing.T) {
value := sealCookieWithKey(t, &rotatedKey, "bigbes")
if got := UsernameFromCookie(value); got != "" {
t.Fatalf("cookie under a foreign key yielded %q, want anonymous", got)
}
// Sanity: the same payload under the live key does resolve, so the test
// above is proving the key check and not a broken helper.
if got := UsernameFromCookie(sealCookie(t, "bigbes")); got != "bigbes" {
t.Fatalf("control cookie yielded %q, want %q", got, "bigbes")
}
}
func TestUsernameFromCookie_NonJSONPayloadIsAnonymous(t *testing.T) {
value := string(crypto.Encrypt([]byte("plain text, well sealed")))
if got := UsernameFromCookie(value); got != "" {
t.Fatalf("non-JSON payload yielded %q, want anonymous", got)
}
}
// A well-sealed cookie can still carry a name we must refuse to treat as an
// identity: empty, or something that would not survive being used as a path
// segment or a log field.
func TestUsernameFromCookie_UnusableNameIsAnonymous(t *testing.T) {
for _, name := range []string{
"",
"..",
"../../etc/passwd",
"has space",
"Uppercase",
"-leading-dash",
} {
t.Run(name, func(t *testing.T) {
if got := UsernameFromCookie(sealCookie(t, name)); got != "" {
t.Fatalf("cookie name %q yielded %q, want anonymous", name, got)
}
})
}
}