Home | History | Annotate | Download | only in download
      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