// Package api — RealAuthManager provides production JWT + bcrypt authentication. package api import ( "fmt" "sync" "git.yeij.top/AskaEth/Cyrene_v2/internal/auth" ) // UserRecord holds a stored user's credentials. type UserRecord struct { UserID string Username string PasswordHash string Role string // "admin" | "user" } // UserStore is the interface for user persistence. type UserStore interface { FindByUsername(username string) (*UserRecord, error) Create(user *UserRecord) error } // MemUserStore is an in-memory user store for development and testing. type MemUserStore struct { mu sync.RWMutex users map[string]*UserRecord } // NewMemUserStore creates an in-memory user store with the configured admin account. func NewMemUserStore(adminUsername, adminPassword string) *MemUserStore { s := &MemUserStore{users: make(map[string]*UserRecord)} hash, _ := auth.HashPassword(adminPassword) s.users[adminUsername] = &UserRecord{ UserID: adminUsername, Username: adminUsername, PasswordHash: hash, Role: "admin", } return s } func (s *MemUserStore) FindByUsername(username string) (*UserRecord, error) { s.mu.RLock() defer s.mu.RUnlock() u, ok := s.users[username] if !ok { return nil, fmt.Errorf("user %s not found", username) } return u, nil } func (s *MemUserStore) Create(user *UserRecord) error { s.mu.Lock() defer s.mu.Unlock() if _, exists := s.users[user.Username]; exists { return fmt.Errorf("username %s already exists", user.Username) } s.users[user.Username] = user return nil } // RealAuthManager implements AuthManager using JWT + bcrypt. type RealAuthManager struct { tokenMgr *auth.TokenManager store UserStore } // NewRealAuthManager creates a production-grade auth manager. func NewRealAuthManager(secret string, expiryHours int, store UserStore) *RealAuthManager { return &RealAuthManager{ tokenMgr: auth.NewTokenManager(secret, expiryHours), store: store, } } // ValidateToken parses and validates a JWT token. func (m *RealAuthManager) ValidateToken(tokenStr string) (string, string, string, error) { claims, err := m.tokenMgr.Validate(tokenStr) if err != nil { return "", "", "", err } return claims.UserID, claims.Username, claims.Role, nil } // Login authenticates a user with username and password. func (m *RealAuthManager) Login(username, password string) (string, error) { user, err := m.store.FindByUsername(username) if err != nil { return "", fmt.Errorf("invalid credentials") } if !auth.CheckPassword(password, user.PasswordHash) { return "", fmt.Errorf("invalid credentials") } return m.tokenMgr.Generate(user.UserID, user.Username, user.Role) } // Register creates a new user account and returns a JWT token. func (m *RealAuthManager) Register(username, password string) (string, error) { if username == "" || password == "" { return "", fmt.Errorf("username and password required") } if len(password) < 6 { return "", fmt.Errorf("password must be at least 6 characters") } hash, err := auth.HashPassword(password) if err != nil { return "", fmt.Errorf("hash password: %w", err) } user := &UserRecord{ UserID: username, Username: username, PasswordHash: hash, Role: "user", } if err := m.store.Create(user); err != nil { return "", err } return m.tokenMgr.Generate(user.UserID, user.Username, user.Role) }