|  | // Copyright (c) 2017 The Chromium Authors. All rights reserved. | 
|  | // 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/settings/chrome_cleanup_handler.h" | 
|  |  | 
|  | #include <memory> | 
|  | #include <string> | 
|  | #include <utility> | 
|  |  | 
|  | #include "base/command_line.h" | 
|  | #include "base/feature_list.h" | 
|  | #include "base/metrics/histogram_macros.h" | 
|  | #include "base/metrics/user_metrics.h" | 
|  | #include "base/metrics/user_metrics_action.h" | 
|  | #include "base/strings/string16.h" | 
|  | #include "base/synchronization/lock.h" | 
|  | #include "base/values.h" | 
|  | #include "build/build_config.h" | 
|  | #include "chrome/browser/browser_process.h" | 
|  | #include "chrome/browser/extensions/extension_service.h" | 
|  | #include "chrome/browser/profiles/profile.h" | 
|  | #include "chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.h" | 
|  | #include "chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.h" | 
|  | #include "chrome/grit/generated_resources.h" | 
|  | #include "components/component_updater/pref_names.h" | 
|  | #include "components/prefs/pref_service.h" | 
|  | #include "content/public/browser/web_contents.h" | 
|  | #include "content/public/browser/web_ui.h" | 
|  | #include "content/public/browser/web_ui_message_handler.h" | 
|  | #include "extensions/browser/extension_system.h" | 
|  | #include "ui/base/l10n/l10n_util.h" | 
|  |  | 
|  | using safe_browsing::ChromeCleanerController; | 
|  |  | 
|  | namespace settings { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Returns a ListValue containing a copy of the file paths stored in |files|. | 
|  | std::unique_ptr<base::ListValue> GetFilesAsListStorage( | 
|  | const std::set<base::FilePath>& files) { | 
|  | auto value = std::make_unique<base::ListValue>(); | 
|  | for (const base::FilePath& path : files) { | 
|  | auto item = std::make_unique<base::DictionaryValue>(); | 
|  | item->SetString("dirname", path.DirName().AsEndingWithSeparator().value()); | 
|  | item->SetString("basename", path.BaseName().value()); | 
|  | value->Append(std::move(item)); | 
|  | } | 
|  | return value; | 
|  | } | 
|  |  | 
|  | // Returns a ListValue containing a copy of the strings stored in |string_set|. | 
|  | std::unique_ptr<base::ListValue> GetStringSetAsListStorage( | 
|  | const std::set<base::string16>& string_set) { | 
|  | auto value = std::make_unique<base::ListValue>(); | 
|  | for (const base::string16& string : string_set) | 
|  | value->AppendString(string); | 
|  |  | 
|  | return value; | 
|  | } | 
|  |  | 
|  | base::DictionaryValue GetScannerResultsAsDictionary( | 
|  | const safe_browsing::ChromeCleanerScannerResults& scanner_results, | 
|  | Profile* profile) { | 
|  | base::DictionaryValue value; | 
|  | value.SetList("files", | 
|  | GetFilesAsListStorage(scanner_results.files_to_delete())); | 
|  | value.SetList("registryKeys", | 
|  | GetStringSetAsListStorage(scanner_results.registry_keys())); | 
|  | std::set<base::string16> extensions; | 
|  | scanner_results.FetchExtensionNames(profile, &extensions); | 
|  | value.SetList("extensions", GetStringSetAsListStorage(extensions)); | 
|  | return value; | 
|  | } | 
|  |  | 
|  | std::string IdleReasonToString( | 
|  | ChromeCleanerController::IdleReason idle_reason) { | 
|  | switch (idle_reason) { | 
|  | case ChromeCleanerController::IdleReason::kInitial: | 
|  | return "initial"; | 
|  | case ChromeCleanerController::IdleReason::kReporterFoundNothing: | 
|  | return "reporter_found_nothing"; | 
|  | case ChromeCleanerController::IdleReason::kReporterFailed: | 
|  | return "reporter_failed"; | 
|  | case ChromeCleanerController::IdleReason::kScanningFoundNothing: | 
|  | return "scanning_found_nothing"; | 
|  | case ChromeCleanerController::IdleReason::kScanningFailed: | 
|  | return "scanning_failed"; | 
|  | case ChromeCleanerController::IdleReason::kConnectionLost: | 
|  | return "connection_lost"; | 
|  | case ChromeCleanerController::IdleReason::kUserDeclinedCleanup: | 
|  | return "user_declined_cleanup"; | 
|  | case ChromeCleanerController::IdleReason::kCleaningFailed: | 
|  | return "cleaning_failed"; | 
|  | case ChromeCleanerController::IdleReason::kCleaningSucceeded: | 
|  | return "cleaning_succeeded"; | 
|  | case ChromeCleanerController::IdleReason::kCleanerDownloadFailed: | 
|  | return "cleaner_download_failed"; | 
|  | } | 
|  | NOTREACHED(); | 
|  | return ""; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | ChromeCleanupHandler::ChromeCleanupHandler(Profile* profile) | 
|  | : controller_(ChromeCleanerController::GetInstance()), profile_(profile) {} | 
|  |  | 
|  | ChromeCleanupHandler::~ChromeCleanupHandler() { | 
|  | controller_->RemoveObserver(this); | 
|  | } | 
|  |  | 
|  | void ChromeCleanupHandler::RegisterMessages() { | 
|  | web_ui()->RegisterMessageCallback( | 
|  | "registerChromeCleanerObserver", | 
|  | base::BindRepeating( | 
|  | &ChromeCleanupHandler::HandleRegisterChromeCleanerObserver, | 
|  | base::Unretained(this))); | 
|  | web_ui()->RegisterMessageCallback( | 
|  | "startScanning", | 
|  | base::BindRepeating(&ChromeCleanupHandler::HandleStartScanning, | 
|  | base::Unretained(this))); | 
|  | web_ui()->RegisterMessageCallback( | 
|  | "restartComputer", | 
|  | base::BindRepeating(&ChromeCleanupHandler::HandleRestartComputer, | 
|  | base::Unretained(this))); | 
|  | web_ui()->RegisterMessageCallback( | 
|  | "startCleanup", | 
|  | base::BindRepeating(&ChromeCleanupHandler::HandleStartCleanup, | 
|  | base::Unretained(this))); | 
|  | web_ui()->RegisterMessageCallback( | 
|  | "notifyShowDetails", | 
|  | base::BindRepeating(&ChromeCleanupHandler::HandleNotifyShowDetails, | 
|  | base::Unretained(this))); | 
|  | web_ui()->RegisterMessageCallback( | 
|  | "notifyChromeCleanupLearnMoreClicked", | 
|  | base::BindRepeating( | 
|  | &ChromeCleanupHandler::HandleNotifyChromeCleanupLearnMoreClicked, | 
|  | base::Unretained(this))); | 
|  | web_ui()->RegisterMessageCallback( | 
|  | "getMoreItemsPluralString", | 
|  | base::BindRepeating(&ChromeCleanupHandler::HandleGetMoreItemsPluralString, | 
|  | base::Unretained(this))); | 
|  | web_ui()->RegisterMessageCallback( | 
|  | "getItemsToRemovePluralString", | 
|  | base::BindRepeating( | 
|  | &ChromeCleanupHandler::HandleGetItemsToRemovePluralString, | 
|  | base::Unretained(this))); | 
|  | } | 
|  |  | 
|  | void ChromeCleanupHandler::OnJavascriptAllowed() { | 
|  | controller_->AddObserver(this); | 
|  | } | 
|  |  | 
|  | void ChromeCleanupHandler::OnJavascriptDisallowed() { | 
|  | controller_->RemoveObserver(this); | 
|  | } | 
|  |  | 
|  | void ChromeCleanupHandler::OnIdle( | 
|  | ChromeCleanerController::IdleReason idle_reason) { | 
|  | FireWebUIListener("chrome-cleanup-on-idle", | 
|  | base::Value(IdleReasonToString(idle_reason))); | 
|  | } | 
|  |  | 
|  | void ChromeCleanupHandler::OnScanning() { | 
|  | FireWebUIListener("chrome-cleanup-on-scanning"); | 
|  | } | 
|  |  | 
|  | void ChromeCleanupHandler::OnReporterRunning() { | 
|  | FireWebUIListener("chrome-cleanup-on-reporter-running"); | 
|  | } | 
|  |  | 
|  | void ChromeCleanupHandler::OnInfected( | 
|  | bool is_powered_by_partner, | 
|  | const safe_browsing::ChromeCleanerScannerResults& scanner_results) { | 
|  | FireWebUIListener("chrome-cleanup-on-infected", | 
|  | base::Value(is_powered_by_partner), | 
|  | GetScannerResultsAsDictionary(scanner_results, profile_)); | 
|  | } | 
|  |  | 
|  | void ChromeCleanupHandler::OnCleaning( | 
|  | bool is_powered_by_partner, | 
|  | const safe_browsing::ChromeCleanerScannerResults& scanner_results) { | 
|  | FireWebUIListener("chrome-cleanup-on-cleaning", | 
|  | base::Value(is_powered_by_partner), | 
|  | GetScannerResultsAsDictionary(scanner_results, profile_)); | 
|  | } | 
|  |  | 
|  | void ChromeCleanupHandler::OnRebootRequired() { | 
|  | FireWebUIListener("chrome-cleanup-on-reboot-required"); | 
|  | } | 
|  |  | 
|  | void ChromeCleanupHandler::HandleRegisterChromeCleanerObserver( | 
|  | const base::ListValue* args) { | 
|  | DCHECK_EQ(0U, args->GetSize()); | 
|  |  | 
|  | UMA_HISTOGRAM_BOOLEAN("SoftwareReporter.CleanupCard", true); | 
|  | base::RecordAction( | 
|  | base::UserMetricsAction("SoftwareReporter.CleanupWebui_Shown")); | 
|  | AllowJavascript(); | 
|  |  | 
|  | FireWebUIListener("chrome-cleanup-enabled-change", | 
|  | base::Value(controller_->IsAllowedByPolicy())); | 
|  | } | 
|  |  | 
|  | void ChromeCleanupHandler::HandleStartScanning(const base::ListValue* args) { | 
|  | CHECK_EQ(1U, args->GetSize()); | 
|  | bool allow_logs_upload = false; | 
|  | args->GetBoolean(0, &allow_logs_upload); | 
|  |  | 
|  | // If this operation is not allowed the UI should be disabled. | 
|  | CHECK(controller_->IsAllowedByPolicy()); | 
|  |  | 
|  | // The state is propagated to all open tabs and should be consistent. | 
|  | DCHECK_EQ(controller_->logs_enabled(profile_), allow_logs_upload); | 
|  |  | 
|  | controller_->RequestUserInitiatedScan(profile_); | 
|  |  | 
|  | base::RecordAction( | 
|  | base::UserMetricsAction("SoftwareReporter.CleanupWebui_StartScanning")); | 
|  | } | 
|  |  | 
|  | void ChromeCleanupHandler::HandleRestartComputer(const base::ListValue* args) { | 
|  | DCHECK_EQ(0U, args->GetSize()); | 
|  |  | 
|  | base::RecordAction( | 
|  | base::UserMetricsAction("SoftwareReporter.CleanupWebui_RestartComputer")); | 
|  |  | 
|  | controller_->Reboot(); | 
|  | } | 
|  |  | 
|  | void ChromeCleanupHandler::HandleStartCleanup(const base::ListValue* args) { | 
|  | CHECK_EQ(1U, args->GetSize()); | 
|  | bool allow_logs_upload = false; | 
|  | args->GetBoolean(0, &allow_logs_upload); | 
|  |  | 
|  | // The state is propagated to all open tabs and should be consistent. | 
|  | DCHECK_EQ(controller_->logs_enabled(profile_), allow_logs_upload); | 
|  |  | 
|  | safe_browsing::RecordCleanupStartedHistogram( | 
|  | safe_browsing::CLEANUP_STARTED_FROM_PROMPT_IN_SETTINGS); | 
|  | base::RecordAction( | 
|  | base::UserMetricsAction("SoftwareReporter.CleanupWebui_StartCleanup")); | 
|  |  | 
|  | extensions::ExtensionService* extension_service = | 
|  | extensions::ExtensionSystem::Get(profile_)->extension_service(); | 
|  |  | 
|  | controller_->ReplyWithUserResponse( | 
|  | profile_, extension_service, | 
|  | allow_logs_upload | 
|  | ? ChromeCleanerController::UserResponse::kAcceptedWithLogs | 
|  | : ChromeCleanerController::UserResponse::kAcceptedWithoutLogs); | 
|  | } | 
|  |  | 
|  | void ChromeCleanupHandler::HandleNotifyShowDetails( | 
|  | const base::ListValue* args) { | 
|  | CHECK_EQ(1U, args->GetSize()); | 
|  | bool details_section_visible = false; | 
|  | args->GetBoolean(0, &details_section_visible); | 
|  |  | 
|  | if (details_section_visible) { | 
|  | base::RecordAction( | 
|  | base::UserMetricsAction("SoftwareReporter.CleanupWebui_ShowDetails")); | 
|  | } else { | 
|  | base::RecordAction( | 
|  | base::UserMetricsAction("SoftwareReporter.CleanupWebui_HideDetails")); | 
|  | } | 
|  | } | 
|  |  | 
|  | void ChromeCleanupHandler::HandleNotifyChromeCleanupLearnMoreClicked( | 
|  | const base::ListValue* args) { | 
|  | CHECK_EQ(0U, args->GetSize()); | 
|  |  | 
|  | base::RecordAction( | 
|  | base::UserMetricsAction("SoftwareReporter.CleanupWebui_LearnMore")); | 
|  | } | 
|  |  | 
|  | void ChromeCleanupHandler::HandleGetMoreItemsPluralString( | 
|  | const base::ListValue* args) { | 
|  | #if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD) | 
|  | GetPluralString(IDS_SETTINGS_RESET_CLEANUP_DETAILS_MORE, args); | 
|  | #endif  // defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD) | 
|  | } | 
|  |  | 
|  | void ChromeCleanupHandler::HandleGetItemsToRemovePluralString( | 
|  | const base::ListValue* args) { | 
|  | #if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD) | 
|  | GetPluralString(IDS_SETTINGS_RESET_CLEANUP_DETAILS_ITEMS_TO_BE_REMOVED, args); | 
|  | #endif  // defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD) | 
|  | } | 
|  |  | 
|  | void ChromeCleanupHandler::GetPluralString(int id, | 
|  | const base::ListValue* args) { | 
|  | CHECK_EQ(2U, args->GetSize()); | 
|  |  | 
|  | std::string callback_id; | 
|  | CHECK(args->GetString(0, &callback_id)); | 
|  |  | 
|  | int num_items = 0; | 
|  | args->GetInteger(1, &num_items); | 
|  |  | 
|  | const base::string16 plural_string = | 
|  | num_items > 0 ? l10n_util::GetPluralStringFUTF16(id, num_items) | 
|  | : base::string16(); | 
|  | ResolveJavascriptCallback(base::Value(callback_id), | 
|  | base::Value(plural_string)); | 
|  | } | 
|  |  | 
|  | }  // namespace settings |