// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif
#include "chrome/browser/ui/webui/ash/network_ui.h"
#include <memory>
#include <string>
#include <utility>
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
#include "ash/public/cpp/connectivity_services.h"
#include "ash/public/cpp/esim_manager.h"
#include "ash/public/cpp/network_config_service.h"
#include "ash/webui/common/trusted_types_util.h"
#include "ash/webui/network_ui/network_diagnostics_resource_provider.h"
#include "ash/webui/network_ui/network_health_resource_provider.h"
#include "ash/webui/network_ui/traffic_counters_resource_provider.h"
#include "base/functional/bind.h"
#include "base/json/json_reader.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
#include "chrome/browser/ash/net/network_health/network_health_manager.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/feedback/show_feedback_page.h"
#include "chrome/browser/ui/ash/system/system_tray_client_impl.h"
#include "chrome/browser/ui/webui/ash/cellular_setup/cellular_setup_localized_strings_provider.h"
#include "chrome/browser/ui/webui/ash/internet_config_dialog.h"
#include "chrome/browser/ui/webui/ash/internet_detail_dialog.h"
#include "chrome/browser/ui/webui/ash/network_logs_message_handler.h"
#include "chrome/browser/ui/webui/ash/onc_import_message_handler.h"
#include "chrome/browser/ui/webui/webui_util.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/browser_resources.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/grit/network_ui_resources.h"
#include "chrome/grit/network_ui_resources_map.h"
#include "chromeos/ash/components/dbus/shill/shill_manager_client.h"
#include "chromeos/ash/components/network/cellular_esim_profile_handler.h"
#include "chromeos/ash/components/network/cellular_esim_profile_handler_impl.h"
#include "chromeos/ash/components/network/cellular_esim_uninstall_handler.h"
#include "chromeos/ash/components/network/cellular_utils.h"
#include "chromeos/ash/components/network/device_state.h"
#include "chromeos/ash/components/network/managed_network_configuration_handler.h"
#include "chromeos/ash/components/network/network_configuration_handler.h"
#include "chromeos/ash/components/network/network_device_handler.h"
#include "chromeos/ash/components/network/network_state.h"
#include "chromeos/ash/components/network/network_state_handler.h"
#include "chromeos/ash/components/network/onc/network_onc_utils.h"
#include "chromeos/ash/services/cellular_setup/public/mojom/esim_manager.mojom.h"
#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
#include "chromeos/services/network_health/public/mojom/network_diagnostics.mojom.h"
#include "chromeos/services/network_health/public/mojom/network_health.mojom.h"
#include "chromeos/strings/grit/chromeos_strings.h"
#include "components/device_event_log/device_event_log.h"
#include "components/user_manager/user_manager.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_data_source.h"
#include "content/public/browser/web_ui_message_handler.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/chromeos/strings/network/network_element_localized_strings_provider.h"
namespace ash {
namespace {
constexpr char kAddNetwork[] = "addNetwork";
constexpr char kDisableESimProfile[] = "disableActiveESimProfile";
constexpr char kGetNetworkProperties[] = "getShillNetworkProperties";
constexpr char kGetFirstWifiNetworkProperties[] =
"getFirstWifiNetworkProperties";
constexpr char kGetDeviceProperties[] = "getShillDeviceProperties";
constexpr char kGetEthernetEAP[] = "getShillEthernetEAP";
constexpr char kOpenCellularActivationUi[] = "openCellularActivationUi";
constexpr char kResetESimCache[] = "resetESimCache";
constexpr char kResetEuicc[] = "resetEuicc";
constexpr char kResetApnMigrator[] = "resetApnMigrator";
constexpr char kShowNetworkDetails[] = "showNetworkDetails";
constexpr char kShowNetworkConfig[] = "showNetworkConfig";
constexpr char kShowAddNewWifiNetworkDialog[] = "showAddNewWifi";
constexpr char kGetHostname[] = "getHostname";
constexpr char kSetHostname[] = "setHostname";
constexpr char kGetTetheringCapabilities[] = "getTetheringCapabilities";
constexpr char kGetTetheringStatus[] = "getTetheringStatus";
constexpr char kGetTetheringConfig[] = "getTetheringConfig";
constexpr char kSetTetheringConfig[] = "setTetheringConfig";
constexpr char kCheckTetheringReadiness[] = "checkTetheringReadiness";
constexpr char kGetWifiDirectCapabilities[] = "getWifiDirectCapabilities";
constexpr char kGetWifiDirectOwnerInfo[] = "getWifiDirectOwnerInfo";
constexpr char kGetWifiDirectClientInfo[] = "getWifiDirectClientInfo";
bool GetServicePathFromGuid(const std::string& guid,
std::string* service_path) {
const NetworkState* network =
NetworkHandler::Get()->network_state_handler()->GetNetworkStateFromGuid(
guid);
if (!network)
return false;
*service_path = network->path();
return true;
}
void SetDeviceProperties(base::Value::Dict* dictionary) {
DCHECK(dictionary);
const std::string* device = dictionary->FindString(shill::kDeviceProperty);
if (!device)
return;
const DeviceState* device_state =
NetworkHandler::Get()->network_state_handler()->GetDeviceState(*device);
if (!device_state)
return;
base::Value::Dict device_dictionary = device_state->properties().Clone();
if (!device_state->ip_configs().empty()) {
// Convert IPConfig dictionary to a ListValue.
base::Value::List ip_configs;
for (auto iter : device_state->ip_configs()) {
ip_configs.Append(iter.second.Clone());
}
device_dictionary.Set(shill::kIPConfigsProperty, std::move(ip_configs));
}
if (!device_dictionary.empty())
dictionary->Set(shill::kDeviceProperty, std::move(device_dictionary));
}
bool IsGuestModeActive() {
return user_manager::UserManager::Get()->IsLoggedInAsGuest() ||
user_manager::UserManager::Get()->IsLoggedInAsManagedGuestSession();
}
// Get the euicc path for reset euicc operation. Return std::nullopt if the
// reset euicc is not allowed, i.e: the user is in guest mode, admin enables
// restrict cellular network policy or a managed eSIM profile already installed.
std::optional<dbus::ObjectPath> GetEuiccResetPath() {
if (IsGuestModeActive()) {
NET_LOG(ERROR) << "Couldn't reset EUICC in guest mode.";
return std::nullopt;
}
std::optional<dbus::ObjectPath> euicc_path =
cellular_utils::GetCurrentEuiccPath();
if (!euicc_path) {
NET_LOG(ERROR) << "No current EUICC. Unable to reset EUICC";
return std::nullopt;
}
const ManagedNetworkConfigurationHandler*
managed_network_configuration_handler =
NetworkHandler::Get()->managed_network_configuration_handler();
if (!managed_network_configuration_handler)
return std::nullopt;
if (managed_network_configuration_handler
->AllowOnlyPolicyCellularNetworks()) {
NET_LOG(ERROR)
<< "Couldn't reset EUICC if admin restricts cellular networks.";
return std::nullopt;
}
NetworkStateHandler* network_state_handler =
NetworkHandler::Get()->network_state_handler();
if (!network_state_handler)
return std::nullopt;
NetworkStateHandler::NetworkStateList state_list;
network_state_handler->GetNetworkListByType(NetworkTypePattern::Cellular(),
/*configured_only=*/false,
/*visible_only=*/false,
/*limit=*/0, &state_list);
HermesEuiccClient::Properties* euicc_properties =
HermesEuiccClient::Get()->GetProperties(*euicc_path);
const std::string& eid = euicc_properties->eid().value();
for (const NetworkState* network : state_list) {
if (network->eid() == eid && network->IsManagedByPolicy()) {
NET_LOG(ERROR)
<< "Couldn't reset EUICC if a managed eSIM profile is installed.";
return std::nullopt;
}
}
return euicc_path;
}
std::string HexDecode(const std::string& hex_ssid) {
std::string ssid;
if (!base::HexStringToString(hex_ssid, &ssid)) {
NET_LOG(ERROR) << "Error decoding HexSSID: " << hex_ssid;
}
return ssid;
}
class NetworkDiagnosticsMessageHandler : public content::WebUIMessageHandler {
public:
NetworkDiagnosticsMessageHandler() = default;
~NetworkDiagnosticsMessageHandler() override = default;
void RegisterMessages() override {
web_ui()->RegisterMessageCallback(
"OpenFeedbackDialog",
base::BindRepeating(
&NetworkDiagnosticsMessageHandler::OpenFeedbackDialog,
base::Unretained(this)));
}
private:
void OpenFeedbackDialog(const base::Value::List& value) {
chrome::ShowFeedbackPage(
nullptr, feedback::kFeedbackSourceNetworkHealthPage,
"" /*description_template*/, "" /*description_template_placeholder*/,
"network-health", "" /*extra_diagnostics*/);
}
};
} // namespace
namespace network_ui {
class NetworkConfigMessageHandler : public content::WebUIMessageHandler {
public:
NetworkConfigMessageHandler() {}
NetworkConfigMessageHandler(const NetworkConfigMessageHandler&) = delete;
NetworkConfigMessageHandler& operator=(const NetworkConfigMessageHandler&) =
delete;
~NetworkConfigMessageHandler() override {}
// WebUIMessageHandler implementation.
void RegisterMessages() override {
web_ui()->RegisterMessageCallback(
kAddNetwork,
base::BindRepeating(&NetworkConfigMessageHandler::AddNetwork,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kGetNetworkProperties,
base::BindRepeating(
&NetworkConfigMessageHandler::GetShillNetworkProperties,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kGetFirstWifiNetworkProperties,
base::BindRepeating(
&NetworkConfigMessageHandler::GetFirstWifiNetworkProperties,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kGetDeviceProperties,
base::BindRepeating(
&NetworkConfigMessageHandler::GetShillDeviceProperties,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kGetEthernetEAP,
base::BindRepeating(&NetworkConfigMessageHandler::GetShillEthernetEAP,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kOpenCellularActivationUi,
base::BindRepeating(
&NetworkConfigMessageHandler::OpenCellularActivationUi,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kResetESimCache,
base::BindRepeating(&NetworkConfigMessageHandler::ResetESimCache,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kDisableESimProfile,
base::BindRepeating(
&NetworkConfigMessageHandler::DisableActiveESimProfile,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kResetEuicc,
base::BindRepeating(&NetworkConfigMessageHandler::ResetEuicc,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kResetApnMigrator,
base::BindRepeating(&NetworkConfigMessageHandler::ResetApnMigrator,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kShowNetworkDetails,
base::BindRepeating(&NetworkConfigMessageHandler::ShowNetworkDetails,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kShowNetworkConfig,
base::BindRepeating(&NetworkConfigMessageHandler::ShowNetworkConfig,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kShowAddNewWifiNetworkDialog,
base::BindRepeating(&NetworkConfigMessageHandler::ShowAddNewWifi,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kGetHostname,
base::BindRepeating(&NetworkConfigMessageHandler::GetHostname,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kSetHostname,
base::BindRepeating(&NetworkConfigMessageHandler::SetHostname,
base::Unretained(this)));
}
private:
void Respond(const std::string& callback_id, const base::ValueView response) {
AllowJavascript();
ResolveJavascriptCallback(base::Value(callback_id), response);
}
void GetShillNetworkProperties(const base::Value::List& arg_list) {
CHECK_EQ(2u, arg_list.size());
std::string callback_id = arg_list[0].GetString();
std::string guid = arg_list[1].GetString();
ProvideNetworkProperties(callback_id, guid);
}
void GetFirstWifiNetworkProperties(const base::Value::List& arg_list) {
std::string callback_id = arg_list[0].GetString();
const NetworkState* wifi_network =
NetworkHandler::Get()->network_state_handler()->FirstNetworkByType(
NetworkTypePattern::WiFi());
if (wifi_network) {
ProvideNetworkProperties(callback_id, wifi_network->guid());
return;
}
Respond(callback_id, base::Value::List());
}
void ProvideNetworkProperties(const std::string& callback_id,
const std::string& guid) {
std::string service_path;
if (!GetServicePathFromGuid(guid, &service_path)) {
RunErrorCallback(callback_id, guid, kGetNetworkProperties,
"Error.InvalidNetworkGuid");
return;
}
NetworkHandler::Get()->network_configuration_handler()->GetShillProperties(
service_path,
base::BindOnce(
&NetworkConfigMessageHandler::OnGetShillNetworkProperties,
weak_ptr_factory_.GetWeakPtr(), callback_id, guid));
}
void OnGetShillNetworkProperties(const std::string& callback_id,
const std::string& guid,
const std::string& service_path,
std::optional<base::Value::Dict> result) {
if (!result) {
RunErrorCallback(callback_id, guid, kGetNetworkProperties, "Error.DBus");
return;
}
// Set the 'service_path' property for debugging.
result->Set("service_path", service_path);
// Set the device properties for debugging.
SetDeviceProperties(&result.value());
base::Value::List return_arg_list;
return_arg_list.Append(std::move(*result));
Respond(callback_id, return_arg_list);
}
void GetShillDeviceProperties(const base::Value::List& arg_list) {
CHECK_EQ(2u, arg_list.size());
std::string callback_id = arg_list[0].GetString();
std::string type = arg_list[1].GetString();
const DeviceState* device =
NetworkHandler::Get()->network_state_handler()->GetDeviceStateByType(
onc::NetworkTypePatternFromOncType(type));
if (!device) {
RunErrorCallback(callback_id, type, kGetDeviceProperties,
"Error.InvalidDeviceType");
return;
}
NetworkHandler::Get()->network_device_handler()->GetDeviceProperties(
device->path(),
base::BindOnce(&NetworkConfigMessageHandler::OnGetShillDeviceProperties,
weak_ptr_factory_.GetWeakPtr(), callback_id, type));
}
void GetShillEthernetEAP(const base::Value::List& arg_list) {
CHECK_EQ(1u, arg_list.size());
std::string callback_id = arg_list[0].GetString();
NetworkStateHandler::NetworkStateList list;
NetworkHandler::Get()->network_state_handler()->GetNetworkListByType(
NetworkTypePattern::Primitive(shill::kTypeEthernetEap),
true /* configured_only */, false /* visible_only */, 1 /* limit */,
&list);
if (list.empty()) {
Respond(callback_id, base::Value::List());
return;
}
const NetworkState* eap = list.front();
Respond(callback_id,
base::Value::List().Append(base::Value::Dict()
.Set("guid", eap->guid())
.Set("name", eap->name())
.Set("type", eap->type())));
}
void OpenCellularActivationUi(const base::Value::List& arg_list) {
CHECK_EQ(1u, arg_list.size());
std::string callback_id = arg_list[0].GetString();
const NetworkState* cellular_network =
NetworkHandler::Get()->network_state_handler()->FirstNetworkByType(
NetworkTypePattern::Cellular());
if (cellular_network) {
SystemTrayClientImpl::Get()->ShowSettingsCellularSetup(
/*show_psim_flow=*/true);
}
base::Value::List response;
response.Append(base::Value(cellular_network != nullptr));
Respond(callback_id, response);
}
void ResetESimCache(const base::Value::List& arg_list) {
CellularESimProfileHandler* handler =
NetworkHandler::Get()->cellular_esim_profile_handler();
if (!handler)
return;
CellularESimProfileHandlerImpl* handler_impl =
static_cast<CellularESimProfileHandlerImpl*>(handler);
handler_impl->ResetESimProfileCache();
}
void DisableActiveESimProfile(const base::Value::List& arg_list) {
CellularESimProfileHandler* handler =
NetworkHandler::Get()->cellular_esim_profile_handler();
if (!handler)
return;
CellularESimProfileHandlerImpl* handler_impl =
static_cast<CellularESimProfileHandlerImpl*>(handler);
handler_impl->DisableActiveESimProfile();
}
void ResetEuicc(const base::Value::List& arg_list) {
std::optional<dbus::ObjectPath> euicc_path = GetEuiccResetPath();
if (!euicc_path)
return;
CellularESimUninstallHandler* handler =
NetworkHandler::Get()->cellular_esim_uninstall_handler();
if (!handler)
return;
NET_LOG(EVENT) << "Executing reset EUICC on " << euicc_path->value();
handler->ResetEuiccMemory(
*euicc_path, base::BindOnce(&NetworkConfigMessageHandler::OnEuiccReset,
base::Unretained(this)));
}
void ResetApnMigrator(const base::Value::List& arg_list) {
NET_LOG(EVENT) << "Executing reset ApnMigrator";
PrefService* local_state = g_browser_process->local_state();
// Clear set of migrated ICCIDs.
local_state->ClearPref(prefs::kApnMigratedIccids);
// Clear all revamp APN lists in all network.
const std::string network_metadata_pref = "network_metadata";
base::Value::Dict device_dict =
local_state->GetDict(network_metadata_pref).Clone();
for (auto const [guid, val] : device_dict) {
base::Value::Dict* network_dict = device_dict.FindDict(guid.c_str());
network_dict->Remove("custom_apn_list_v2");
}
local_state->SetDict(network_metadata_pref, std::move(device_dict));
}
void OnEuiccReset(bool success) {
if (!success) {
NET_LOG(ERROR) << "Error occurred when resetting EUICC.";
}
}
void ShowNetworkDetails(const base::Value::List& arg_list) {
CHECK_EQ(1u, arg_list.size());
std::string guid = arg_list[0].GetString();
InternetDetailDialog::ShowDialog(guid);
}
void ShowNetworkConfig(const base::Value::List& arg_list) {
CHECK_EQ(1u, arg_list.size());
std::string guid = arg_list[0].GetString();
InternetConfigDialog::ShowDialogForNetworkId(guid);
}
void ShowAddNewWifi(const base::Value::List& arg_list) {
InternetConfigDialog::ShowDialogForNetworkType(::onc::network_type::kWiFi);
}
void OnGetShillDeviceProperties(const std::string& callback_id,
const std::string& type,
const std::string& device_path,
std::optional<base::Value::Dict> result) {
if (!result) {
RunErrorCallback(callback_id, type, kGetDeviceProperties,
"GetDeviceProperties failed");
return;
}
// Set the 'device_path' property for debugging.
result->Set("device_path", device_path);
base::Value::List return_arg_list;
return_arg_list.Append(std::move(*result));
Respond(callback_id, return_arg_list);
}
void GetHostname(const base::Value::List& arg_list) {
CHECK_EQ(1u, arg_list.size());
std::string callback_id = arg_list[0].GetString();
std::string hostname =
NetworkHandler::Get()->network_state_handler()->hostname();
Respond(callback_id, base::Value(hostname));
}
void SetHostname(const base::Value::List& arg_list) {
CHECK_EQ(1u, arg_list.size());
std::string hostname = arg_list[0].GetString();
NET_LOG(USER) << "SET HOSTNAME: " << hostname;
NetworkHandler::Get()->network_state_handler()->SetHostname(hostname);
}
void RunErrorCallback(const std::string& callback_id,
const std::string& guid_or_type,
const std::string& function_name,
const std::string& error_name) {
NET_LOG(ERROR) << "Shill Error: " << error_name << " id=" << guid_or_type;
std::string key = function_name == kGetDeviceProperties
? shill::kTypeProperty
: shill::kGuidProperty;
Respond(callback_id, base::Value::List().Append(
base::Value::Dict()
.Set(key, base::Value(guid_or_type))
.Set("ShillError", base::Value(error_name))));
}
void AddNetwork(const base::Value::List& args) {
DCHECK(!args.empty());
std::string onc_type = args[0].GetString();
InternetConfigDialog::ShowDialogForNetworkType(onc_type);
}
base::WeakPtrFactory<NetworkConfigMessageHandler> weak_ptr_factory_{this};
};
class HotspotConfigMessageHandler : public content::WebUIMessageHandler {
public:
HotspotConfigMessageHandler() = default;
~HotspotConfigMessageHandler() override = default;
// WebUIMessageHandler implementation.
void RegisterMessages() override {
web_ui()->RegisterMessageCallback(
kGetTetheringCapabilities,
base::BindRepeating(
&HotspotConfigMessageHandler::GetTetheringCapabilities,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kGetTetheringStatus,
base::BindRepeating(&HotspotConfigMessageHandler::GetTetheringStatus,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kGetTetheringConfig,
base::BindRepeating(&HotspotConfigMessageHandler::GetTetheringConfig,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kSetTetheringConfig,
base::BindRepeating(&HotspotConfigMessageHandler::SetTetheringConfig,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kCheckTetheringReadiness,
base::BindRepeating(
&HotspotConfigMessageHandler::CheckTetheringReadiness,
base::Unretained(this)));
}
private:
void Respond(const std::string& callback_id, const base::ValueView response) {
AllowJavascript();
ResolveJavascriptCallback(base::Value(callback_id), response);
}
void GetTetheringCapabilities(const base::Value::List& arg_list) {
CHECK_EQ(1u, arg_list.size());
std::string callback_id = arg_list[0].GetString();
ShillManagerClient::Get()->GetProperties(base::BindOnce(
&HotspotConfigMessageHandler::OnGetShillManagerDictPropertiesByKey,
weak_ptr_factory_.GetWeakPtr(), callback_id,
shill::kTetheringCapabilitiesProperty));
}
void GetTetheringStatus(const base::Value::List& arg_list) {
CHECK_EQ(1u, arg_list.size());
std::string callback_id = arg_list[0].GetString();
ShillManagerClient::Get()->GetProperties(base::BindOnce(
&HotspotConfigMessageHandler::OnGetShillManagerDictPropertiesByKey,
weak_ptr_factory_.GetWeakPtr(), callback_id,
shill::kTetheringStatusProperty));
}
void GetTetheringConfig(const base::Value::List& arg_list) {
CHECK_EQ(1u, arg_list.size());
std::string callback_id = arg_list[0].GetString();
ShillManagerClient::Get()->GetProperties(base::BindOnce(
&HotspotConfigMessageHandler::OnGetShillManagerDictPropertiesByKey,
weak_ptr_factory_.GetWeakPtr(), callback_id,
shill::kTetheringConfigProperty));
}
void CheckTetheringReadiness(const base::Value::List& arg_list) {
CHECK_EQ(1u, arg_list.size());
std::string callback_id = arg_list[0].GetString();
ShillManagerClient::Get()->CheckTetheringReadiness(
base::BindOnce(&HotspotConfigMessageHandler::RespondStringResult,
weak_ptr_factory_.GetWeakPtr(), callback_id),
base::BindOnce(&HotspotConfigMessageHandler::RespondError,
weak_ptr_factory_.GetWeakPtr(), callback_id,
kCheckTetheringReadiness));
}
void SetTetheringConfig(const base::Value::List& arg_list) {
CHECK_EQ(2u, arg_list.size());
std::string callback_id = arg_list[0].GetString();
std::string tethering_config = arg_list[1].GetString();
std::optional<base::Value> value = base::JSONReader::Read(tethering_config);
if (!value || !value->is_dict()) {
NET_LOG(ERROR) << "Invalid tethering configuration: " << tethering_config;
Respond(callback_id, base::Value("Invalid tethering configuration"));
return;
}
NET_LOG(USER) << "SetManagerProperty: " << shill::kTetheringConfigProperty
<< ": " << *value;
const std::string* ssid =
value->GetDict().FindString(shill::kTetheringConfSSIDProperty);
if (ssid) {
value->GetDict().Set(shill::kTetheringConfSSIDProperty,
base::Value(base::HexEncode(*ssid)));
}
ShillManagerClient::Get()->SetProperty(
shill::kTetheringConfigProperty, *value,
base::BindOnce(&HotspotConfigMessageHandler::RespondStringResult,
weak_ptr_factory_.GetWeakPtr(), callback_id, "success"),
base::BindOnce(
&HotspotConfigMessageHandler::SetManagerPropertiesErrorCallback,
weak_ptr_factory_.GetWeakPtr(), callback_id,
shill::kTetheringConfigProperty));
}
void OnGetShillManagerDictPropertiesByKey(
const std::string& callback_id,
const std::string& dict_key,
std::optional<base::Value::Dict> properties) {
if (!properties) {
NET_LOG(ERROR) << "Error getting Shill manager properties.";
Respond(callback_id,
base::Value("Error getting Shill manager properties."));
return;
}
base::Value::Dict* value = properties->FindDict(dict_key);
if (value) {
const std::string* ssid =
value->FindString(shill::kTetheringConfSSIDProperty);
if (ssid) {
value->Set(shill::kTetheringConfSSIDProperty, HexDecode(*ssid));
}
Respond(callback_id, *value);
return;
}
Respond(callback_id, base::Value::Dict());
}
void SetManagerPropertiesErrorCallback(
const std::string& callback_id,
const std::string& property_name,
const std::string& dbus_error_name,
const std::string& dbus_error_message) {
NET_LOG(ERROR) << "Error setting Shill manager properties: "
<< property_name << ", error: " << dbus_error_name
<< ", message: " << dbus_error_message;
Respond(callback_id, base::Value(dbus_error_name));
}
void RespondError(const std::string& callback_id,
const std::string& operation,
const std::string& error_name,
const std::string& error_message) {
NET_LOG(ERROR) << "Error occured when " << operation << ": " << error_name
<< ", error message: " << error_message;
Respond(callback_id, base::Value(error_name));
}
void RespondStringResult(const std::string& callback_id,
const std::string& result) {
Respond(callback_id, base::Value(result));
}
base::WeakPtrFactory<HotspotConfigMessageHandler> weak_ptr_factory_{this};
};
class WifiDirectMessageHandler : public content::WebUIMessageHandler {
public:
WifiDirectMessageHandler() = default;
~WifiDirectMessageHandler() override = default;
// WebUIMessageHandler implementation.
void RegisterMessages() override {
web_ui()->RegisterMessageCallback(
kGetWifiDirectCapabilities,
base::BindRepeating(
&WifiDirectMessageHandler::GetWifiDirectCapabilities,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kGetWifiDirectOwnerInfo,
base::BindRepeating(&WifiDirectMessageHandler::GetWifiDirectOwnerInfo,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kGetWifiDirectClientInfo,
base::BindRepeating(&WifiDirectMessageHandler::GetWifiDirectClientInfo,
base::Unretained(this)));
}
private:
void Respond(const std::string& callback_id, const base::ValueView response) {
AllowJavascript();
ResolveJavascriptCallback(base::Value(callback_id), response);
}
void GetWifiDirectCapabilities(const base::Value::List& arg_list) {
CHECK_EQ(1u, arg_list.size());
std::string callback_id = arg_list[0].GetString();
ShillManagerClient::Get()->GetProperties(base::BindOnce(
&WifiDirectMessageHandler::OnGetShillManagerDictPropertiesByKey,
weak_ptr_factory_.GetWeakPtr(), callback_id,
shill::kP2PCapabilitiesProperty));
}
void GetWifiDirectOwnerInfo(const base::Value::List& arg_list) {
CHECK_EQ(1u, arg_list.size());
std::string callback_id = arg_list[0].GetString();
ShillManagerClient::Get()->GetProperties(base::BindOnce(
&WifiDirectMessageHandler::OnGetShillManagerListPropertiesByKey,
weak_ptr_factory_.GetWeakPtr(), callback_id,
shill::kP2PGroupInfosProperty));
}
void GetWifiDirectClientInfo(const base::Value::List& arg_list) {
CHECK_EQ(1u, arg_list.size());
std::string callback_id = arg_list[0].GetString();
ShillManagerClient::Get()->GetProperties(base::BindOnce(
&WifiDirectMessageHandler::OnGetShillManagerListPropertiesByKey,
weak_ptr_factory_.GetWeakPtr(), callback_id,
shill::kP2PClientInfosProperty));
}
void OnGetShillManagerListPropertiesByKey(
const std::string& callback_id,
const std::string& dict_key,
std::optional<base::Value::Dict> properties) {
if (!properties) {
NET_LOG(ERROR) << "Error getting Shill manager properties.";
Respond(callback_id,
base::Value("Error getting Shill manager properties."));
return;
}
base::Value::List* value = properties->FindList(dict_key);
Respond(callback_id, value ? std::move(*value) : base::Value::List());
}
void OnGetShillManagerDictPropertiesByKey(
const std::string& callback_id,
const std::string& dict_key,
std::optional<base::Value::Dict> properties) {
if (!properties) {
NET_LOG(ERROR) << "Error getting Shill manager properties.";
Respond(callback_id,
base::Value("Error getting Shill manager properties."));
return;
}
base::Value::Dict* value = properties->FindDict(dict_key);
Respond(callback_id, value ? std::move(*value) : base::Value::Dict());
}
base::WeakPtrFactory<WifiDirectMessageHandler> weak_ptr_factory_{this};
};
} // namespace network_ui
// static
base::Value::Dict NetworkUI::GetLocalizedStrings() {
return base::Value::Dict()
.Set("titleText", l10n_util::GetStringUTF16(IDS_NETWORK_UI_TITLE))
.Set("generalTab", l10n_util::GetStringUTF16(IDS_NETWORK_UI_TAB_GENERAL))
.Set("networkHealthTab",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_TAB_NETWORK_HEALTH))
.Set("networkLogsTab",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_TAB_NETWORK_LOGS))
.Set("networkStateTab",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_TAB_NETWORK_STATE))
.Set("networkSelectTab",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_TAB_NETWORK_SELECT))
.Set("networkHotspotTab",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_TAB_NETWORK_HOTSPOT))
.Set("networkMetricsTab",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_TAB_NETWORK_METRICS))
.Set("networkWifiDirectTab",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_TAB_NETWORK_WIFI_DIRECT))
.Set("autoRefreshText",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_AUTO_REFRESH))
.Set("deviceLogLinkText",
l10n_util::GetStringUTF16(IDS_DEVICE_LOG_LINK_TEXT))
.Set("networkRefreshText",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_REFRESH))
.Set("clickToExpandText",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_EXPAND))
.Set("propertyFormatText",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_PROPERTY_FORMAT))
.Set("normalFormatOption",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_FORMAT_NORMAL))
.Set("managedFormatOption",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_FORMAT_MANAGED))
.Set("stateFormatOption",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_FORMAT_STATE))
.Set("shillFormatOption",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_FORMAT_SHILL))
.Set("dhcpHostnameLabel",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_DHCP_HOSTNAME))
.Set("globalPolicyLabel",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_GLOBAL_POLICY))
.Set("networkListsLabel",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_NETWORK_LISTS))
.Set("networkHealthLabel",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_NETWORK_HEALTH))
.Set("networkDiagnosticsLabel",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_NETWORK_DIAGNOSTICS))
.Set("visibleNetworksLabel",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_VISIBLE_NETWORKS))
.Set("favoriteNetworksLabel",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_FAVORITE_NETWORKS))
.Set("ethernetEapNetworkLabel",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_ETHERNET_EAP))
.Set("devicesLabel", l10n_util::GetStringUTF16(IDS_NETWORK_UI_DEVICES))
.Set("cellularActivationLabel",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_NO_CELLULAR_ACTIVATION_LABEL))
.Set("cellularActivationButtonText",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_OPEN_CELLULAR_ACTIVATION_BUTTON_TEXT))
.Set("noCellularErrorText",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_NO_CELLULAR_ERROR_TEXT))
.Set("resetESimCacheLabel",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_RESET_ESIM_PROFILES_BUTTON_TEXT))
.Set("resetESimCacheButtonText",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_RESET_ESIM_PROFILES_BUTTON_TEXT))
.Set(
"disableESimProfilesLabel",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_DISABLE_ESIM_PROFILES_LABEL))
.Set("disableActiveESimProfileButtonText",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_DISABLE_ACTIVE_ESIM_PROFILE_BUTTON_TEXT))
.Set("resetEuiccLabel",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_RESET_EUICC_LABEL))
.Set("resetApnMigratorLabel",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_RESET_APN_MIGRATOR_LABEL))
.Set("addNewWifiLabel",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_ADD_NEW_WIFI_LABEL))
.Set("addNewWifiButtonText",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_ADD_NEW_WIFI_BUTTON_TEXT))
.Set("importOncButtonText",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_IMPORT_ONC_BUTTON_TEXT))
.Set("addWiFiListItemName",
l10n_util::GetStringUTF16(IDS_NETWORK_ADD_WI_FI_LIST_ITEM_NAME))
// Network logs
.Set("networkLogsDescription",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_NETWORK_LOGS_DESCRIPTION))
.Set("networkLogsSystemLogs",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_NETWORK_LOGS_SYSTEM_LOGS))
.Set("networkLogsFilterPii",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_NETWORK_LOGS_FILTER_PII))
.Set("networkLogsPolicies",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_NETWORK_LOGS_POLICIES))
.Set("networkLogsDebugLogs",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_NETWORK_LOGS_DEBUG_LOGS))
.Set("networkLogsChromeLogs",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_NETWORK_LOGS_CHROME_LOGS))
.Set("networkLogsStoreButton",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_NETWORK_LOGS_STORE_BUTTON))
.Set("networkLogsStatus",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_NETWORK_LOGS_STATUS))
.Set("networkLogsDebuggingTitle",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_NETWORK_LOGS_DEBUGGING_TITLE))
.Set("networkLogsDebuggingDescription",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_NETWORK_LOGS_DEBUGGING_DESCRIPTION))
.Set(
"networkLogsDebuggingNone",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_NETWORK_LOGS_DEBUGGING_NONE))
.Set("networkLogsDebuggingUnknown",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_NETWORK_LOGS_DEBUGGING_UNKNOWN))
// Network Diagnostics
.Set("NetworkDiagnosticsRunAll",
l10n_util::GetStringUTF16(IDS_NETWORK_DIAGNOSTICS_RUN_ALL))
.Set("NetworkDiagnosticsSendFeedback",
l10n_util::GetStringUTF16(IDS_NETWORK_DIAGNOSTICS_SEND_FEEDBACK))
.Set("renderNetworkSelectButtonText",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_RENDER_NETWORK_SELECT_BUTTON_TEXT))
.Set("renderNetworkSelectButtonDescription",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_RENDER_NETWORK_SELECT_BUTTON_DESCRIPTION))
// Network Metrics
.Set("networkMetricsLabel",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_NETWORK_METRICS_LABEL))
.Set("renderGraphButtonText",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_NETWORK_METRICS_RENDER_BUTTON))
.Set("startPlotsButtonText",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_NETWORK_METRICS_START_BUTTON))
.Set(
"stopPlotsButtonText",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_NETWORK_METRICS_STOP_BUTTON))
.Set("increaseRateButtonText",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_NETWORK_METRICS_INCREASE_RATE_BUTTON))
.Set("decreaseRateButtonText",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_NETWORK_METRICS_DECREASE_RATE_BUTTON))
// Network Hotspot
.Set("tetheringCapabilitiesLabel",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_TETHERING_CAPABILITIES_LABEL))
.Set("refreshTetheringCapabilitiesButtonText",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_REFRESH_TETHERING_CAPABILITIES_BUTTON_TEXT))
.Set("tetheringStatusLabel",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_TETHERING_STATUS_LABEL))
.Set("refreshTetheringStatusButtonText",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_REFRESH_TETHERING_STATUS_BUTTON_TEXT))
.Set("tetheringConfigLabel",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_TETHERING_CONFIG_LABEL))
.Set("refreshTetheringConfigButtonText",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_REFRESH_TETHERING_CONFIG_BUTTON_TEXT))
.Set("setTetheringConfigButtonText",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_SET_TETHERING_CONFIG_BUTTON_TEXT))
.Set("tetheringReadinessLabel",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_TETHERING_READINESS_LABEL))
.Set("checkTetheringReadinessButtonText",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_CHECK_TETHERING_READINESS_BUTTON_TEXT))
.Set(
"setTetheringEnabledLabel",
l10n_util::GetStringUTF16(IDS_NETWORK_UI_SET_TETHERING_ENABLED_LABEL))
// Network Wifi Direct
.Set("wifiDirectCapabilitiesLabel",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_WIFI_DIRECT_CAPABILITIES_LABEL))
.Set("refreshWifiDirectCapabilitiesButtonText",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_REFRESH_WIFI_DIRECT_CAPABILITIES_BUTTON_TEXT))
.Set("wifiDirectOwnerInfoLabel",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_WIFI_DIRECT_OWNER_INFO_LABEL))
.Set("refreshWifiDirectOwnerInfoButtonText",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_REFRESH_WIFI_DIRECT_OWNER_INFO_BUTTON_TEXT))
.Set("wifiDirectClientInfoLabel",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_WIFI_DIRECT_CLIENT_INFO_LABEL))
.Set("refreshWifiDirectClientInfoButtonText",
l10n_util::GetStringUTF16(
IDS_NETWORK_UI_REFRESH_WIFI_DIRECT_CLIENT_INFO_BUTTON_TEXT));
}
NetworkUI::NetworkUI(content::WebUI* web_ui)
: ui::MojoWebUIController(web_ui, /*enable_chrome_send=*/true) {
web_ui->AddMessageHandler(
std::make_unique<network_ui::NetworkConfigMessageHandler>());
web_ui->AddMessageHandler(std::make_unique<OncImportMessageHandler>());
web_ui->AddMessageHandler(std::make_unique<NetworkLogsMessageHandler>());
web_ui->AddMessageHandler(
std::make_unique<NetworkDiagnosticsMessageHandler>());
web_ui->AddMessageHandler(
std::make_unique<network_ui::HotspotConfigMessageHandler>());
web_ui->AddMessageHandler(
std::make_unique<network_ui::WifiDirectMessageHandler>());
// Enable extension API calls in the WebUI.
extensions::TabHelper::CreateForWebContents(web_ui->GetWebContents());
base::Value::Dict localized_strings = GetLocalizedStrings();
content::WebUIDataSource* html = content::WebUIDataSource::CreateAndAdd(
web_ui->GetWebContents()->GetBrowserContext(),
chrome::kChromeUINetworkHost);
html->AddLocalizedStrings(localized_strings);
html->AddBoolean("isGuestModeActive", IsGuestModeActive());
html->AddBoolean("isWifiDirectEnabled", features::IsWifiDirectEnabled());
html->AddString("tetheringStateStarting", shill::kTetheringStateStarting);
html->AddString("tetheringStateActive", shill::kTetheringStateActive);
network_health::AddResources(html);
network_diagnostics::AddResources(html);
cellular_setup::AddLocalizedStrings(html);
cellular_setup::AddNonStringLoadTimeData(html);
ui::network_element::AddLocalizedStrings(html);
ui::network_element::AddOncLocalizedStrings(html);
traffic_counters::AddResources(html);
webui::SetupWebUIDataSource(
html, base::make_span(kNetworkUiResources, kNetworkUiResourcesSize),
IDR_NETWORK_UI_NETWORK_HTML);
// Enabling trusted types via trusted_types_util must be done after
// webui::SetupWebUIDataSource to override the trusted type CSP with correct
// policies for JS WebUIs.
ash::EnableTrustedTypesCSP(html);
}
NetworkUI::~NetworkUI() = default;
void NetworkUI::BindInterface(
mojo::PendingReceiver<chromeos::network_config::mojom::CrosNetworkConfig>
receiver) {
GetNetworkConfigService(std::move(receiver));
}
void NetworkUI::BindInterface(
mojo::PendingReceiver<chromeos::network_health::mojom::NetworkHealthService>
receiver) {
network_health::NetworkHealthManager::GetInstance()->BindHealthReceiver(
std::move(receiver));
}
void NetworkUI::BindInterface(
mojo::PendingReceiver<
chromeos::network_diagnostics::mojom::NetworkDiagnosticsRoutines>
receiver) {
network_health::NetworkHealthManager::GetInstance()->BindDiagnosticsReceiver(
std::move(receiver));
}
void NetworkUI::BindInterface(
mojo::PendingReceiver<cellular_setup::mojom::ESimManager> receiver) {
GetESimManager(std::move(receiver));
}
void NetworkUI::BindInterface(
mojo::PendingReceiver<chromeos::connectivity::mojom::PasspointService>
receiver) {
GetPasspointService(std::move(receiver));
}
WEB_UI_CONTROLLER_TYPE_IMPL(NetworkUI)
} // namespace ash