chromium/chrome/browser/ash/device_name/device_name_store_impl.cc

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

#include "chrome/browser/ash/device_name/device_name_store_impl.h"

#include "base/logging.h"
#include "chrome/browser/ash/device_name/device_name_applier_impl.h"
#include "chrome/browser/ash/device_name/device_name_validator.h"
#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
#include "chrome/browser/browser_process.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_thread.h"

namespace ash {

namespace {
const char kDefaultDeviceName[] = "ChromeOS";
}  // namespace

DeviceNameStoreImpl::DeviceNameStoreImpl(
    PrefService* prefs,
    policy::DeviceNamePolicyHandler* handler)
    : DeviceNameStoreImpl(prefs,
                          handler,
                          std::make_unique<DeviceNameApplierImpl>()) {}

DeviceNameStoreImpl::DeviceNameStoreImpl(
    PrefService* prefs,
    policy::DeviceNamePolicyHandler* handler,
    std::unique_ptr<DeviceNameApplier> device_name_applier)
    : prefs_(prefs),
      handler_(handler),
      device_name_applier_(std::move(device_name_applier)) {
  policy_handler_observation_.Observe(handler_.get());

  if (g_browser_process->profile_manager())
    profile_manager_observer_.Observe(g_browser_process->profile_manager());

  // Gets the device name according to the device name policy set. If empty, the
  // name in prefs is not set yet and hence we set it to the default name.
  std::string device_name = ComputeDeviceName();

  if (device_name.empty())
    device_name = kDefaultDeviceName;

  device_name_state_ = ComputeDeviceNameState();
  ChangeDeviceName(device_name);
}

DeviceNameStoreImpl::~DeviceNameStoreImpl() = default;

std::string DeviceNameStoreImpl::GetDeviceName() const {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  DCHECK(prefs_);
  return prefs_->GetString(prefs::kDeviceName);
}

DeviceNameStore::DeviceNameMetadata DeviceNameStoreImpl::GetDeviceNameMetadata()
    const {
  return {GetDeviceName(), device_name_state_};
}

DeviceNameStore::DeviceNameState DeviceNameStoreImpl::ComputeDeviceNameState()
    const {
  if (IsConfiguringDeviceNameProhibitedByPolicy())
    return DeviceNameState::kCannotBeModifiedBecauseOfPolicy;

  if (CannotModifyBecauseNotDeviceOwner())
    return DeviceNameState::kCannotBeModifiedBecauseNotDeviceOwner;

  return DeviceNameState::kCanBeModified;
}

bool DeviceNameStoreImpl::CannotModifyBecauseNotDeviceOwner() const {
  // If kNoPolicy is not in place, then the device is managed and user does not
  // have to be device owner to be able to change the name.
  if (handler_->GetDeviceNamePolicy() !=
      policy::DeviceNamePolicyHandler::DeviceNamePolicy::kNoPolicy) {
    return false;
  }

  // If device is unmanaged, then user has to be the device owner to be able to
  // change the name.
  if (is_user_owner_)
    return false;

  return true;
}

bool DeviceNameStoreImpl::IsConfiguringDeviceNameProhibitedByPolicy() const {
  switch (handler_->GetDeviceNamePolicy()) {
    case policy::DeviceNamePolicyHandler::DeviceNamePolicy::
        kPolicyHostnameNotConfigurable:
      [[fallthrough]];
    case policy::DeviceNamePolicyHandler::DeviceNamePolicy::
        kPolicyHostnameChosenByAdmin:
      return true;

    case policy::DeviceNamePolicyHandler::DeviceNamePolicy::
        kPolicyHostnameConfigurableByManagedUser:
      [[fallthrough]];
    case policy::DeviceNamePolicyHandler::DeviceNamePolicy::kNoPolicy:
      return false;
  }
}

void DeviceNameStoreImpl::ChangeDeviceName(const std::string& device_name) {
  device_name_applier_->SetDeviceName(device_name);
  prefs_->SetString(prefs::kDeviceName, device_name);
}

void DeviceNameStoreImpl::AttemptDeviceNameUpdate(
    const std::string& new_device_name) {
  std::string old_device_name = GetDeviceName();
  DeviceNameStore::DeviceNameState new_state = ComputeDeviceNameState();

  if (old_device_name == new_device_name && device_name_state_ == new_state)
    return;

  if (old_device_name != new_device_name)
    ChangeDeviceName(new_device_name);

  device_name_state_ = new_state;
  NotifyDeviceNameMetadataChanged();
}

DeviceNameStore::SetDeviceNameResult DeviceNameStoreImpl::SetDeviceName(
    const std::string& new_device_name) {
  if (device_name_state_ == DeviceNameState::kCannotBeModifiedBecauseOfPolicy)
    return SetDeviceNameResult::kProhibitedByPolicy;

  if (device_name_state_ ==
      DeviceNameState::kCannotBeModifiedBecauseNotDeviceOwner)
    return SetDeviceNameResult::kNotDeviceOwner;

  if (!IsValidDeviceName(new_device_name))
    return SetDeviceNameResult::kInvalidName;

  AttemptDeviceNameUpdate(new_device_name);
  return SetDeviceNameResult::kSuccess;
}

std::string DeviceNameStoreImpl::ComputeDeviceName() const {
  switch (handler_->GetDeviceNamePolicy()) {
    case policy::DeviceNamePolicyHandler::DeviceNamePolicy::
        kPolicyHostnameChosenByAdmin:
      return *handler_->GetHostnameChosenByAdministrator();

    case policy::DeviceNamePolicyHandler::DeviceNamePolicy::
        kPolicyHostnameNotConfigurable:
      return kDefaultDeviceName;

    case policy::DeviceNamePolicyHandler::DeviceNamePolicy::
        kPolicyHostnameConfigurableByManagedUser:
      return GetDeviceName();

    case policy::DeviceNamePolicyHandler::DeviceNamePolicy::kNoPolicy:
      return GetDeviceName();
  }
}

void DeviceNameStoreImpl::AttemptUpdateToComputedDeviceName() {
  AttemptDeviceNameUpdate(ComputeDeviceName());
}

void DeviceNameStoreImpl::OnHostnamePolicyChanged() {
  AttemptUpdateToComputedDeviceName();
}

void DeviceNameStoreImpl::AttemptDeviceNameStateUpdate(bool is_user_owner) {
  is_user_owner_ = is_user_owner;
  AttemptUpdateToComputedDeviceName();
}

void DeviceNameStoreImpl::OnProfileAdded(Profile* profile) {
  DCHECK(profile);

  OwnerSettingsServiceAsh* service =
      OwnerSettingsServiceAshFactory::GetForBrowserContext(profile);
  if (service) {
    service->IsOwnerAsync(
        base::BindOnce(&DeviceNameStoreImpl::AttemptDeviceNameStateUpdate,
                       weak_factory_.GetWeakPtr()));
  } else {
    VLOG(1) << "Owner settings service unavailable for added profile, will "
               "not update device name state.";
  }
}

void DeviceNameStoreImpl::OnProfileManagerDestroying() {
  profile_manager_observer_.Reset();
}

}  // namespace ash