1 // Copyright (c) 2012 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/download/download_danger_prompt.h" 6 7 #include "base/bind.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "chrome/browser/chrome_notification_types.h" 10 #include "chrome/browser/download/chrome_download_manager_delegate.h" 11 #include "chrome/browser/download/download_stats.h" 12 #include "chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h" 13 #include "chrome/browser/ui/tab_modal_confirm_dialog.h" 14 #include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h" 15 #include "chrome/grit/chromium_strings.h" 16 #include "chrome/grit/generated_resources.h" 17 #include "content/public/browser/download_danger_type.h" 18 #include "content/public/browser/download_item.h" 19 #include "ui/base/l10n/l10n_util.h" 20 21 using extensions::ExperienceSamplingEvent; 22 23 namespace { 24 25 // TODO(wittman): Create a native web contents modal dialog implementation of 26 // this dialog for non-Views platforms, to support bold formatting of the 27 // message lead. 28 29 // Implements DownloadDangerPrompt using a TabModalConfirmDialog. 30 class DownloadDangerPromptImpl : public DownloadDangerPrompt, 31 public content::DownloadItem::Observer, 32 public TabModalConfirmDialogDelegate { 33 public: 34 DownloadDangerPromptImpl(content::DownloadItem* item, 35 content::WebContents* web_contents, 36 bool show_context, 37 const OnDone& done); 38 virtual ~DownloadDangerPromptImpl(); 39 40 // DownloadDangerPrompt: 41 virtual void InvokeActionForTesting(Action action) OVERRIDE; 42 43 private: 44 // content::DownloadItem::Observer: 45 virtual void OnDownloadUpdated(content::DownloadItem* download) OVERRIDE; 46 47 // TabModalConfirmDialogDelegate: 48 virtual base::string16 GetTitle() OVERRIDE; 49 virtual base::string16 GetDialogMessage() OVERRIDE; 50 virtual base::string16 GetAcceptButtonTitle() OVERRIDE; 51 virtual base::string16 GetCancelButtonTitle() OVERRIDE; 52 virtual void OnAccepted() OVERRIDE; 53 virtual void OnCanceled() OVERRIDE; 54 virtual void OnClosed() OVERRIDE; 55 56 void RunDone(Action action); 57 58 content::DownloadItem* download_; 59 bool show_context_; 60 OnDone done_; 61 62 scoped_ptr<ExperienceSamplingEvent> sampling_event_; 63 64 DISALLOW_COPY_AND_ASSIGN(DownloadDangerPromptImpl); 65 }; 66 67 DownloadDangerPromptImpl::DownloadDangerPromptImpl( 68 content::DownloadItem* download, 69 content::WebContents* web_contents, 70 bool show_context, 71 const OnDone& done) 72 : TabModalConfirmDialogDelegate(web_contents), 73 download_(download), 74 show_context_(show_context), 75 done_(done) { 76 DCHECK(!done_.is_null()); 77 download_->AddObserver(this); 78 RecordOpenedDangerousConfirmDialog(download_->GetDangerType()); 79 80 // ExperienceSampling: A malicious download warning is being shown to the 81 // user, so we start a new SamplingEvent and track it. 82 sampling_event_.reset(new ExperienceSamplingEvent( 83 ExperienceSamplingEvent::kDownloadDangerPrompt, 84 download->GetURL(), 85 download->GetReferrerUrl(), 86 download->GetBrowserContext())); 87 } 88 89 DownloadDangerPromptImpl::~DownloadDangerPromptImpl() { 90 // |this| might be deleted without invoking any callbacks. E.g. pressing Esc 91 // on GTK or if the user navigates away from the page showing the prompt. 92 RunDone(DISMISS); 93 } 94 95 void DownloadDangerPromptImpl::InvokeActionForTesting(Action action) { 96 switch (action) { 97 case ACCEPT: Accept(); break; 98 case CANCEL: Cancel(); break; 99 case DISMISS: 100 RunDone(DISMISS); 101 Cancel(); 102 break; 103 } 104 } 105 106 void DownloadDangerPromptImpl::OnDownloadUpdated( 107 content::DownloadItem* download) { 108 // If the download is nolonger dangerous (accepted externally) or the download 109 // is in a terminal state, then the download danger prompt is no longer 110 // necessary. 111 if (!download->IsDangerous() || download->IsDone()) { 112 RunDone(DISMISS); 113 Cancel(); 114 } 115 } 116 117 base::string16 DownloadDangerPromptImpl::GetTitle() { 118 if (show_context_) 119 return l10n_util::GetStringUTF16(IDS_CONFIRM_KEEP_DANGEROUS_DOWNLOAD_TITLE); 120 switch (download_->GetDangerType()) { 121 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: 122 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: 123 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: 124 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: { 125 return l10n_util::GetStringUTF16( 126 IDS_RESTORE_KEEP_DANGEROUS_DOWNLOAD_TITLE); 127 } 128 default: { 129 return l10n_util::GetStringUTF16( 130 IDS_CONFIRM_KEEP_DANGEROUS_DOWNLOAD_TITLE); 131 } 132 } 133 } 134 135 base::string16 DownloadDangerPromptImpl::GetDialogMessage() { 136 if (show_context_) { 137 switch (download_->GetDangerType()) { 138 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: { 139 return l10n_util::GetStringFUTF16( 140 IDS_PROMPT_DANGEROUS_DOWNLOAD, 141 download_->GetFileNameToReportUser().LossyDisplayName()); 142 } 143 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: // Fall through 144 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: 145 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: { 146 return l10n_util::GetStringFUTF16( 147 IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT, 148 download_->GetFileNameToReportUser().LossyDisplayName()); 149 } 150 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: { 151 return l10n_util::GetStringFUTF16( 152 IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT, 153 download_->GetFileNameToReportUser().LossyDisplayName()); 154 } 155 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: { 156 return l10n_util::GetStringFUTF16( 157 IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS, 158 download_->GetFileNameToReportUser().LossyDisplayName()); 159 } 160 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS: 161 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT: 162 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED: 163 case content::DOWNLOAD_DANGER_TYPE_MAX: { 164 break; 165 } 166 } 167 } else { 168 switch (download_->GetDangerType()) { 169 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: 170 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: 171 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: { 172 return l10n_util::GetStringUTF16( 173 IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_LEAD) + 174 base::ASCIIToUTF16("\n\n") + 175 l10n_util::GetStringUTF16( 176 IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_BODY); 177 } 178 default: { 179 return l10n_util::GetStringUTF16( 180 IDS_PROMPT_CONFIRM_KEEP_DANGEROUS_DOWNLOAD); 181 } 182 } 183 } 184 NOTREACHED(); 185 return base::string16(); 186 } 187 188 base::string16 DownloadDangerPromptImpl::GetAcceptButtonTitle() { 189 if (show_context_) 190 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD); 191 switch (download_->GetDangerType()) { 192 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: 193 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: 194 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: 195 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: { 196 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD_AGAIN_MALICIOUS); 197 } 198 default: 199 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD_AGAIN); 200 } 201 } 202 203 base::string16 DownloadDangerPromptImpl::GetCancelButtonTitle() { 204 if (show_context_) 205 return l10n_util::GetStringUTF16(IDS_CANCEL); 206 switch (download_->GetDangerType()) { 207 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: 208 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: 209 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: 210 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: { 211 return l10n_util::GetStringUTF16(IDS_CONFIRM_CANCEL_AGAIN_MALICIOUS); 212 } 213 default: 214 return l10n_util::GetStringUTF16(IDS_CANCEL); 215 } 216 } 217 218 void DownloadDangerPromptImpl::OnAccepted() { 219 // ExperienceSampling: User proceeded through the warning. 220 sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed); 221 RunDone(ACCEPT); 222 } 223 224 void DownloadDangerPromptImpl::OnCanceled() { 225 // ExperienceSampling: User canceled the warning. 226 sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny); 227 RunDone(CANCEL); 228 } 229 230 void DownloadDangerPromptImpl::OnClosed() { 231 // ExperienceSampling: User canceled the warning. 232 sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny); 233 RunDone(DISMISS); 234 } 235 236 void DownloadDangerPromptImpl::RunDone(Action action) { 237 // Invoking the callback can cause the download item state to change or cause 238 // the constrained window to close, and |callback| refers to a member 239 // variable. 240 OnDone done = done_; 241 done_.Reset(); 242 if (download_ != NULL) { 243 download_->RemoveObserver(this); 244 download_ = NULL; 245 } 246 if (!done.is_null()) 247 done.Run(action); 248 } 249 250 } // namespace 251 252 #if !defined(USE_AURA) 253 // static 254 DownloadDangerPrompt* DownloadDangerPrompt::Create( 255 content::DownloadItem* item, 256 content::WebContents* web_contents, 257 bool show_context, 258 const OnDone& done) { 259 DownloadDangerPromptImpl* prompt = new DownloadDangerPromptImpl( 260 item, web_contents, show_context, done); 261 // |prompt| will be deleted when the dialog is done. 262 TabModalConfirmDialog::Create(prompt, web_contents); 263 return prompt; 264 } 265 #endif 266