chromium/components/user_manager/fake_user_manager.cc

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/user_manager/fake_user_manager.h"

#include <utility>

#include "base/containers/contains.h"
#include "base/functional/callback.h"
#include "base/ranges/algorithm.h"
#include "base/system/sys_info.h"
#include "base/task/single_thread_task_runner.h"
#include "chromeos/ash/components/settings/cros_settings.h"
#include "components/user_manager/fake_user_manager_delegate.h"
#include "components/user_manager/user_names.h"
#include "components/user_manager/user_type.h"

namespace {

class FakeTaskRunner : public base::SingleThreadTaskRunner {
 public:
  // base::SingleThreadTaskRunner:
  bool PostDelayedTask(const base::Location& from_here,
                       base::OnceClosure task,
                       base::TimeDelta delay) override {
    std::move(task).Run();
    return true;
  }
  bool PostNonNestableDelayedTask(const base::Location& from_here,
                                  base::OnceClosure task,
                                  base::TimeDelta delay) override {
    return PostDelayedTask(from_here, std::move(task), delay);
  }
  bool RunsTasksInCurrentSequence() const override { return true; }

 protected:
  ~FakeTaskRunner() override {}
};

}  // namespace

namespace user_manager {

FakeUserManager::FakeUserManager(PrefService* local_state)
    : UserManagerBase(std::make_unique<FakeUserManagerDelegate>(),
                      new FakeTaskRunner(),
                      local_state,
                      ash::CrosSettings::IsInitialized()
                          ? ash::CrosSettings::Get()
                          : nullptr) {}

FakeUserManager::~FakeUserManager() = default;

std::string FakeUserManager::GetFakeUsernameHash(const AccountId& account_id) {
  // Consistent with the
  // kUserDataDirNameSuffix in fake_userdataauth_client.cc and
  // UserDataAuthClient::GetStubSanitizedUsername.
  // TODO(crbug.com/1347837): After resolving the dependent code,
  // consolidate the all implementation to cryptohome utilities,
  // and remove this.
  DCHECK(account_id.is_valid());
  return account_id.GetUserEmail() + "-hash";
}

const User* FakeUserManager::AddUser(const AccountId& account_id) {
  return AddUserWithAffiliation(account_id, false);
}

const User* FakeUserManager::AddChildUser(const AccountId& account_id) {
  User* user = User::CreateRegularUser(account_id, UserType::kChild);
  user_storage_.emplace_back(user);
  users_.push_back(user);
  return user;
}

const User* FakeUserManager::AddGuestUser(const AccountId& account_id) {
  User* user = User::CreateGuestUser(account_id);
  user_storage_.emplace_back(user);
  users_.push_back(user);
  return user;
}

const User* FakeUserManager::AddKioskAppUser(const AccountId& account_id) {
  User* user = User::CreateKioskAppUser(account_id);
  user->set_username_hash(GetFakeUsernameHash(account_id));
  user_storage_.emplace_back(user);
  users_.push_back(user);
  return user;
}

const User* FakeUserManager::AddUserWithAffiliation(const AccountId& account_id,
                                                    bool is_affiliated) {
  User* user = User::CreateRegularUser(account_id, UserType::kRegular);
  user->SetAffiliated(is_affiliated);
  user->set_username_hash(GetFakeUsernameHash(account_id));
  user_storage_.emplace_back(user);
  users_.push_back(user);
  return user;
}

const user_manager::User* FakeUserManager::AddPublicAccountUser(
    const AccountId& account_id) {
  User* user = User::CreatePublicAccountUserForTesting(account_id);
  user_storage_.emplace_back(user);
  users_.push_back(user);
  return user;
}

const UserList& FakeUserManager::GetUsers() const {
  return users_;
}

UserList FakeUserManager::GetUsersAllowedForMultiProfile() const {
  UserList result;
  for (UserList::const_iterator it = users_.begin(); it != users_.end(); ++it) {
    if ((*it)->GetType() == UserType::kRegular && !(*it)->is_logged_in()) {
      result.push_back(*it);
    }
  }
  return result;
}

void FakeUserManager::UpdateUserAccountData(
    const AccountId& account_id,
    const UserAccountData& account_data) {
  for (User* user : users_) {
    if (user->GetAccountId() == account_id) {
      user->set_display_name(account_data.display_name());
      user->set_given_name(account_data.given_name());
      return;
    }
  }
}

void FakeUserManager::LogoutAllUsers() {
  primary_user_ = nullptr;
  active_user_ = nullptr;

  logged_in_users_.clear();
  lru_logged_in_users_.clear();
}

void FakeUserManager::SetUserNonCryptohomeDataEphemeral(
    const AccountId& account_id,
    bool is_ephemeral) {
  if (is_ephemeral) {
    accounts_with_ephemeral_non_cryptohome_data_.insert(account_id);
  } else {
    accounts_with_ephemeral_non_cryptohome_data_.erase(account_id);
  }
}

void FakeUserManager::SetUserCryptohomeDataEphemeral(
    const AccountId& account_id,
    bool is_ephemeral) {
  accounts_with_ephemeral_cryptohome_data_.insert({account_id, is_ephemeral});
}

void FakeUserManager::UserLoggedIn(const AccountId& account_id,
                                   const std::string& username_hash,
                                   bool browser_restart,
                                   bool is_child) {
  // Please keep the implementation in sync with
  // FakeChromeUserManager::UserLoggedIn. We're in process to merge.
  for (user_manager::User* user : users_) {
    if (user->GetAccountId() == account_id) {
      user->set_is_logged_in(true);
      user->set_username_hash(username_hash);
      logged_in_users_.push_back(user);
      if (!primary_user_) {
        primary_user_ = user;
      }
      if (active_user_) {
        NotifyUserAddedToSession(user);
      } else {
        active_user_ = user;
      }
      break;
    }
  }

  if (!active_user_ && IsEphemeralAccountId(account_id)) {
    RegularUserLoggedInAsEphemeral(account_id, UserType::kRegular);
  }

  NotifyOnLogin();
}

User* FakeUserManager::GetActiveUserInternal() const {
  if (active_user_ != nullptr)
    return active_user_;

  if (!users_.empty()) {
    if (active_account_id_.is_valid()) {
      for (UserList::const_iterator it = users_.begin(); it != users_.end();
           ++it) {
        if ((*it)->GetAccountId() == active_account_id_)
          return *it;
      }
    }
    return users_[0];
  }
  return nullptr;
}

const User* FakeUserManager::GetActiveUser() const {
  return GetActiveUserInternal();
}

User* FakeUserManager::GetActiveUser() {
  return GetActiveUserInternal();
}

void FakeUserManager::SwitchActiveUser(const AccountId& account_id) {
  for (UserList::const_iterator it = logged_in_users_.begin();
       it != logged_in_users_.end(); ++it) {
    if ((*it)->GetAccountId() == account_id) {
      active_user_ = (*it).get();
      break;
    }
  }
}

void FakeUserManager::SaveUserDisplayName(const AccountId& account_id,
                                          const std::u16string& display_name) {
  for (UserList::iterator it = users_.begin(); it != users_.end(); ++it) {
    if ((*it)->GetAccountId() == account_id) {
      (*it)->set_display_name(display_name);
      return;
    }
  }
}

const UserList& FakeUserManager::GetLRULoggedInUsers() const {
  return users_;
}

UserList FakeUserManager::GetUnlockUsers() const {
  return users_;
}

const AccountId& FakeUserManager::GetOwnerAccountId() const {
  return owner_account_id_;
}

bool FakeUserManager::IsKnownUser(const AccountId& account_id) const {
  return true;
}

const User* FakeUserManager::FindUser(const AccountId& account_id) const {
  if (active_user_ != nullptr && active_user_->GetAccountId() == account_id)
    return active_user_;

  for (const User* user : users_) {
    if (user->GetAccountId() == account_id) {
      return user;
    }
  }

  return nullptr;
}

User* FakeUserManager::FindUserAndModify(const AccountId& account_id) {
  return const_cast<User*>(FindUser(account_id));
}

std::optional<std::string> FakeUserManager::GetOwnerEmail() {
  return GetLocalState() ? UserManagerBase::GetOwnerEmail() : std::nullopt;
}

bool FakeUserManager::IsCurrentUserNonCryptohomeDataEphemeral() const {
  return false;
}

bool FakeUserManager::IsUserLoggedIn() const {
  return logged_in_users_.size() > 0;
}

bool FakeUserManager::IsLoggedInAsUserWithGaiaAccount() const {
  return true;
}

bool FakeUserManager::IsLoggedInAsManagedGuestSession() const {
  const User* active_user = GetActiveUser();
  return active_user && active_user->GetType() == UserType::kPublicAccount;
}

bool FakeUserManager::IsLoggedInAsGuest() const {
  const User* active_user = GetActiveUser();
  return active_user && active_user->GetType() == UserType::kGuest;
}

bool FakeUserManager::IsLoggedInAsKioskApp() const {
  const User* active_user = GetActiveUser();
  return active_user ? active_user->GetType() == UserType::kKioskApp : false;
}

bool FakeUserManager::IsLoggedInAsWebKioskApp() const {
  const User* active_user = GetActiveUser();
  return active_user ? active_user->GetType() == UserType::kWebKioskApp : false;
}

bool FakeUserManager::IsLoggedInAsAnyKioskApp() const {
  const User* active_user = GetActiveUser();
  return active_user && active_user->IsKioskType();
}

bool FakeUserManager::IsLoggedInAsStub() const {
  return false;
}

bool FakeUserManager::IsUserNonCryptohomeDataEphemeral(
    const AccountId& account_id) const {
  return base::Contains(accounts_with_ephemeral_non_cryptohome_data_,
                        account_id);
}

bool FakeUserManager::IsUserCryptohomeDataEphemeral(
    const AccountId& account_id) const {
  auto is_ephemeral_overriden =
      base::Contains(accounts_with_ephemeral_cryptohome_data_, account_id);

  if (!is_ephemeral_overriden) {
    // Otherwise fall back to default behavior.
    return UserManagerBase::IsUserCryptohomeDataEphemeral(account_id);
  }

  return accounts_with_ephemeral_cryptohome_data_.at(account_id);
}

bool FakeUserManager::IsGuestSessionAllowed() const {
  return true;
}

bool FakeUserManager::IsGaiaUserAllowed(const User& user) const {
  return true;
}

bool FakeUserManager::IsUserAllowed(const User& user) const {
  return true;
}

bool FakeUserManager::IsDeviceLocalAccountMarkedForRemoval(
    const AccountId& account_id) const {
  return false;
}

bool FakeUserManager::IsDeprecatedSupervisedAccountId(
    const AccountId& account_id) const {
  return false;
}

}  // namespace user_manager