| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/safe_browsing/srt_global_error_win.h" | |
| 6 | |
| 7 #include "base/base_paths.h" | |
| 8 #include "base/bind.h" | |
| 9 #include "base/bind_helpers.h" | |
| 10 #include "base/callback.h" | |
| 11 #include "base/command_line.h" | |
| 12 #include "base/files/file_path.h" | |
| 13 #include "base/files/file_util.h" | |
| 14 #include "base/path_service.h" | |
| 15 #include "base/process/launch.h" | |
| 16 #include "base/strings/string_number_conversions.h" | |
| 17 #include "base/task_scheduler/post_task.h" | |
| 18 #include "chrome/app/chrome_command_ids.h" | |
| 19 #include "chrome/browser/browser_process.h" | |
| 20 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" | |
| 21 #include "chrome/browser/safe_browsing/srt_client_info_win.h" | |
| 22 #include "chrome/browser/safe_browsing/srt_field_trial_win.h" | |
| 23 #include "chrome/browser/ui/browser.h" | |
| 24 #include "chrome/browser/ui/browser_finder.h" | |
| 25 #include "chrome/browser/ui/global_error/global_error_service.h" | |
| 26 #include "chrome/common/channel_info.h" | |
| 27 #include "chrome/grit/chromium_strings.h" | |
| 28 #include "chrome/grit/generated_resources.h" | |
| 29 #include "chrome/installer/util/install_util.h" | |
| 30 #include "components/chrome_cleaner/public/constants/constants.h" | |
| 31 #include "components/component_updater/pref_names.h" | |
| 32 #include "components/prefs/pref_service.h" | |
| 33 #include "components/version_info/version_info.h" | |
| 34 #include "ui/base/l10n/l10n_util.h" | |
| 35 | |
| 36 namespace safe_browsing { | |
| 37 | |
| 38 namespace { | |
| 39 | |
| 40 // Used as a backup plan in case the SRT executable was not successfully | |
| 41 // downloaded or run. | |
| 42 const char kSRTDownloadURL[] = | |
| 43 "https://www.google.com/chrome/srt/?chrome-prompt=1"; | |
| 44 | |
| 45 // The extension to use to replace the temporary one created when the SRT was | |
| 46 // downloaded. | |
| 47 const base::FilePath::CharType kExecutableExtension[] = L"exe"; | |
| 48 | |
| 49 bool MaybeExecuteSRTFromBlockingPool( | |
| 50 const base::FilePath& downloaded_path, | |
| 51 bool metrics_enabled, | |
| 52 bool sber_enabled, | |
| 53 chrome_cleaner::ChromePromptValue prompt_value) { | |
| 54 DCHECK(!downloaded_path.empty()); | |
| 55 | |
| 56 if (base::PathExists(downloaded_path)) { | |
| 57 base::FilePath executable_path( | |
| 58 downloaded_path.ReplaceExtension(kExecutableExtension)); | |
| 59 if (base::ReplaceFile(downloaded_path, executable_path, nullptr)) { | |
| 60 base::CommandLine srt_command_line(executable_path); | |
| 61 srt_command_line.AppendSwitchASCII( | |
| 62 chrome_cleaner::kChromePromptSwitch, | |
| 63 base::IntToString(static_cast<int>(prompt_value))); | |
| 64 srt_command_line.AppendSwitchASCII(chrome_cleaner::kChromeVersionSwitch, | |
| 65 version_info::GetVersionNumber()); | |
| 66 srt_command_line.AppendSwitchASCII(chrome_cleaner::kChromeChannelSwitch, | |
| 67 base::IntToString(ChannelAsInt())); | |
| 68 | |
| 69 base::FilePath chrome_exe_path; | |
| 70 PathService::Get(base::FILE_EXE, &chrome_exe_path); | |
| 71 srt_command_line.AppendSwitchPath(chrome_cleaner::kChromeExePathSwitch, | |
| 72 chrome_exe_path); | |
| 73 if (!InstallUtil::IsPerUserInstall()) | |
| 74 srt_command_line.AppendSwitch( | |
| 75 chrome_cleaner::kChromeSystemInstallSwitch); | |
| 76 | |
| 77 if (metrics_enabled) { | |
| 78 srt_command_line.AppendSwitch(chrome_cleaner::kUmaUserSwitch); | |
| 79 srt_command_line.AppendSwitch( | |
| 80 chrome_cleaner::kEnableCrashReportingSwitch); | |
| 81 } | |
| 82 | |
| 83 if (sber_enabled) | |
| 84 srt_command_line.AppendSwitch( | |
| 85 chrome_cleaner::kExtendedSafeBrowsingEnabledSwitch); | |
| 86 | |
| 87 base::Process srt_process( | |
| 88 base::LaunchProcess(srt_command_line, base::LaunchOptions())); | |
| 89 return srt_process.IsValid(); | |
| 90 } | |
| 91 } | |
| 92 return false; | |
| 93 } | |
| 94 | |
| 95 void DeleteFilesFromBlockingPool(const base::FilePath& downloaded_path) { | |
| 96 base::DeleteFile(downloaded_path, false); | |
| 97 base::DeleteFile(downloaded_path.ReplaceExtension(kExecutableExtension), | |
| 98 false); | |
| 99 } | |
| 100 | |
| 101 } // namespace | |
| 102 | |
| 103 // SRTGlobalError ------------------------------------------------------------ | |
| 104 | |
| 105 SRTGlobalError::SRTGlobalError(GlobalErrorService* global_error_service, | |
| 106 const base::FilePath& downloaded_path) | |
| 107 : global_error_service_(global_error_service), | |
| 108 downloaded_path_(downloaded_path) { | |
| 109 DCHECK(global_error_service_); | |
| 110 } | |
| 111 | |
| 112 SRTGlobalError::~SRTGlobalError() { | |
| 113 if (!interacted_) { | |
| 114 base::PostTaskWithTraits( | |
| 115 FROM_HERE, base::TaskTraits().MayBlock().WithPriority( | |
| 116 base::TaskPriority::BACKGROUND), | |
| 117 base::Bind(&DeleteFilesFromBlockingPool, downloaded_path_)); | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 bool SRTGlobalError::HasMenuItem() { | |
| 122 return true; | |
| 123 } | |
| 124 | |
| 125 int SRTGlobalError::MenuItemCommandID() { | |
| 126 return IDC_SHOW_SRT_BUBBLE; | |
| 127 } | |
| 128 | |
| 129 base::string16 SRTGlobalError::MenuItemLabel() { | |
| 130 return l10n_util::GetStringUTF16(IDS_SRT_MENU_ITEM); | |
| 131 } | |
| 132 | |
| 133 void SRTGlobalError::ExecuteMenuItem(Browser* browser) { | |
| 134 RecordSRTPromptHistogram(SRT_PROMPT_SHOWN_FROM_MENU); | |
| 135 bubble_shown_from_menu_ = true; | |
| 136 ShowBubbleView(browser); | |
| 137 } | |
| 138 | |
| 139 void SRTGlobalError::ShowBubbleView(Browser* browser) { | |
| 140 RecordSRTPromptHistogram(SRT_PROMPT_SHOWN); | |
| 141 GlobalErrorWithStandardBubble::ShowBubbleView(browser); | |
| 142 } | |
| 143 | |
| 144 bool SRTGlobalError::ShouldShowCloseButton() const { | |
| 145 return true; | |
| 146 } | |
| 147 | |
| 148 base::string16 SRTGlobalError::GetBubbleViewTitle() { | |
| 149 return l10n_util::GetStringUTF16(IDS_SRT_BUBBLE_TITLE); | |
| 150 } | |
| 151 | |
| 152 std::vector<base::string16> SRTGlobalError::GetBubbleViewMessages() { | |
| 153 std::vector<base::string16> messages; | |
| 154 messages.push_back(l10n_util::GetStringUTF16(IDS_SRT_BUBBLE_TEXT)); | |
| 155 return messages; | |
| 156 } | |
| 157 | |
| 158 base::string16 SRTGlobalError::GetBubbleViewAcceptButtonLabel() { | |
| 159 return downloaded_path_.empty() | |
| 160 ? l10n_util::GetStringUTF16(IDS_SRT_BUBBLE_DOWNLOAD_BUTTON_TEXT) | |
| 161 : l10n_util::GetStringUTF16(IDS_SRT_BUBBLE_RUN_BUTTON_TEXT); | |
| 162 } | |
| 163 | |
| 164 bool SRTGlobalError::ShouldAddElevationIconToAcceptButton() { | |
| 165 return !downloaded_path_.empty() && SRTPromptNeedsElevationIcon(); | |
| 166 } | |
| 167 | |
| 168 base::string16 SRTGlobalError::GetBubbleViewCancelButtonLabel() { | |
| 169 // Show the dismiss button only if the bubble was shown from the menu. | |
| 170 return bubble_shown_from_menu_ | |
| 171 ? l10n_util::GetStringUTF16(IDS_SRT_BUBBLE_DISMISS) | |
| 172 : base::string16(); | |
| 173 } | |
| 174 | |
| 175 void SRTGlobalError::OnBubbleViewDidClose(Browser* browser) { | |
| 176 if (!interacted_) { | |
| 177 // If user didn't interact with the bubble, it means they used the generic | |
| 178 // close bubble button. | |
| 179 RecordSRTPromptHistogram(SRT_PROMPT_CLOSED); | |
| 180 g_browser_process->local_state()->SetBoolean( | |
| 181 prefs::kSwReporterPendingPrompt, true); | |
| 182 } | |
| 183 } | |
| 184 | |
| 185 void SRTGlobalError::BubbleViewAcceptButtonPressed(Browser* browser) { | |
| 186 OnUserinteractionStarted(SRT_PROMPT_ACCEPTED); | |
| 187 MaybeExecuteSRT(); | |
| 188 } | |
| 189 | |
| 190 void SRTGlobalError::BubbleViewCancelButtonPressed(Browser* browser) { | |
| 191 OnUserinteractionStarted(SRT_PROMPT_DENIED); | |
| 192 base::PostTaskWithTraits( | |
| 193 FROM_HERE, base::TaskTraits().MayBlock().WithPriority( | |
| 194 base::TaskPriority::BACKGROUND), | |
| 195 base::Bind(&DeleteFilesFromBlockingPool, downloaded_path_)); | |
| 196 OnUserinteractionDone(); | |
| 197 } | |
| 198 | |
| 199 bool SRTGlobalError::ShouldCloseOnDeactivate() const { | |
| 200 return false; | |
| 201 } | |
| 202 | |
| 203 void SRTGlobalError::MaybeExecuteSRT() { | |
| 204 if (downloaded_path_.empty()) { | |
| 205 FallbackToDownloadPage(); | |
| 206 return; | |
| 207 } | |
| 208 // At this point, this object owns itself, since ownership has been taken back | |
| 209 // from the global_error_service_ in the call to OnUserInteractionStarted. | |
| 210 // This means that it is safe to use base::Unretained here. | |
| 211 base::PostTaskWithTraitsAndReplyWithResult( | |
| 212 FROM_HERE, | |
| 213 base::TaskTraits().MayBlock().WithPriority( | |
| 214 base::TaskPriority::BACKGROUND), | |
| 215 base::Bind( | |
| 216 &MaybeExecuteSRTFromBlockingPool, downloaded_path_, | |
| 217 ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled(), | |
| 218 SafeBrowsingExtendedReportingEnabled(), | |
| 219 bubble_shown_from_menu_ | |
| 220 ? chrome_cleaner::ChromePromptValue::kShownFromMenu | |
| 221 : chrome_cleaner::ChromePromptValue::kPrompted), | |
| 222 base::Bind( | |
| 223 [](SRTGlobalError* self, bool success) { | |
| 224 if (success) | |
| 225 self->OnUserinteractionDone(); | |
| 226 else | |
| 227 self->FallbackToDownloadPage(); | |
| 228 }, | |
| 229 base::Unretained(this))); | |
| 230 } | |
| 231 | |
| 232 void SRTGlobalError::FallbackToDownloadPage() { | |
| 233 RecordSRTPromptHistogram(SRT_PROMPT_FALLBACK); | |
| 234 | |
| 235 Browser* browser = chrome::FindLastActive(); | |
| 236 if (browser) { | |
| 237 browser->OpenURL( | |
| 238 content::OpenURLParams(GURL(kSRTDownloadURL), content::Referrer(), | |
| 239 WindowOpenDisposition::NEW_FOREGROUND_TAB, | |
| 240 ui::PAGE_TRANSITION_LINK, false)); | |
| 241 } | |
| 242 | |
| 243 base::PostTaskWithTraits( | |
| 244 FROM_HERE, base::TaskTraits().MayBlock().WithPriority( | |
| 245 base::TaskPriority::BACKGROUND), | |
| 246 base::Bind(&DeleteFilesFromBlockingPool, downloaded_path_)); | |
| 247 OnUserinteractionDone(); | |
| 248 } | |
| 249 | |
| 250 void SRTGlobalError::OnUserinteractionStarted( | |
| 251 SRTPromptHistogramValue histogram_value) { | |
| 252 // This is for cases where the UI doesn't go away quickly enough and user | |
| 253 // might click on the button more than once, or more than one button. | |
| 254 if (interacted_) | |
| 255 return; | |
| 256 RecordSRTPromptHistogram(histogram_value); | |
| 257 interacted_ = true; | |
| 258 if (global_error_service_) { | |
| 259 global_error_service_->RemoveGlobalError(this).release(); | |
| 260 global_error_service_ = nullptr; | |
| 261 } | |
| 262 } | |
| 263 | |
| 264 void SRTGlobalError::OnUserinteractionDone() { | |
| 265 DCHECK(interacted_); | |
| 266 // Once the user interacted with the bubble, we can forget about any pending | |
| 267 // prompt. | |
| 268 g_browser_process->local_state()->SetBoolean(prefs::kSwReporterPendingPrompt, | |
| 269 false); | |
| 270 delete this; | |
| 271 } | |
| 272 | |
| 273 } // namespace safe_browsing | |
| OLD | NEW |