package auth_test import ( "os" "path/filepath" "testing" "golang.org/x/crypto/bcrypt" "osdb/internal/auth" ) // hashPepper mirrors the pepper convention: bcrypt("username:password") func hashPepper(username, password string) string { h, err := bcrypt.GenerateFromPassword([]byte(username+":"+password), bcrypt.MinCost) if err != nil { panic(err) } return string(h) } func writeTempUsersFile(t *testing.T, content string) string { t.Helper() f, err := os.CreateTemp(t.TempDir(), "users*.env") if err != nil { t.Fatal(err) } if _, err := f.WriteString(content); err != nil { t.Fatal(err) } f.Close() return f.Name() } func TestLoadUsers_ParsesValidFile(t *testing.T) { hash := hashPepper("admin", "secret") path := writeTempUsersFile(t, "admin:"+hash+"\n") users, err := auth.LoadUsers(path) if err != nil { t.Fatalf("LoadUsers: %v", err) } if len(users) != 1 { t.Fatalf("expected 1 user, got %d", len(users)) } if _, ok := users["admin"]; !ok { t.Error("expected 'admin' in users map") } } func TestLoadUsers_SkipsCommentLines(t *testing.T) { hash := hashPepper("admin", "secret") content := "# comment\nadmin:" + hash + "\n" path := writeTempUsersFile(t, content) users, err := auth.LoadUsers(path) if err != nil { t.Fatalf("LoadUsers: %v", err) } if len(users) != 1 { t.Fatalf("expected 1 user, got %d", len(users)) } } func TestLoadUsers_MissingFile(t *testing.T) { _, err := auth.LoadUsers(filepath.Join(t.TempDir(), "nonexistent.env")) if err == nil { t.Error("expected error for missing file") } } func TestVerifyPassword_CorrectPassword(t *testing.T) { hash := hashPepper("admin", "secret") users := map[string]string{"admin": hash} if !auth.VerifyPassword(users, "admin", "secret") { t.Error("expected password to match") } } func TestVerifyPassword_WrongPassword(t *testing.T) { hash := hashPepper("admin", "secret") users := map[string]string{"admin": hash} if auth.VerifyPassword(users, "admin", "wrong") { t.Error("expected password to not match") } } func TestVerifyPassword_UnknownUser(t *testing.T) { if auth.VerifyPassword(map[string]string{}, "nobody", "secret") { t.Error("expected false for unknown user") } } func TestGenerateAndValidateJWT(t *testing.T) { token, err := auth.GenerateJWT("admin", "testsecret") if err != nil { t.Fatalf("GenerateJWT: %v", err) } if token == "" { t.Error("expected non-empty token") } claims, err := auth.ValidateJWT(token, "testsecret") if err != nil { t.Fatalf("ValidateJWT: %v", err) } if claims.Username != "admin" { t.Errorf("expected username 'admin', got %q", claims.Username) } } func TestValidateJWT_WrongSecret(t *testing.T) { token, _ := auth.GenerateJWT("admin", "correct") if _, err := auth.ValidateJWT(token, "wrong"); err == nil { t.Error("expected error for wrong secret") } } func TestValidateJWT_MalformedToken(t *testing.T) { if _, err := auth.ValidateJWT("not.a.token", "secret"); err == nil { t.Error("expected error for malformed token") } }