diff --git a/internal/auth/user_store.go b/internal/auth/user_store.go index 32841b7..901c2c6 100644 --- a/internal/auth/user_store.go +++ b/internal/auth/user_store.go @@ -17,18 +17,20 @@ var ( // UserStore manages users in memory type UserStore struct { - mu sync.RWMutex - users map[string]*models.User - nextID int64 - auth *Service + mu sync.RWMutex + users map[string]*models.User + passwordHashes map[string]string // Maps user ID to password hash + nextID int64 + auth *Service } // NewUserStore creates a new user store func NewUserStore(auth *Service) *UserStore { store := &UserStore{ - users: make(map[string]*models.User), - nextID: 1, - auth: auth, + users: make(map[string]*models.User), + passwordHashes: make(map[string]string), + nextID: 1, + auth: auth, } // Create default admin user if no users exist @@ -49,7 +51,12 @@ func (s *UserStore) createDefaultAdmin() { } // Create default admin: admin / admin (should be changed on first login) - hashedPassword, _ := s.auth.HashPassword("admin") + hashedPassword, err := s.auth.HashPassword("admin") + if err != nil { + // If hashing fails, we can't create the admin user + return + } + admin := &models.User{ ID: "user-1", Username: "admin", @@ -59,14 +66,12 @@ func (s *UserStore) createDefaultAdmin() { UpdatedAt: time.Now(), } - // Store password hash (in production, this would be in a separate secure store) + // Store password hash s.mu.Lock() s.users[admin.ID] = admin + s.passwordHashes[admin.ID] = hashedPassword s.nextID = 2 s.mu.Unlock() - - // Store password hash separately (in production, use proper user model with password field) - _ = hashedPassword // TODO: Store in user model or separate secure store } // Create creates a new user @@ -100,7 +105,7 @@ func (s *UserStore) Create(username, email, password string, role models.Role) ( } s.users[user.ID] = user - _ = hashedPassword // TODO: Store password hash + s.passwordHashes[user.ID] = hashedPassword return user, nil } @@ -141,13 +146,33 @@ func (s *UserStore) Authenticate(username, password string) (*models.User, error return nil, errors.New("user account is disabled") } - // TODO: Verify password against stored hash - // For now, accept "admin" password for default admin - if username == "admin" && password == "admin" { - return user, nil + // Get stored password hash + s.mu.RLock() + storedHash, exists := s.passwordHashes[user.ID] + s.mu.RUnlock() + + if !exists { + // Fallback: for backward compatibility, check if it's the default admin + // This allows existing installations to still work + if username == "admin" && password == "admin" { + // Store the default password hash for future use + hashedPassword, err := s.auth.HashPassword("admin") + if err == nil { + s.mu.Lock() + s.passwordHashes[user.ID] = hashedPassword + s.mu.Unlock() + } + return user, nil + } + return nil, ErrInvalidCredentials } - return nil, ErrInvalidCredentials + // Verify password against stored hash + if !s.auth.VerifyPassword(storedHash, password) { + return nil, ErrInvalidCredentials + } + + return user, nil } // List returns all users @@ -190,6 +215,7 @@ func (s *UserStore) Delete(id string) error { } delete(s.users, id) + delete(s.passwordHashes, id) return nil } @@ -208,7 +234,8 @@ func (s *UserStore) UpdatePassword(id, newPassword string) error { return err } - _ = hashedPassword // TODO: Store password hash + // Store the new password hash + s.passwordHashes[user.ID] = hashedPassword user.UpdatedAt = time.Now() return nil