| // Copyright 2020 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/ash/network_logs_message_handler.h" |
| |
| #include <iostream> |
| |
| #include "base/files/file_util.h" |
| #include "base/system/sys_info.h" |
| #include "base/task/task_traits.h" |
| #include "base/task/thread_pool.h" |
| #include "chrome/browser/ash/file_manager/filesystem_api_util.h" |
| #include "chrome/browser/ash/system_logs/debug_log_writer.h" |
| #include "chrome/browser/ash/system_logs/system_logs_writer.h" |
| #include "chrome/browser/download/download_prefs.h" |
| #include "chrome/browser/policy/chrome_policy_conversions_client.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/common/logging_chrome.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "chromeos/ash/components/dbus/debug_daemon/debug_daemon_client.h" |
| #include "components/policy/core/browser/policy_conversions.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/browser/web_ui.h" |
| #include "ui/base/l10n/l10n_util.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| base::FilePath GetDownloadsDirectory(content::WebUI* web_ui) { |
| Profile* profile = Profile::FromWebUI(web_ui); |
| const DownloadPrefs* const prefs = DownloadPrefs::FromBrowserContext(profile); |
| base::FilePath path = prefs->DownloadPath(); |
| if (file_manager::util::IsUnderNonNativeLocalPath(profile, path)) |
| path = prefs->GetDefaultDownloadDirectoryForProfile(); |
| return path; |
| } |
| |
| std::string GetJsonPolicies(content::WebUI* web_ui) { |
| return policy::PolicyConversions( |
| std::make_unique<policy::ChromePolicyConversionsClient>( |
| web_ui->GetWebContents()->GetBrowserContext())) |
| .ToJSON(); |
| } |
| |
| bool WriteTimestampedFile(const base::FilePath& file_path, |
| const std::string& contents) { |
| base::FilePath timestamped_file_path = |
| logging::GenerateTimestampedName(file_path, base::Time::Now()); |
| return base::WriteFile(timestamped_file_path, contents); |
| } |
| |
| bool GetBoolOrFalse(const base::Value::Dict& dict, const char* keyname) { |
| const auto key = dict.FindBool(keyname); |
| return key && *key; |
| } |
| |
| } // namespace |
| |
| NetworkLogsMessageHandler::NetworkLogsMessageHandler() = default; |
| |
| NetworkLogsMessageHandler::~NetworkLogsMessageHandler() = default; |
| |
| void NetworkLogsMessageHandler::RegisterMessages() { |
| out_dir_ = GetDownloadsDirectory(web_ui()); |
| web_ui()->RegisterMessageCallback( |
| "storeLogs", base::BindRepeating(&NetworkLogsMessageHandler::OnStoreLogs, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "setShillDebugging", |
| base::BindRepeating(&NetworkLogsMessageHandler::OnSetShillDebugging, |
| base::Unretained(this))); |
| } |
| |
| void NetworkLogsMessageHandler::Respond(const std::string& callback_id, |
| const std::string& result, |
| bool is_error) { |
| base::Value::List response; |
| response.Append(result); |
| response.Append(is_error); |
| ResolveJavascriptCallback(base::Value(callback_id), response); |
| } |
| |
| void NetworkLogsMessageHandler::OnStoreLogs(const base::Value::List& list) { |
| CHECK_EQ(2u, list.size()); |
| std::string callback_id = list[0].GetString(); |
| const base::Value::Dict& options = list[1].GetDict(); |
| AllowJavascript(); |
| |
| if (GetBoolOrFalse(options, "systemLogs")) { |
| bool scrub_data = GetBoolOrFalse(options, "filterPII"); |
| system_logs_writer::WriteSystemLogs( |
| Profile::FromWebUI(web_ui()), out_dir_, scrub_data, |
| base::BindOnce(&NetworkLogsMessageHandler::OnWriteSystemLogs, |
| weak_factory_.GetWeakPtr(), callback_id, |
| options.Clone())); |
| } else { |
| MaybeWriteDebugLogs(callback_id, options.Clone()); |
| } |
| } |
| |
| void NetworkLogsMessageHandler::OnWriteSystemLogs( |
| const std::string& callback_id, |
| base::Value::Dict&& options, |
| std::optional<base::FilePath> syslogs_path) { |
| if (!syslogs_path) { |
| Respond(callback_id, "Error writing system logs file.", /*is_error=*/true); |
| return; |
| } |
| MaybeWriteDebugLogs(callback_id, std::move(options)); |
| } |
| |
| void NetworkLogsMessageHandler::MaybeWriteDebugLogs( |
| const std::string& callback_id, |
| base::Value::Dict&& options) { |
| if (GetBoolOrFalse(options, "debugLogs")) { |
| if (!base::SysInfo::IsRunningOnChromeOS()) { |
| Respond(callback_id, "Debug logs unavailable on Linux build.", |
| /*is_error=*/true); |
| return; |
| } |
| bool include_chrome = GetBoolOrFalse(options, "chromeLogs"); |
| debug_log_writer::StoreLogs( |
| out_dir_, include_chrome, |
| base::BindOnce(&NetworkLogsMessageHandler::OnWriteDebugLogs, |
| weak_factory_.GetWeakPtr(), callback_id, |
| std::move(options))); |
| } else { |
| MaybeWritePolicies(callback_id, std::move(options)); |
| } |
| } |
| |
| void NetworkLogsMessageHandler::OnWriteDebugLogs( |
| const std::string& callback_id, |
| base::Value::Dict&& options, |
| std::optional<base::FilePath> logs_path) { |
| if (!logs_path) { |
| Respond(callback_id, "Error writing debug logs.", /*is_error=*/true); |
| return; |
| } |
| MaybeWritePolicies(callback_id, std::move(options)); |
| } |
| |
| void NetworkLogsMessageHandler::MaybeWritePolicies( |
| const std::string& callback_id, |
| base::Value::Dict&& options) { |
| if (GetBoolOrFalse(options, "policies")) { |
| std::string json_policies = GetJsonPolicies(web_ui()); |
| base::ThreadPool::PostTaskAndReplyWithResult( |
| FROM_HERE, |
| {base::MayBlock(), base::TaskPriority::BEST_EFFORT, |
| base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, |
| base::BindOnce(WriteTimestampedFile, out_dir_.Append("policies.json"), |
| json_policies), |
| base::BindOnce(&NetworkLogsMessageHandler::OnWritePolicies, |
| weak_factory_.GetWeakPtr(), callback_id)); |
| } else { |
| OnWriteSystemLogsCompleted(callback_id); |
| } |
| } |
| |
| void NetworkLogsMessageHandler::OnWritePolicies(const std::string& callback_id, |
| bool result) { |
| if (!result) { |
| Respond(callback_id, "Error writing policies.", /*is_error=*/true); |
| return; |
| } |
| OnWriteSystemLogsCompleted(callback_id); |
| } |
| |
| void NetworkLogsMessageHandler::OnWriteSystemLogsCompleted( |
| const std::string& callback_id) { |
| Respond(callback_id, |
| l10n_util::GetStringUTF8(IDS_NETWORK_UI_NETWORK_LOGS_SUCCESS), |
| /*is_error=*/false); |
| } |
| |
| void NetworkLogsMessageHandler::OnSetShillDebugging( |
| const base::Value::List& list) { |
| CHECK_EQ(2u, list.size()); |
| std::string callback_id = list[0].GetString(); |
| std::string subsystem = list[1].GetString(); |
| AllowJavascript(); |
| DebugDaemonClient::Get()->SetDebugMode( |
| subsystem, |
| base::BindOnce(&NetworkLogsMessageHandler::OnSetShillDebuggingCompleted, |
| weak_factory_.GetWeakPtr(), callback_id)); |
| } |
| |
| void NetworkLogsMessageHandler::OnSetShillDebuggingCompleted( |
| const std::string& callback_id, |
| bool succeeded) { |
| Respond(callback_id, /*result=*/"", !succeeded); |
| } |
| |
| } // namespace ash |