114 lines
3.3 KiB
Go
114 lines
3.3 KiB
Go
package auth
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"errors"
|
||
|
|
"testing"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestPreferMembershipRoleNeverDemotesAdmin(t *testing.T) {
|
||
|
|
t.Parallel()
|
||
|
|
cases := []struct {
|
||
|
|
name string
|
||
|
|
existing string
|
||
|
|
invited string
|
||
|
|
want string
|
||
|
|
}{
|
||
|
|
{name: "admin stays admin on member invite", existing: "admin", invited: "member", want: "admin"},
|
||
|
|
{name: "admin stays admin on admin invite", existing: "admin", invited: "admin", want: "admin"},
|
||
|
|
{name: "member promotes to admin", existing: "member", invited: "admin", want: "admin"},
|
||
|
|
{name: "member stays member", existing: "member", invited: "member", want: "member"},
|
||
|
|
{name: "unknown invited normalizes to member", existing: "member", invited: "owner", want: "member"},
|
||
|
|
{name: "empty existing yields invited role", existing: "", invited: "admin", want: "admin"},
|
||
|
|
}
|
||
|
|
for _, tc := range cases {
|
||
|
|
t.Run(tc.name, func(t *testing.T) {
|
||
|
|
t.Parallel()
|
||
|
|
got := preferMembershipRole(tc.existing, tc.invited)
|
||
|
|
if got != tc.want {
|
||
|
|
t.Fatalf("preferMembershipRole(%q, %q)=%q want %q", tc.existing, tc.invited, got, tc.want)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestHashInviteTokenMatchesAPIKeyHash(t *testing.T) {
|
||
|
|
t.Parallel()
|
||
|
|
const raw = "invite-plaintext-secret"
|
||
|
|
got := HashInviteToken(raw)
|
||
|
|
if got != HashAPIKey(raw) {
|
||
|
|
t.Fatalf("HashInviteToken must match HashAPIKey construction")
|
||
|
|
}
|
||
|
|
if len(got) != 64 {
|
||
|
|
t.Fatalf("expected sha256 hex length 64, got %d", len(got))
|
||
|
|
}
|
||
|
|
if got == raw {
|
||
|
|
t.Fatal("invite token must not be stored as plaintext")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestNormalizeInviteRole(t *testing.T) {
|
||
|
|
t.Parallel()
|
||
|
|
if normalizeInviteRole("Admin") != "admin" {
|
||
|
|
t.Fatal("expected admin")
|
||
|
|
}
|
||
|
|
if normalizeInviteRole(" MEMBER ") != "member" {
|
||
|
|
t.Fatal("expected member")
|
||
|
|
}
|
||
|
|
if normalizeInviteRole("owner") != "member" {
|
||
|
|
t.Fatal("unknown roles collapse to member")
|
||
|
|
}
|
||
|
|
if NormalizeMembershipRole("Admin") != "admin" {
|
||
|
|
t.Fatal("NormalizeMembershipRole should accept Admin")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestParseMembershipRole(t *testing.T) {
|
||
|
|
t.Parallel()
|
||
|
|
got, err := ParseMembershipRole(" Admin ")
|
||
|
|
if err != nil || got != "admin" {
|
||
|
|
t.Fatalf("admin: got %q err=%v", got, err)
|
||
|
|
}
|
||
|
|
got, err = ParseMembershipRole("MEMBER")
|
||
|
|
if err != nil || got != "member" {
|
||
|
|
t.Fatalf("member: got %q err=%v", got, err)
|
||
|
|
}
|
||
|
|
if _, err := ParseMembershipRole("owner"); !errors.Is(err, ErrInvalidMembershipRole) {
|
||
|
|
t.Fatalf("owner: err=%v want ErrInvalidMembershipRole", err)
|
||
|
|
}
|
||
|
|
if _, err := ParseMembershipRole(""); !errors.Is(err, ErrInvalidMembershipRole) {
|
||
|
|
t.Fatalf("empty: err=%v want ErrInvalidMembershipRole", err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestIsSyntheticLegacyEmail(t *testing.T) {
|
||
|
|
t.Parallel()
|
||
|
|
if !IsSyntheticLegacyEmail("user_abc@legacy.local") {
|
||
|
|
t.Fatal("expected synthetic")
|
||
|
|
}
|
||
|
|
if !IsSyntheticLegacyEmail(" User@Legacy.Local ") {
|
||
|
|
t.Fatal("expected case-insensitive synthetic")
|
||
|
|
}
|
||
|
|
if IsSyntheticLegacyEmail("real@example.com") {
|
||
|
|
t.Fatal("real email must not be treated as synthetic")
|
||
|
|
}
|
||
|
|
if IsSyntheticLegacyEmail("legacy.local@example.com") {
|
||
|
|
t.Fatal("suffix-only match; local-part must not trigger")
|
||
|
|
}
|
||
|
|
if IsSyntheticLegacyEmail("") {
|
||
|
|
t.Fatal("empty must not be synthetic")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestEmailsEqual(t *testing.T) {
|
||
|
|
t.Parallel()
|
||
|
|
if !EmailsEqual("A@Example.COM", " a@example.com ") {
|
||
|
|
t.Fatal("expected equal after normalize")
|
||
|
|
}
|
||
|
|
if EmailsEqual("a@example.com", "b@example.com") {
|
||
|
|
t.Fatal("expected mismatch")
|
||
|
|
}
|
||
|
|
if !EmailsEqual("", "") {
|
||
|
|
t.Fatal("empty emails should compare equal")
|
||
|
|
}
|
||
|
|
}
|