chromium/chrome/browser/ui/webui/management/management_ui_handler_chromeos.cc

// Copyright 2019 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/ui/webui/management/management_ui_handler_chromeos.h"

#include "base/check_is_test.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/enterprise/browser_management/management_service_factory.h"
#include "chrome/browser/enterprise/reporting/prefs.h"
#include "chrome/browser/media/webrtc/capture_policy_utils.h"
#include "chrome/browser/policy/networking/policy_cert_service.h"
#include "chrome/browser/policy/networking/policy_cert_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/management/management_ui_constants.h"
#include "chrome/browser/ui/webui/webui_util.h"
#include "chrome/common/pref_names.h"
#include "components/policy/core/common/management/management_service.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/crostini/crostini_features.h"
#include "chrome/browser/ash/crostini/crostini_pref_names.h"
#include "chrome/browser/ash/net/secure_dns_manager.h"
#include "chrome/browser/ash/plugin_vm/plugin_vm_pref_names.h"
#include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
#include "chrome/browser/ash/policy/core/device_cloud_policy_manager_ash.h"
#include "chrome/browser/ash/policy/handlers/minimum_version_policy_handler.h"
#include "chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_prefs.h"
#include "chrome/browser/ash/policy/skyvault/policy_utils.h"
#include "chrome/browser/ash/policy/status_collector/device_status_collector.h"
#include "chrome/browser/ash/policy/status_collector/status_collector.h"
#include "chrome/browser/ash/policy/uploading/status_uploader.h"
#include "chrome/browser/ash/policy/uploading/system_log_uploader.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/browser_process_platform_part_ash.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager_factory.h"
#include "chrome/browser/chromeos/reporting/metric_reporting_prefs.h"
#include "chrome/browser/net/stub_resolver_config_reader.h"
#include "chrome/browser/net/system_network_context_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/managed_ui.h"
#include "chrome/browser/ui/webui/management/management_ui_handler_chromeos.h"
#include "chrome/grit/branded_strings.h"
#include "chromeos/ash/components/network/network_state_handler.h"
#include "chromeos/ash/components/network/proxy/proxy_config_handler.h"
#include "chromeos/ash/components/network/proxy/ui_proxy_config_service.h"
#include "chromeos/ash/components/settings/cros_settings.h"
#include "chromeos/ash/components/settings/cros_settings_names.h"
#include "components/enterprise/browser/reporting/common_pref_names.h"
#include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
#include "components/policy/policy_constants.h"
#include "components/prefs/pref_service.h"
#include "components/user_manager/user_manager.h"
#include "content/public/browser/storage_partition.h"
#include "ui/chromeos/devicetype_utils.h"
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "base/strings/escape.h"
#include "chrome/browser/ui/managed_ui.h"
#include "chromeos/lacros/lacros_service.h"
#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)

namespace {

const char kAccountManagedInfo[] = "accountManagedInfo";
const char kDeviceManagedInfo[] = "deviceManagedInfo";
const char kOverview[] = "overview";

enum class DeviceReportingType {
  kSupervisedUser,
  kDeviceActivity,
  kDeviceStatistics,
  kDevice,
  kCrashReport,
  kAppInfoAndActivity,
  kLogs,
  kPrint,
  kPrintJobs,
  kCrostini,
  kUsername,
  kExtensions,
  kAndroidApplication,
  kDlpEvents,
  kLoginLogout,
  kCRDSessions,
  kPeripherals,
  kLegacyTech,
  kWebsiteInfoAndActivity,
  kFileEvents,
};

#if BUILDFLAG(IS_CHROMEOS_ASH)

const char kCustomerLogo[] = "customerLogo";

net::NetworkTrafficAnnotationTag GetManagementUICustomerLogoAnnotation() {
  return net::DefineNetworkTrafficAnnotation("management_ui_customer_logo", R"(
      semantics {
        sender: "Management UI Handler"
        description:
          "Download organization logo for visualization on the "
          "chrome://management page."
        trigger:
          "The user managed by organization that provides a company logo "
          "in their GSuites account loads the chrome://management page."
        data:
          "Organization uploaded image URL."
        destination: GOOGLE_OWNED_SERVICE
      }
      policy {
        cookies_allowed: NO
        setting:
          "This feature cannot be disabled by settings, but it is only "
          "triggered by a user action."
        policy_exception_justification: "Not implemented."
      })");
}

// Corresponds to DeviceReportingType in management_browser_proxy.js
std::string ToJSDeviceReportingType(const DeviceReportingType& type) {
  switch (type) {
    case DeviceReportingType::kSupervisedUser:
      return "supervised user";
    case DeviceReportingType::kDeviceActivity:
      return "device activity";
    case DeviceReportingType::kDeviceStatistics:
      return "device statistics";
    case DeviceReportingType::kDevice:
      return "device";
    case DeviceReportingType::kCrashReport:
      return "crash report";
    case DeviceReportingType::kAppInfoAndActivity:
      return "app info and activity";
    case DeviceReportingType::kLogs:
      return "logs";
    case DeviceReportingType::kPrint:
      return "print";
    case DeviceReportingType::kPrintJobs:
      return "print jobs";
    case DeviceReportingType::kCrostini:
      return "crostini";
    case DeviceReportingType::kUsername:
      return "username";
    case DeviceReportingType::kExtensions:
      return "extension";
    case DeviceReportingType::kAndroidApplication:
      return "android application";
    case DeviceReportingType::kDlpEvents:
      return "dlp events";
    case DeviceReportingType::kLoginLogout:
      return "login-logout";
    case DeviceReportingType::kCRDSessions:
      return "crd sessions";
    case DeviceReportingType::kPeripherals:
      return "peripherals";
    case DeviceReportingType::kLegacyTech:
      return kReportingTypeLegacyTech;
    case DeviceReportingType::kWebsiteInfoAndActivity:
      return "website info and activity";
    case DeviceReportingType::kFileEvents:
      return "file events";
    default:
      NOTREACHED_IN_MIGRATION() << "Unknown device reporting type";
      return "device";
  }
}

std::string GetWebsiteReportingAllowlistMessageParam(
    const base::Value::List& url_allowlist) {
  std::vector<std::string> url_patterns;
  for (const base::Value& pattern_value : url_allowlist) {
    url_patterns.push_back(pattern_value.GetString());
  }

  return base::JoinString(url_patterns, ", ");
}

void AddDeviceReportingElement(
    base::Value::List* report_sources,
    const std::string& message_id,
    const DeviceReportingType& type,
    base::Value::List message_params = base::Value::List()) {
  base::Value::Dict data;
  data.Set("messageId", message_id);
  data.Set("reportingType", ToJSDeviceReportingType(type));
  data.Set("messageParams", std::move(message_params));

  report_sources->Append(std::move(data));
}

const policy::DlpRulesManager* GetDlpRulesManager() {
  return policy::DlpRulesManagerFactory::GetForPrimaryProfile();
}

// If you are adding a privacy note, please also add it to
// go/chrome-policy-privacy-note-mappings.
void AddDeviceReportingInfo(base::Value::List* report_sources,
                            const policy::StatusCollector* collector,
                            const policy::SystemLogUploader* uploader,
                            Profile* profile) {
  if (!collector || !profile || !uploader) {
    return;
  }

  // Elements appear on the page in the order they are added.
  bool report_device_peripherals = false;
  ash::CrosSettings::Get()->GetBoolean(ash::kReportDevicePeripherals,
                                       &report_device_peripherals);
  bool report_audio_status = false;
  ash::CrosSettings::Get()->GetBoolean(ash::kReportDeviceAudioStatus,
                                       &report_audio_status);
  // TODO(b/262295601): Add/refine management strings corresponding to XDR
  // reporting policy.
  bool device_report_xdr_events = false;
  ash::CrosSettings::Get()->GetBoolean(ash::kDeviceReportXDREvents,
                                       &device_report_xdr_events);
  if (collector->IsReportingActivityTimes() || report_device_peripherals ||
      report_audio_status || device_report_xdr_events ||
      profile->GetPrefs()->GetBoolean(::prefs::kInsightsExtensionEnabled)) {
    AddDeviceReportingElement(report_sources, kManagementReportActivityTimes,
                              DeviceReportingType::kDeviceActivity);
  } else {
    if (collector->IsReportingUsers()) {
      AddDeviceReportingElement(report_sources, kManagementReportUsers,
                                DeviceReportingType::kSupervisedUser);
    }
  }
  if (collector->IsReportingNetworkData() ||
      profile->GetPrefs()->GetBoolean(::prefs::kInsightsExtensionEnabled)) {
    AddDeviceReportingElement(report_sources, kManagementReportNetworkData,
                              DeviceReportingType::kDevice);
  }
  if (collector->IsReportingHardwareData()) {
    AddDeviceReportingElement(report_sources, kManagementReportHardwareData,
                              DeviceReportingType::kDeviceStatistics);
  }
  if (collector->IsReportingCrashReportInfo()) {
    AddDeviceReportingElement(report_sources, kManagementReportCrashReports,
                              DeviceReportingType::kCrashReport);
  }

  const auto& app_inventory_app_types =
      profile->GetPrefs()->GetList(::ash::reporting::kReportAppInventory);
  const auto& app_usage_app_types =
      profile->GetPrefs()->GetList(::ash::reporting::kReportAppUsage);
  if (collector->IsReportingAppInfoAndActivity() || device_report_xdr_events ||
      !app_inventory_app_types.empty() || !app_usage_app_types.empty()) {
    AddDeviceReportingElement(report_sources,
                              kManagementReportAppInfoAndActivity,
                              DeviceReportingType::kAppInfoAndActivity);
  }
  if (uploader->upload_enabled()) {
    AddDeviceReportingElement(report_sources, kManagementLogUploadEnabled,
                              DeviceReportingType::kLogs);
  }

  if (report_audio_status) {
    AddDeviceReportingElement(report_sources,
                              kManagementReportDeviceAudioStatus,
                              DeviceReportingType::kDevice);
  }

  bool report_graphics_status = false;
  ash::CrosSettings::Get()->GetBoolean(ash::kReportDeviceGraphicsStatus,
                                       &report_graphics_status);
  if (report_graphics_status) {
    AddDeviceReportingElement(report_sources,
                              kManagementReportDeviceGraphicsStatus,
                              DeviceReportingType::kDevice);
  }

  if (report_device_peripherals) {
    AddDeviceReportingElement(report_sources,
                              kManagementReportDevicePeripherals,
                              DeviceReportingType::kPeripherals);
  }

  bool report_print_jobs = false;
  ash::CrosSettings::Get()->GetBoolean(ash::kReportDevicePrintJobs,
                                       &report_print_jobs);
  if (report_print_jobs) {
    AddDeviceReportingElement(report_sources, kManagementReportPrintJobs,
                              DeviceReportingType::kPrintJobs);
  }

  bool report_print_username = profile->GetPrefs()->GetBoolean(
      prefs::kPrintingSendUsernameAndFilenameEnabled);
  if (report_print_username && !report_print_jobs) {
    AddDeviceReportingElement(report_sources, kManagementPrinting,
                              DeviceReportingType::kPrint);
  }

  if (GetDlpRulesManager() && GetDlpRulesManager()->IsReportingEnabled()) {
    AddDeviceReportingElement(report_sources, kManagementReportDlpEvents,
                              DeviceReportingType::kDlpEvents);
  }

  if (crostini::CrostiniFeatures::Get()->IsAllowedNow(profile)) {
    if (!profile->GetPrefs()
             ->GetFilePath(crostini::prefs::kCrostiniAnsiblePlaybookFilePath)
             .empty()) {
      AddDeviceReportingElement(report_sources,
                                kManagementCrostiniContainerConfiguration,
                                DeviceReportingType::kCrostini);
    } else if (profile->GetPrefs()->GetBoolean(
                   crostini::prefs::kReportCrostiniUsageEnabled)) {
      AddDeviceReportingElement(report_sources, kManagementCrostini,
                                DeviceReportingType::kCrostini);
    }
  }

  if (g_browser_process->local_state()->GetBoolean(
          enterprise_reporting::kCloudReportingEnabled)) {
    AddDeviceReportingElement(report_sources,
                              kManagementExtensionReportUsername,
                              DeviceReportingType::kUsername);
    AddDeviceReportingElement(report_sources, kManagementReportExtensions,
                              DeviceReportingType::kExtensions);
    AddDeviceReportingElement(report_sources,
                              kManagementReportAndroidApplications,
                              DeviceReportingType::kAndroidApplication);
  }

  if (!profile->GetPrefs()
           ->GetList(enterprise_reporting::kCloudLegacyTechReportAllowlist)
           .empty()) {
    AddDeviceReportingElement(report_sources, kManagementLegacyTechReport,
                              DeviceReportingType::kLegacyTech);
  }

  bool report_login_logout = false;
  ash::CrosSettings::Get()->GetBoolean(ash::kReportDeviceLoginLogout,
                                       &report_login_logout);
  bool report_xdr_events = false;
  ash::CrosSettings::Get()->GetBoolean(ash::kDeviceReportXDREvents,
                                       &report_xdr_events);
  if (report_login_logout || report_xdr_events) {
    AddDeviceReportingElement(report_sources, kManagementReportLoginLogout,
                              DeviceReportingType::kLoginLogout);
  }

  if (report_xdr_events) {
    AddDeviceReportingElement(report_sources, kManagementReportFileEvents,
                              DeviceReportingType::kFileEvents);
  }

  bool report_crd_sessions = false;
  ash::CrosSettings::Get()->GetBoolean(ash::kReportCRDSessions,
                                       &report_crd_sessions);
  if (report_crd_sessions) {
    AddDeviceReportingElement(report_sources, kManagementReportCRDSessions,
                              DeviceReportingType::kCRDSessions);
  }

  const auto wildcard_pattern_string =
      ContentSettingsPattern::Wildcard().ToString();
  const auto& website_telemetry_types =
      profile->GetPrefs()->GetList(::reporting::kReportWebsiteTelemetry);
  const auto& website_telemetry_allowlist = profile->GetPrefs()->GetList(
      ::reporting::kReportWebsiteTelemetryAllowlist);
  const auto& website_activity_allowlist = profile->GetPrefs()->GetList(
      ::reporting::kReportWebsiteActivityAllowlist);
  if (base::Contains(website_activity_allowlist, wildcard_pattern_string) ||
      (!website_telemetry_types.empty() &&
       base::Contains(website_telemetry_allowlist, wildcard_pattern_string))) {
    // One or more website metrics reporting policies allowlists all website
    // URLs.
    AddDeviceReportingElement(report_sources,
                              kManagementReportAllWebsiteInfoAndActivity,
                              DeviceReportingType::kWebsiteInfoAndActivity);
  } else if (!website_activity_allowlist.empty()) {
    // Admin defined subset of URLs allowlisted for website activity reporting.
    base::Value::List message_params;
    message_params.Append(
        GetWebsiteReportingAllowlistMessageParam(website_activity_allowlist));
    AddDeviceReportingElement(report_sources,
                              kManagementReportWebsiteInfoAndActivity,
                              DeviceReportingType::kWebsiteInfoAndActivity,
                              std::move(message_params));
  } else if (!website_telemetry_types.empty() &&
             !website_telemetry_allowlist.empty()) {
    // Admin defined subset of URLs allowlisted for website telemetry reporting.
    base::Value::List message_params;
    message_params.Append(
        GetWebsiteReportingAllowlistMessageParam(website_telemetry_allowlist));
    AddDeviceReportingElement(report_sources,
                              kManagementReportWebsiteInfoAndActivity,
                              DeviceReportingType::kWebsiteInfoAndActivity,
                              std::move(message_params));
  }
}

void AddStatusOverviewManagedDeviceAndAccount(
    base::Value::Dict* status,
    bool device_managed,
    bool account_managed,
    const std::string& device_manager,
    const std::string& account_manager) {
  if (device_managed && account_managed &&
      (account_manager.empty() || account_manager == device_manager)) {
    status->Set(kOverview, base::Value(l10n_util::GetStringFUTF16(
                               IDS_MANAGEMENT_DEVICE_AND_ACCOUNT_MANAGED_BY,
                               base::UTF8ToUTF16(device_manager))));

    return;
  }

  if (account_managed && !account_manager.empty()) {
    status->Set(kOverview, base::Value(l10n_util::GetStringFUTF16(
                               IDS_MANAGEMENT_ACCOUNT_MANAGED_BY,
                               base::UTF8ToUTF16(account_manager))));
  }

  if (account_managed && device_managed && !account_manager.empty() &&
      account_manager != device_manager) {
    status->Set(kOverview,
                base::Value(l10n_util::GetStringFUTF16(
                    IDS_MANAGEMENT_DEVICE_MANAGED_BY_ACCOUNT_MANAGED_BY,
                    base::UTF8ToUTF16(device_manager),
                    base::UTF8ToUTF16(account_manager))));
  }
}

bool IsCloudDestination(policy::local_user_files::FileSaveDestination dest) {
  return dest == policy::local_user_files::FileSaveDestination::kGoogleDrive ||
         dest == policy::local_user_files::FileSaveDestination::kOneDrive;
}
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

}  // namespace

ManagementUIHandlerChromeOS::ManagementUIHandlerChromeOS(Profile* profile)
    : ManagementUIHandler(profile) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
  chromeos::LacrosService* service = chromeos::LacrosService::Get();
  // Get device report sources.
  if (service->IsAvailable<crosapi::mojom::DeviceSettingsService>() &&
      service->GetInterfaceVersion<crosapi::mojom::DeviceSettingsService>() >=
          static_cast<int>(crosapi::mojom::DeviceSettingsService::
                               kGetDeviceReportSourcesMinVersion)) {
    service->GetRemote<crosapi::mojom::DeviceSettingsService>()
        ->GetDeviceReportSources(base::BindOnce(
            &ManagementUIHandlerChromeOS::OnGotDeviceReportSources,
            weak_factory_.GetWeakPtr()));
  }
#endif
  // profile is unset during unittest, in which case, we can initial device
  // managed state in ctor either. Hence skip the process.
  if (!profile) {
    CHECK_IS_TEST();
    return;
  }
  UpdateDeviceManagedState();
}

ManagementUIHandlerChromeOS::~ManagementUIHandlerChromeOS() = default;

void ManagementUIHandlerChromeOS::RegisterMessages() {
  ManagementUIHandler::RegisterMessages();
  web_ui()->RegisterMessageCallback(
      "getLocalTrustRootsInfo",
      base::BindRepeating(
          &ManagementUIHandlerChromeOS::HandleGetLocalTrustRootsInfo,
          base::Unretained(this)));
  web_ui()->RegisterMessageCallback(
      "getDeviceReportingInfo",
      base::BindRepeating(
          &ManagementUIHandlerChromeOS::HandleGetDeviceReportingInfo,
          base::Unretained(this)));
  web_ui()->RegisterMessageCallback(
      "getPluginVmDataCollectionStatus",
      base::BindRepeating(
          &ManagementUIHandlerChromeOS::HandleGetPluginVmDataCollectionStatus,
          base::Unretained(this)));
  web_ui()->RegisterMessageCallback(
      "getFilesUploadToCloudInfo",
      base::BindRepeating(
          &ManagementUIHandlerChromeOS::HandleGetFilesUploadToCloudInfo,
          base::Unretained(this)));

  capture_policy::CheckGetAllScreensMediaAllowedForAnyOrigin(
      Profile::FromWebUI(web_ui()),
      base::BindOnce(
          &ManagementUIHandlerChromeOS::
              CheckGetAllScreensMediaAllowedForAnyOriginResultReceived,
          weak_factory_.GetWeakPtr()));
}

#if BUILDFLAG(IS_CHROMEOS_ASH)

// static
base::Value::List ManagementUIHandlerChromeOS::GetDeviceReportingInfo(
    const policy::DeviceCloudPolicyManagerAsh* manager,
    Profile* profile) {
  base::Value::List report_sources;
  policy::StatusUploader* uploader = nullptr;
  policy::SystemLogUploader* syslog_uploader = nullptr;
  policy::StatusCollector* collector = nullptr;
  if (manager) {
    uploader = manager->GetStatusUploader();
    syslog_uploader = manager->GetSystemLogUploader();
    if (uploader) {
      collector = uploader->status_collector();
    }
  }
  AddDeviceReportingInfo(&report_sources, collector, syslog_uploader, profile);
  return report_sources;
}

// static
void ManagementUIHandlerChromeOS::AddDlpDeviceReportingElementForTesting(
    base::Value::List* report_sources,
    const std::string& message_id) {
  AddDeviceReportingElement(report_sources, message_id,
                            DeviceReportingType::kDlpEvents);
}

// static
void ManagementUIHandlerChromeOS::AddDeviceReportingInfoForTesting(
    base::Value::List* report_sources,
    const policy::StatusCollector* collector,
    const policy::SystemLogUploader* uploader,
    Profile* profile) {
  AddDeviceReportingInfo(report_sources, collector, uploader, profile);
}

const policy::DeviceCloudPolicyManagerAsh*
ManagementUIHandlerChromeOS::GetDeviceCloudPolicyManager() const {
  // Only check for report status in managed environment.
  if (!device_managed_) {
    return nullptr;
  }

  const policy::BrowserPolicyConnectorAsh* connector =
      g_browser_process->platform_part()->browser_policy_connector_ash();
  return connector->GetDeviceCloudPolicyManager();
}

const std::string ManagementUIHandlerChromeOS::GetDeviceManager() const {
  std::string device_domain;
  policy::BrowserPolicyConnectorAsh* connector =
      g_browser_process->platform_part()->browser_policy_connector_ash();
  if (device_managed_) {
    device_domain = connector->GetEnterpriseDomainManager();
  }
  return device_domain;
}

bool ManagementUIHandlerChromeOS::IsUpdateRequiredEol() const {
  const policy::BrowserPolicyConnectorAsh* connector =
      g_browser_process->platform_part()->browser_policy_connector_ash();
  policy::MinimumVersionPolicyHandler* handler =
      connector->GetMinimumVersionPolicyHandler();
  return handler && handler->ShouldShowUpdateRequiredEolBanner();
}

void ManagementUIHandlerChromeOS::AddUpdateRequiredEolInfo(
    base::Value::Dict* response) const {
  if (!device_managed_ || !IsUpdateRequiredEol()) {
    response->Set("eolMessage", std::string());
    return;
  }

  response->Set("eolMessage", l10n_util::GetStringFUTF16(
                                  IDS_MANAGEMENT_UPDATE_REQUIRED_EOL_MESSAGE,
                                  base::UTF8ToUTF16(GetDeviceManager()),
                                  ui::GetChromeOSDeviceName()));
  std::string eol_admin_message;
  ash::CrosSettings::Get()->GetString(ash::kDeviceMinimumVersionAueMessage,
                                      &eol_admin_message);
  response->Set("eolAdminMessage", eol_admin_message);
}

void ManagementUIHandlerChromeOS::AddMonitoredNetworkPrivacyDisclosure(
    base::Value::Dict* response) {
  bool showMonitoredNetworkDisclosure = false;

  // Check for secure DNS templates with identifiers.
  std::optional<std::string> doh_with_identifiers_servers_for_display;

  doh_with_identifiers_servers_for_display =
      GetSecureDnsManager()->GetDohWithIdentifiersDisplayServers();

  showMonitoredNetworkDisclosure =
      doh_with_identifiers_servers_for_display.has_value();
  if (showMonitoredNetworkDisclosure) {
    response->Set("showMonitoredNetworkPrivacyDisclosure",
                  showMonitoredNetworkDisclosure);
    return;
  }

  // Check if DeviceReportXDREvents is enabled.
  auto* report_xdr_events_policy_value =
      GetPolicyService()
          ->GetPolicies(policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME,
                                                std::string()))
          .GetValue(policy::key::kDeviceReportXDREvents,
                    base::Value::Type::BOOLEAN);
  bool report_xdr_events_policy_enabled =
      report_xdr_events_policy_value &&
      report_xdr_events_policy_value->GetBool();

  if (report_xdr_events_policy_enabled) {
    response->Set("showMonitoredNetworkPrivacyDisclosure",
                  report_xdr_events_policy_enabled);
    return;
  }

  // Check for proxy config.
  ash::NetworkHandler* network_handler = ash::NetworkHandler::Get();
  base::Value::Dict proxy_settings;
  // |ui_proxy_config_service| may be missing in tests. If the device is offline
  // (no network connected) the |DefaultNetwork| is null.
  if (ash::NetworkHandler::HasUiProxyConfigService() &&
      network_handler->network_state_handler()->DefaultNetwork()) {
    // Check if proxy is enforced by user policy, a forced install extension or
    // ONC policies. This will only read managed settings.
    ash::NetworkHandler::GetUiProxyConfigService()->MergeEnforcedProxyConfig(
        network_handler->network_state_handler()->DefaultNetwork()->guid(),
        &proxy_settings);
  }
  if (!proxy_settings.empty()) {
    // Proxies can be specified by web server url, via a PAC script or via the
    // web proxy auto-discovery protocol. Chrome also supports the "direct"
    // mode, in which no proxy is used.
    std::string* proxy_specification_mode =
        proxy_settings.FindStringByDottedPath(base::JoinString(
            {::onc::network_config::kType, ::onc::kAugmentationActiveSetting},
            "."));
    showMonitoredNetworkDisclosure =
        proxy_specification_mode &&
        *proxy_specification_mode != ::onc::proxy::kDirect;
  }
  response->Set("showMonitoredNetworkPrivacyDisclosure",
                showMonitoredNetworkDisclosure);
}

void ManagementUIHandlerChromeOS::RegisterPrefChange(
    PrefChangeRegistrar& pref_registrar) {
  ManagementUIHandler::RegisterPrefChange(pref_registrar);
  pref_registrar.Add(
      plugin_vm::prefs::kPluginVmDataCollectionAllowed,
      base::BindRepeating(
          &ManagementUIHandlerChromeOS::NotifyPluginVmDataCollectionUpdated,
          base::Unretained(this)));
}

#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

base::Value::Dict ManagementUIHandlerChromeOS::GetContextualManagedData(
    Profile* profile) {
  base::Value::Dict response;
  std::string enterprise_manager;
#if BUILDFLAG(IS_CHROMEOS_ASH)
  enterprise_manager = GetDeviceManager();
#endif
  if (enterprise_manager.empty()) {
    enterprise_manager = GetAccountManager(profile);
  }
#if BUILDFLAG(IS_CHROMEOS_ASH)
  AddUpdateRequiredEolInfo(&response);
  AddMonitoredNetworkPrivacyDisclosure(&response);
#endif

#if BUILDFLAG(IS_CHROMEOS_LACROS)
  response.Set("pageSubtitle", chrome::GetManagementPageSubtitle(profile));
  response.Set("browserManagementNotice",
               l10n_util::GetStringFUTF16(
                   managed() ? IDS_MANAGEMENT_BROWSER_NOTICE
                             : IDS_MANAGEMENT_NOT_MANAGED_NOTICE,
                   chrome::kManagedUiLearnMoreUrl,
                   base::EscapeForHTML(l10n_util::GetStringUTF16(
                       IDS_MANAGEMENT_LEARN_MORE_ACCCESSIBILITY_TEXT))));
#endif
  if (enterprise_manager.empty()) {
    response.Set(
        "extensionReportingSubtitle",
        l10n_util::GetStringUTF16(IDS_MANAGEMENT_EXTENSIONS_INSTALLED));
    response.Set(
        "applicationReportingSubtitle",
        l10n_util::GetStringUTF16(IDS_MANAGEMENT_APPLICATIONS_INSTALLED));
    response.Set(
        "managedWebsitesSubtitle",
        l10n_util::GetStringUTF16(IDS_MANAGEMENT_MANAGED_WEBSITES_EXPLANATION));
#if BUILDFLAG(IS_CHROMEOS_ASH)
    const auto device_type = ui::GetChromeOSDeviceTypeResourceId();
    response.Set("pageSubtitle",
                 managed() ? l10n_util::GetStringFUTF16(
                                 IDS_MANAGEMENT_SUBTITLE_MANAGED,
                                 l10n_util::GetStringUTF16(device_type))
                           : l10n_util::GetStringFUTF16(
                                 IDS_MANAGEMENT_NOT_MANAGED_SUBTITLE,
                                 l10n_util::GetStringUTF16(device_type)));
#endif
  } else {
    response.Set(
        "extensionReportingSubtitle",
        l10n_util::GetStringFUTF16(IDS_MANAGEMENT_EXTENSIONS_INSTALLED_BY,
                                   base::UTF8ToUTF16(enterprise_manager)));
    response.Set(
        "applicationReportingSubtitle",
        l10n_util::GetStringFUTF16(IDS_MANAGEMENT_APPLICATIONS_INSTALLED_BY,
                                   base::UTF8ToUTF16(enterprise_manager)));
    response.Set("managedWebsitesSubtitle",
                 l10n_util::GetStringFUTF16(
                     IDS_MANAGEMENT_MANAGED_WEBSITES_BY_EXPLANATION,
                     base::UTF8ToUTF16(enterprise_manager)));
#if BUILDFLAG(IS_CHROMEOS_ASH)
    const auto device_type = ui::GetChromeOSDeviceTypeResourceId();
    response.Set("pageSubtitle",
                 managed() ? l10n_util::GetStringFUTF16(
                                 IDS_MANAGEMENT_SUBTITLE_MANAGED_BY,
                                 l10n_util::GetStringUTF16(device_type),
                                 base::UTF8ToUTF16(enterprise_manager))
                           : l10n_util::GetStringFUTF16(
                                 IDS_MANAGEMENT_NOT_MANAGED_SUBTITLE,
                                 l10n_util::GetStringUTF16(device_type)));
#endif
  }
  response.Set("managed", managed());
  GetManagementStatus(profile, &response);

#if BUILDFLAG(IS_CHROMEOS_ASH)
  AsyncUpdateLogo();
  if (!fetched_image_.empty()) {
    response.Set(kCustomerLogo, base::Value(fetched_image_));
  }
#endif

  return response;
}

bool ManagementUIHandlerChromeOS::managed() const {
  return account_managed() || device_managed_;
}

void ManagementUIHandlerChromeOS::UpdateManagedState() {
  bool is_account_updated =
      UpdateAccountManagedState(Profile::FromWebUI(web_ui()));
  bool is_device_updated = UpdateDeviceManagedState();
  if (is_account_updated || is_device_updated) {
    FireWebUIListener("managed_data_changed");
  }
}

bool ManagementUIHandlerChromeOS::UpdateDeviceManagedState() {
  bool new_managed =
      policy::ManagementServiceFactory::GetForPlatform()->IsManaged();
  bool is_updated = (device_managed_ != new_managed);
  device_managed_ = new_managed;
  return is_updated;
}

#if BUILDFLAG(IS_CHROMEOS_ASH)
void ManagementUIHandlerChromeOS::AsyncUpdateLogo() {
  policy::BrowserPolicyConnectorAsh* connector =
      g_browser_process->platform_part()->browser_policy_connector_ash();
  const auto url = connector->GetCustomerLogoURL();
  if (!url.empty() && GURL(url) != logo_url_) {
    icon_fetcher_ = std::make_unique<BitmapFetcher>(
        GURL(url), this, GetManagementUICustomerLogoAnnotation());
    icon_fetcher_->Init(net::ReferrerPolicy::NEVER_CLEAR,
                        network::mojom::CredentialsMode::kOmit);
    auto* profile = Profile::FromWebUI(web_ui());
    icon_fetcher_->Start(profile->GetDefaultStoragePartition()
                             ->GetURLLoaderFactoryForBrowserProcess()
                             .get());
  }
}

void ManagementUIHandlerChromeOS::OnFetchComplete(const GURL& url,
                                                  const SkBitmap* bitmap) {
  if (!bitmap) {
    return;
  }
  fetched_image_ = webui::GetBitmapDataUrl(*bitmap);
  logo_url_ = url;
  // Fire listener to reload managed data.
  FireWebUIListener("managed_data_changed");
}

void ManagementUIHandlerChromeOS::NotifyPluginVmDataCollectionUpdated() {
  FireWebUIListener(
      "plugin-vm-data-collection-updated",
      base::Value(Profile::FromWebUI(web_ui())->GetPrefs()->GetBoolean(
          plugin_vm::prefs::kPluginVmDataCollectionAllowed)));
}

#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

#if BUILDFLAG(IS_CHROMEOS_LACROS)
void ManagementUIHandlerChromeOS::OnGotDeviceReportSources(
    base::Value::List report_sources,
    bool plugin_vm_data_collection_enabled) {
  report_sources_ = std::move(report_sources);
  plugin_vm_data_collection_enabled_ = plugin_vm_data_collection_enabled;
}
#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)

void ManagementUIHandlerChromeOS::GetManagementStatus(
    Profile* profile,
    base::Value::Dict* status) const {
  status->Set(kDeviceManagedInfo, base::Value());
  status->Set(kAccountManagedInfo, base::Value());
  status->Set(kOverview, base::Value());
  if (!managed()) {
    status->Set(kOverview, base::Value(l10n_util::GetStringUTF16(
                               IDS_MANAGEMENT_DEVICE_NOT_MANAGED)));
    return;
  }
#if BUILDFLAG(IS_CHROMEOS_ASH)
  std::string account_manager = GetAccountManager(profile);
  auto* primary_user = user_manager::UserManager::Get()->GetPrimaryUser();
  auto* primary_profile =
      primary_user ? ash::ProfileHelper::Get()->GetProfileByUser(primary_user)
                   : nullptr;
  const bool primary_user_managed =
      primary_profile ? IsProfileManaged(primary_profile) : false;

  if (primary_user_managed) {
    account_manager = GetAccountManager(primary_profile);
  }

  std::string device_manager = GetDeviceManager();

  AddStatusOverviewManagedDeviceAndAccount(
      status, device_managed_, account_managed() || primary_user_managed,
      device_manager, account_manager);
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
}

void ManagementUIHandlerChromeOS::HandleGetLocalTrustRootsInfo(
    const base::Value::List& args) {
  CHECK_EQ(1U, args.size());
  base::Value trust_roots_configured(false);
  AllowJavascript();

  policy::PolicyCertService* policy_service =
      policy::PolicyCertServiceFactory::GetForProfile(
          Profile::FromWebUI(web_ui()));
  if (policy_service && policy_service->has_policy_certificates()) {
    trust_roots_configured = base::Value(true);
  }

  ResolveJavascriptCallback(args[0] /* callback_id */, trust_roots_configured);
}

#if BUILDFLAG(IS_CHROMEOS_ASH)
std::u16string ManagementUIHandlerChromeOS::GetFilesUploadToCloudInfo(
    Profile* profile) {
  policy::local_user_files::FileSaveDestination download_destination =
      policy::local_user_files::GetDownloadsDestination(profile);
  policy::local_user_files::FileSaveDestination screenshot_destination =
      policy::local_user_files::GetScreenCaptureDestination(profile);
  int uploads_id = -1;
  int destination_id = -1;
  if (IsCloudDestination(download_destination) &&
      IsCloudDestination(screenshot_destination)) {
    uploads_id = IDS_MANAGEMENT_FILES_CLOUD_UPLOAD_DOWNLOADS_AND_SCREENSHOTS;
    if (download_destination ==
            policy::local_user_files::FileSaveDestination::kGoogleDrive &&
        screenshot_destination ==
            policy::local_user_files::FileSaveDestination::kGoogleDrive) {
      destination_id = IDS_MANAGEMENT_FILES_CLOUD_UPLOAD_GOOGLE_DRIVE;
    } else if (download_destination ==
                   policy::local_user_files::FileSaveDestination::kOneDrive &&
               screenshot_destination ==
                   policy::local_user_files::FileSaveDestination::kOneDrive) {
      destination_id = IDS_MANAGEMENT_FILES_CLOUD_UPLOAD_ONEDRIVE;
    } else {
      destination_id =
          IDS_MANAGEMENT_FILES_CLOUD_UPLOAD_GOOGLE_DRIVE_AND_ONEDRIVE;
    }
  } else if (IsCloudDestination(download_destination)) {
    uploads_id = IDS_MANAGEMENT_FILES_CLOUD_UPLOAD_DOWNLOADS;
    if (download_destination ==
        policy::local_user_files::FileSaveDestination::kGoogleDrive) {
      destination_id = IDS_MANAGEMENT_FILES_CLOUD_UPLOAD_GOOGLE_DRIVE;
    } else {
      destination_id = IDS_MANAGEMENT_FILES_CLOUD_UPLOAD_ONEDRIVE;
    }
  } else if (IsCloudDestination(screenshot_destination)) {
    uploads_id = IDS_MANAGEMENT_FILES_CLOUD_UPLOAD_SCREENSHOTS;
    if (screenshot_destination ==
        policy::local_user_files::FileSaveDestination::kGoogleDrive) {
      destination_id = IDS_MANAGEMENT_FILES_CLOUD_UPLOAD_GOOGLE_DRIVE;
    } else {
      destination_id = IDS_MANAGEMENT_FILES_CLOUD_UPLOAD_ONEDRIVE;
    }
  }

  if (uploads_id == -1) {
    return std::u16string();
  }

  return l10n_util::GetStringFUTF16(
      IDS_MANAGEMENT_FILES_CLOUD_UPLOAD_CONFIGURATION,
      l10n_util::GetStringUTF16(uploads_id),
      l10n_util::GetStringUTF16(destination_id));
}

const ash::SecureDnsManager* ManagementUIHandlerChromeOS::GetSecureDnsManager()
    const {
  return g_browser_process->platform_part()->secure_dns_manager();
}
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

void ManagementUIHandlerChromeOS::HandleGetFilesUploadToCloudInfo(
    const base::Value::List& args) {
  CHECK_EQ(1U, args.size());

  AllowJavascript();

#if BUILDFLAG(IS_CHROMEOS_ASH)
  ResolveJavascriptCallback(
      args[0] /* callback_id */,
      base::Value(GetFilesUploadToCloudInfo(Profile::FromWebUI(web_ui()))));
#else
  ResolveJavascriptCallback(args[0] /* callback_id */, base::Value());
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
}

void ManagementUIHandlerChromeOS::HandleGetDeviceReportingInfo(
    const base::Value::List& args) {
  AllowJavascript();
#if BUILDFLAG(IS_CHROMEOS_ASH)
  base::Value::List report_sources = GetDeviceReportingInfo(
      GetDeviceCloudPolicyManager(), Profile::FromWebUI(web_ui()));
  ResolveJavascriptCallback(args[0] /* callback_id */, report_sources);
#else
  ResolveJavascriptCallback(args[0] /* callback_id */, report_sources_);
#endif
}

void ManagementUIHandlerChromeOS::HandleGetPluginVmDataCollectionStatus(
    const base::Value::List& args) {
  CHECK_EQ(1U, args.size());
#if BUILDFLAG(IS_CHROMEOS_ASH)
  base::Value plugin_vm_data_collection_enabled(
      Profile::FromWebUI(web_ui())->GetPrefs()->GetBoolean(
          plugin_vm::prefs::kPluginVmDataCollectionAllowed));
#else
  base::Value plugin_vm_data_collection_enabled(
      plugin_vm_data_collection_enabled_);
#endif
  AllowJavascript();
  ResolveJavascriptCallback(args[0] /* callback_id */,
                            plugin_vm_data_collection_enabled);
}

void ManagementUIHandlerChromeOS::
    CheckGetAllScreensMediaAllowedForAnyOriginResultReceived(bool is_allowed) {
  set_is_get_all_screens_media_allowed_for_any_origin(is_allowed);
  if (IsJavascriptAllowed()) {
    NotifyThreatProtectionInfoUpdated();
  }
}

std::unique_ptr<ManagementUIHandler> ManagementUIHandler::Create(
    Profile* profile) {
  return std::make_unique<ManagementUIHandlerChromeOS>(profile);
}