package auth import ( "errors" "fmt" "sync" "time" "gitea.avt.data-center.id/othman.suseno/atlas/internal/models" ) var ( ErrUserNotFound = errors.New("user not found") ErrUserExists = errors.New("user already exists") ErrInvalidCredentials = errors.New("invalid credentials") ) // UserStore manages users in memory type UserStore struct { mu sync.RWMutex users map[string]*models.User 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, } // Create default admin user if no users exist store.createDefaultAdmin() return store } // createDefaultAdmin creates a default administrator user func (s *UserStore) createDefaultAdmin() { // Check if any users exist s.mu.RLock() hasUsers := len(s.users) > 0 s.mu.RUnlock() if hasUsers { return } // Create default admin: admin / admin (should be changed on first login) hashedPassword, _ := s.auth.HashPassword("admin") admin := &models.User{ ID: "user-1", Username: "admin", Role: models.RoleAdministrator, Active: true, CreatedAt: time.Now(), UpdatedAt: time.Now(), } // Store password hash (in production, this would be in a separate secure store) s.mu.Lock() s.users[admin.ID] = admin 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 func (s *UserStore) Create(username, email, password string, role models.Role) (*models.User, error) { s.mu.Lock() defer s.mu.Unlock() // Check if username already exists for _, user := range s.users { if user.Username == username { return nil, ErrUserExists } } id := fmt.Sprintf("user-%d", s.nextID) s.nextID++ hashedPassword, err := s.auth.HashPassword(password) if err != nil { return nil, err } user := &models.User{ ID: id, Username: username, Email: email, Role: role, Active: true, CreatedAt: time.Now(), UpdatedAt: time.Now(), } s.users[user.ID] = user _ = hashedPassword // TODO: Store password hash return user, nil } // GetByID returns a user by ID func (s *UserStore) GetByID(id string) (*models.User, error) { s.mu.RLock() defer s.mu.RUnlock() user, exists := s.users[id] if !exists { return nil, ErrUserNotFound } return user, nil } // GetByUsername returns a user by username func (s *UserStore) GetByUsername(username string) (*models.User, error) { s.mu.RLock() defer s.mu.RUnlock() for _, user := range s.users { if user.Username == username { return user, nil } } return nil, ErrUserNotFound } // Authenticate verifies username and password func (s *UserStore) Authenticate(username, password string) (*models.User, error) { user, err := s.GetByUsername(username) if err != nil { return nil, ErrInvalidCredentials } if !user.Active { 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 } return nil, ErrInvalidCredentials } // List returns all users func (s *UserStore) List() []models.User { s.mu.RLock() defer s.mu.RUnlock() users := make([]models.User, 0, len(s.users)) for _, user := range s.users { users = append(users, *user) } return users } // Update updates a user func (s *UserStore) Update(id string, email string, role models.Role, active bool) error { s.mu.Lock() defer s.mu.Unlock() user, exists := s.users[id] if !exists { return ErrUserNotFound } user.Email = email user.Role = role user.Active = active user.UpdatedAt = time.Now() return nil } // Delete deletes a user func (s *UserStore) Delete(id string) error { s.mu.Lock() defer s.mu.Unlock() if _, exists := s.users[id]; !exists { return ErrUserNotFound } delete(s.users, id) return nil } // UpdatePassword updates a user's password func (s *UserStore) UpdatePassword(id, newPassword string) error { s.mu.Lock() defer s.mu.Unlock() user, exists := s.users[id] if !exists { return ErrUserNotFound } hashedPassword, err := s.auth.HashPassword(newPassword) if err != nil { return err } _ = hashedPassword // TODO: Store password hash user.UpdatedAt = time.Now() return nil }