chromium/chrome/browser/lacros/net/proxy_config_service_lacros.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/lacros/net/proxy_config_service_lacros.h"

#include <memory>

#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/values.h"
#include "chrome/browser/lacros/net/lacros_extension_proxy_tracker.h"
#include "chrome/browser/lacros/net/network_settings_translation.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "chromeos/lacros/lacros_service.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "net/proxy_resolution/proxy_config.h"
#include "net/proxy_resolution/proxy_config_with_annotation.h"

namespace {

net::ProxyConfigWithAnnotation GetConfigOrDirect(
    const std::optional<net::ProxyConfigWithAnnotation>& optional_config,
    Profile* profile,
    bool proxy_controlled_by_extension) {
  DCHECK(profile);

  auto CreateDirect = net::ProxyConfigWithAnnotation::CreateDirect;

  if (!optional_config)
    return CreateDirect();

  // The primary profile always uses the OS proxy.
  if (profile->IsMainProfile())
    return optional_config.value();

  // Incognito profile doesn't apply proxies set by an extension in the main
  // profile.
  if (profile->IsIncognitoProfile()) {
    if (proxy_controlled_by_extension)
      return CreateDirect();
    return optional_config.value();
  }

  // Secondary Lacros profiles can opt to use the OS proxy.
  return profile->GetPrefs()->GetBoolean(prefs::kUseAshProxy)
             ? optional_config.value()
             : CreateDirect();
}
}  // namespace

namespace chromeos {

ProxyConfigServiceLacros::ProxyConfigServiceLacros(Profile* profile)
    : profile_(profile) {
  DCHECK(profile);
  auto* lacros_service = chromeos::LacrosService::Get();
  // crosapi is disabled in browser_tests.
  if (!lacros_service->IsAvailable<crosapi::mojom::NetworkSettingsService>()) {
    LOG(ERROR) << "The NetworkSettingsService service is not available";
    return;
  }
  lacros_service->GetRemote<crosapi::mojom::NetworkSettingsService>()
      ->AddNetworkSettingsObserver(receiver_.BindNewPipeAndPassRemote());

  // `kUseAshProxy` is a user exposed setting whether to use the ash proxy (from
  // the system) or whether to use profile specific proxy settings. This option
  // is only given for secondary profiles. For the primary profile, the user has
  // to use the system proxy settings, the value of kUseAshProxy is always true,
  // and the setting is not exposed to the user.
  // TODO(acostinas, b:192915915) Enable secondary profiles to configure
  // `kUseAshProxy` from chrome://settings.
  if (profile->IsMainProfile()) {
    lacros_extension_proxy_tracker_ =
        std::make_unique<lacros::net::LacrosExtensionProxyTracker>(profile);
  }

  profile_pref_change_registrar_.Init(profile->GetPrefs());
  profile_pref_change_registrar_.Add(
      prefs::kUseAshProxy,
      base::BindRepeating(&ProxyConfigServiceLacros::OnUseAshProxyPrefChanged,
                          base::Unretained(this)));
}

ProxyConfigServiceLacros::~ProxyConfigServiceLacros() = default;

void ProxyConfigServiceLacros::OnProxyChanged(
    crosapi::mojom::ProxyConfigPtr proxy_config) {
  proxy_controlled_by_extension_ = !proxy_config->extension.is_null();
  cached_config_ = CrosapiProxyToNetProxy(std::move(proxy_config));
  NotifyObservers();
}

void ProxyConfigServiceLacros::
    OnAlwaysOnVpnPreConnectUrlAllowlistEnforcedChanged(bool enforced) {}

void ProxyConfigServiceLacros::OnUseAshProxyPrefChanged() {
  NotifyObservers();
}

void ProxyConfigServiceLacros::NotifyObservers() {
  for (auto& observer : observers_) {
    observer.OnProxyConfigChanged(
        GetConfigOrDirect(cached_config_, profile_,
                          proxy_controlled_by_extension_),
        ConfigAvailability::CONFIG_VALID);
  }
}

void ProxyConfigServiceLacros::AddObserver(Observer* observer) {
  observers_.AddObserver(observer);
}

void ProxyConfigServiceLacros::RemoveObserver(Observer* observer) {
  observers_.RemoveObserver(observer);
}

// static
void ProxyConfigServiceLacros::RegisterProfilePrefs(
    PrefRegistrySimple* registry) {
  registry->RegisterBooleanPref(prefs::kUseAshProxy, false);
}

net::ProxyConfigService::ConfigAvailability
ProxyConfigServiceLacros::GetLatestProxyConfig(
    net::ProxyConfigWithAnnotation* config) {
  // Returns the last proxy configuration that the Ash
  // NetworkSettingsService notified us, or the direct proxy if `cached_config_`
  // is not set.
  *config = GetConfigOrDirect(cached_config_, profile_,
                              proxy_controlled_by_extension_);
  return ConfigAvailability::CONFIG_VALID;
}

}  // namespace chromeos