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

#include "chrome/browser/extensions/settings_api_helpers.h"
#include "chrome/browser/lacros/net/network_settings_translation.h"
#include "chrome/browser/profiles/profile.h"
#include "chromeos/crosapi/mojom/network_settings_service.mojom.h"
#include "chromeos/lacros/lacros_service.h"
#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
#include "components/proxy_config/proxy_config_pref_names.h"
#include "components/proxy_config/proxy_prefs.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/management_policy.h"
#include "extensions/common/extension.h"
#include "net/proxy_resolution/proxy_config_with_annotation.h"

namespace lacros {
namespace {
crosapi::mojom::NetworkSettingsService* GetNetworkSettingsApi() {
  auto* lacros_service = chromeos::LacrosService::Get();
  return lacros_service->GetRemote<crosapi::mojom::NetworkSettingsService>()
      .get();
}
}  // namespace
namespace net {

LacrosExtensionProxyTracker::LacrosExtensionProxyTracker(Profile* profile)
    : profile_(profile) {
  DCHECK(profile_->IsMainProfile());
  proxy_prefs_registrar_.Init(profile_->GetPrefs());
  proxy_prefs_registrar_.Add(
      proxy_config::prefs::kProxy,
      base::BindRepeating(&LacrosExtensionProxyTracker::OnProxyPrefChanged,
                          base::Unretained(this)));
  OnProxyPrefChanged(proxy_config::prefs::kProxy);
  extension_observation_.Observe(extensions::ExtensionRegistry::Get(profile));
}

LacrosExtensionProxyTracker::~LacrosExtensionProxyTracker() = default;

void LacrosExtensionProxyTracker::OnProxyPrefChanged(
    const std::string& pref_name) {
  DCHECK(profile_->IsMainProfile());
  DCHECK(pref_name == proxy_config::prefs::kProxy);
  ::net::ProxyConfigWithAnnotation config;
  ProxyPrefs::ConfigState config_state =
      PrefProxyConfigTrackerImpl::ReadPrefConfig(profile_->GetPrefs(), &config);

  if (config_state != ProxyPrefs::ConfigState::CONFIG_EXTENSION) {
    if (extension_proxy_active_) {
      extension_proxy_active_ = false;
      if (AshVersionSupportsExtensionMetadata()) {
        GetNetworkSettingsApi()->ClearExtensionControllingProxyMetadata();
      } else {
        // TODO(acostinas,b/267719988) Remove this deprecated call in 118.
        GetNetworkSettingsApi()->ClearExtensionProxy();
      }
    }
    return;
  }
  extension_proxy_active_ = true;
  const extensions::Extension* extension =
      extensions::GetExtensionOverridingProxy(profile_);

  // The the extension-set proxy pref update is received before the extension is
  // enabled. This happens when the extension store where the pref is stored is
  // loaded before the extension, in one of the following cases:
  // - A new Chrome session is started, where the extension has set the proxy
  // pref in a previous session;
  // - Ash to Lacros migration;
  // - Disabling and then enabling an extension which is controlling the proxy.
  // It's safe to ignore the update here because this case is handled by
  // listening to the ExtensionRegistry events and re-sending the proxy config
  // to Ash when the extension which is controlling the proxy is loaded.
  if (!extension) {
    return;
  }

  auto extension_info = crosapi::mojom::ExtensionControllingProxy::New();
  extension_info->name = extension->name();
  extension_info->id = extension->id();
  extension_info->can_be_disabled =
      !extensions::ExtensionSystem::Get(profile_)
           ->management_policy()
           ->MustRemainEnabled(extension, nullptr);

  if (AshVersionSupportsExtensionMetadata()) {
    GetNetworkSettingsApi()->SetExtensionControllingProxyMetadata(
        std::move(extension_info));
    return;
  }
  auto proxy_config = chromeos::NetProxyToCrosapiProxy(config);
  proxy_config->extension = std::move(extension_info);
  // TODO(acostinas, b/267719988) Remove this deprecated call in 118.
  GetNetworkSettingsApi()->SetExtensionProxy(std::move(proxy_config));
}

void LacrosExtensionProxyTracker::OnExtensionReady(
    content::BrowserContext* browser_context,
    const extensions::Extension* extension) {
  if (!extension_proxy_active_) {
    return;
  }
  if (profile_ != Profile::FromBrowserContext(browser_context)) {
    return;
  }
  if (extensions::GetExtensionOverridingProxy(profile_) != extension) {
    return;
  }

  OnProxyPrefChanged(proxy_config::prefs::kProxy);
}

// static
bool LacrosExtensionProxyTracker::AshVersionSupportsExtensionMetadata() {
  chromeos::LacrosService* service = chromeos::LacrosService::Get();
  if (!service->IsAvailable<crosapi::mojom::NetworkSettingsService>()) {
    LOG(ERROR) << "Ash NetworkSettingsService not available";
    return false;
  }

  int network_settings_version =
      service->GetInterfaceVersion<crosapi::mojom::NetworkSettingsService>();
  if (network_settings_version <
      int{crosapi::mojom::NetworkSettingsService::MethodMinVersions::
              kSetExtensionControllingProxyMetadataMinVersion}) {
    LOG(WARNING) << "Ash NetworkSettingsService version "
                 << network_settings_version
                 << " does not support extension set proxies.";
    return false;
  }

  return true;
}

}  // namespace net
}  // namespace lacros