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_item_model.h"
6 
7 #include "base/bind.h"
8 #include "base/i18n/number_formatting.h"
9 #include "base/i18n/rtl.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/metrics/field_trial.h"
12 #include "base/strings/string16.h"
13 #include "base/strings/sys_string_conversions.h"
14 #include "base/supports_user_data.h"
15 #include "base/time/time.h"
16 #include "build/build_config.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/download/chrome_download_manager_delegate.h"
19 #include "chrome/browser/download/download_commands.h"
20 #include "chrome/browser/download/download_core_service.h"
21 #include "chrome/browser/download/download_core_service_factory.h"
22 #include "chrome/browser/download/download_crx_util.h"
23 #include "chrome/browser/download/download_history.h"
24 #include "chrome/browser/download/download_prefs.h"
25 #include "chrome/browser/download/download_stats.h"
26 #include "chrome/browser/download/offline_item_utils.h"
27 #include "chrome/browser/enterprise/connectors/common.h"
28 #include "chrome/browser/enterprise/connectors/connectors_manager.h"
29 #include "chrome/browser/profiles/profile.h"
30 #include "chrome/browser/safe_browsing/download_protection/deep_scanning_request.h"
31 #include "chrome/browser/safe_browsing/download_protection/download_feedback_service.h"
32 #include "chrome/grit/chromium_strings.h"
33 #include "chrome/grit/generated_resources.h"
34 #include "components/download/public/common/download_danger_type.h"
35 #include "components/download/public/common/download_interrupt_reasons.h"
36 #include "components/download/public/common/download_item.h"
37 #include "components/safe_browsing/buildflags.h"
38 #include "components/safe_browsing/core/file_type_policies.h"
39 #include "components/safe_browsing/core/proto/download_file_types.pb.h"
40 #include "content/public/browser/download_item_utils.h"
41 #include "ui/base/l10n/l10n_util.h"
42 #include "ui/base/l10n/time_format.h"
43 #include "ui/base/text/bytes_formatting.h"
44 
45 #if !defined(OS_ANDROID)
46 #include "chrome/browser/ui/browser.h"
47 #endif
48 
49 using base::TimeDelta;
50 using download::DownloadItem;
51 using MixedContentStatus = download::DownloadItem::MixedContentStatus;
52 using safe_browsing::DownloadFileType;
53 
54 namespace {
55 
56 // Per DownloadItem data used by DownloadItemModel. The model doesn't keep any
57 // state since there could be multiple models associated with a single
58 // DownloadItem, and the lifetime of the model is shorter than the DownloadItem.
59 class DownloadItemModelData : public base::SupportsUserData::Data {
60  public:
~DownloadItemModelData()61   ~DownloadItemModelData() override {}
62 
63   // Get the DownloadItemModelData object for |download|. Returns NULL if
64   // there's no model data.
65   static const DownloadItemModelData* Get(const DownloadItem* download);
66 
67   // Get the DownloadItemModelData object for |download|. Creates a model data
68   // object if not found. Always returns a non-NULL pointer, unless OOM.
69   static DownloadItemModelData* GetOrCreate(DownloadItem* download);
70 
71   // Whether the download should be displayed in the download shelf. True by
72   // default.
73   bool should_show_in_shelf_;
74 
75   // Whether the UI has been notified about this download.
76   bool was_ui_notified_;
77 
78   // Whether the download should be opened in the browser vs. the system handler
79   // for the file type.
80   bool should_prefer_opening_in_browser_;
81 
82   // Danger level of the file determined based on the file type and whether
83   // there was a user action associated with the download.
84   DownloadFileType::DangerLevel danger_level_;
85 
86   // Whether the download is currently being revived.
87   bool is_being_revived_;
88 
89  private:
90   DownloadItemModelData();
91 
92   static const char kKey[];
93 };
94 
95 // static
96 const char DownloadItemModelData::kKey[] = "DownloadItemModelData key";
97 
98 // static
Get(const DownloadItem * download)99 const DownloadItemModelData* DownloadItemModelData::Get(
100     const DownloadItem* download) {
101   return static_cast<const DownloadItemModelData*>(download->GetUserData(kKey));
102 }
103 
104 // static
GetOrCreate(DownloadItem * download)105 DownloadItemModelData* DownloadItemModelData::GetOrCreate(
106     DownloadItem* download) {
107   DownloadItemModelData* data =
108       static_cast<DownloadItemModelData*>(download->GetUserData(kKey));
109   if (data == NULL) {
110     data = new DownloadItemModelData();
111     data->should_show_in_shelf_ = !download->IsTransient();
112     download->SetUserData(kKey, base::WrapUnique(data));
113   }
114   return data;
115 }
116 
DownloadItemModelData()117 DownloadItemModelData::DownloadItemModelData()
118     : should_show_in_shelf_(true),
119       was_ui_notified_(false),
120       should_prefer_opening_in_browser_(false),
121       danger_level_(DownloadFileType::NOT_DANGEROUS),
122       is_being_revived_(false) {}
123 
124 } // namespace
125 
126 // -----------------------------------------------------------------------------
127 // DownloadItemModel
128 
129 // static
Wrap(download::DownloadItem * download)130 DownloadUIModel::DownloadUIModelPtr DownloadItemModel::Wrap(
131     download::DownloadItem* download) {
132   DownloadUIModel::DownloadUIModelPtr model(
133       new DownloadItemModel(download),
134       base::OnTaskRunnerDeleter(base::ThreadTaskRunnerHandle::Get()));
135   return model;
136 }
137 
DownloadItemModel(DownloadItem * download)138 DownloadItemModel::DownloadItemModel(DownloadItem* download)
139     : download_(download) {
140   download_->AddObserver(this);
141 }
142 
~DownloadItemModel()143 DownloadItemModel::~DownloadItemModel() {
144   if (download_)
145     download_->RemoveObserver(this);
146 }
147 
GetContentId() const148 ContentId DownloadItemModel::GetContentId() const {
149   bool off_the_record = content::DownloadItemUtils::GetBrowserContext(download_)
150                             ->IsOffTheRecord();
151   return ContentId(OfflineItemUtils::GetDownloadNamespacePrefix(off_the_record),
152                    download_->GetGuid());
153 }
154 
profile() const155 Profile* DownloadItemModel::profile() const {
156   return Profile::FromBrowserContext(
157       content::DownloadItemUtils::GetBrowserContext(download_));
158 }
159 
GetTabProgressStatusText() const160 base::string16 DownloadItemModel::GetTabProgressStatusText() const {
161   int64_t total = GetTotalBytes();
162   int64_t size = download_->GetReceivedBytes();
163   base::string16 received_size = ui::FormatBytes(size);
164   base::string16 amount = received_size;
165 
166   // Adjust both strings for the locale direction since we don't yet know which
167   // string we'll end up using for constructing the final progress string.
168   base::i18n::AdjustStringForLocaleDirection(&amount);
169 
170   if (total) {
171     base::string16 total_text = ui::FormatBytes(total);
172     base::i18n::AdjustStringForLocaleDirection(&total_text);
173 
174     base::i18n::AdjustStringForLocaleDirection(&received_size);
175     amount = l10n_util::GetStringFUTF16(
176         IDS_DOWNLOAD_TAB_PROGRESS_SIZE, received_size, total_text);
177   } else {
178     amount.assign(received_size);
179   }
180   int64_t current_speed = download_->CurrentSpeed();
181   base::string16 speed_text = ui::FormatSpeed(current_speed);
182   base::i18n::AdjustStringForLocaleDirection(&speed_text);
183 
184   base::TimeDelta remaining;
185   base::string16 time_remaining;
186   if (download_->IsPaused()) {
187     time_remaining = l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED);
188   } else if (download_->TimeRemaining(&remaining)) {
189     time_remaining = ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_REMAINING,
190                                             ui::TimeFormat::LENGTH_SHORT,
191                                             remaining);
192   }
193 
194   if (time_remaining.empty()) {
195     base::i18n::AdjustStringForLocaleDirection(&amount);
196     return l10n_util::GetStringFUTF16(
197         IDS_DOWNLOAD_TAB_PROGRESS_STATUS_TIME_UNKNOWN, speed_text, amount);
198   }
199   return l10n_util::GetStringFUTF16(
200       IDS_DOWNLOAD_TAB_PROGRESS_STATUS, speed_text, amount, time_remaining);
201 }
202 
203 
GetCompletedBytes() const204 int64_t DownloadItemModel::GetCompletedBytes() const {
205   return download_->GetReceivedBytes();
206 }
207 
GetTotalBytes() const208 int64_t DownloadItemModel::GetTotalBytes() const {
209   return download_->AllDataSaved() ? download_->GetReceivedBytes() :
210                                      download_->GetTotalBytes();
211 }
212 
213 // TODO(asanka,rdsmith): Once 'open' moves exclusively to the
214 //     ChromeDownloadManagerDelegate, we should calculate the percentage here
215 //     instead of calling into the DownloadItem.
PercentComplete() const216 int DownloadItemModel::PercentComplete() const {
217   return download_->PercentComplete();
218 }
219 
IsDangerous() const220 bool DownloadItemModel::IsDangerous() const {
221   return download_->IsDangerous();
222 }
223 
MightBeMalicious() const224 bool DownloadItemModel::MightBeMalicious() const {
225   return IsDangerous() && (download_->GetDangerType() !=
226                            download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE);
227 }
228 
229 // If you change this definition of malicious, also update
230 // DownloadManagerImpl::NonMaliciousInProgressCount.
IsMalicious() const231 bool DownloadItemModel::IsMalicious() const {
232   if (!MightBeMalicious())
233     return false;
234   switch (download_->GetDangerType()) {
235     case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
236     case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
237     case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
238     case download::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
239     case download::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_OPENED_DANGEROUS:
240       return true;
241 
242     case download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
243     case download::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
244     case download::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
245     case download::DOWNLOAD_DANGER_TYPE_WHITELISTED_BY_POLICY:
246     case download::DOWNLOAD_DANGER_TYPE_MAX:
247     case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
248       // We shouldn't get any of these due to the MightBeMalicious() test above.
249       NOTREACHED();
250       FALLTHROUGH;
251     case download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
252     case download::DOWNLOAD_DANGER_TYPE_ASYNC_SCANNING:
253     case download::DOWNLOAD_DANGER_TYPE_BLOCKED_PASSWORD_PROTECTED:
254     case download::DOWNLOAD_DANGER_TYPE_BLOCKED_TOO_LARGE:
255     case download::DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_WARNING:
256     case download::DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_BLOCK:
257     case download::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_SAFE:
258     case download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING:
259     case download::DOWNLOAD_DANGER_TYPE_BLOCKED_UNSUPPORTED_FILETYPE:
260       return false;
261   }
262   NOTREACHED();
263   return false;
264 }
265 
IsMixedContent() const266 bool DownloadItemModel::IsMixedContent() const {
267   return download_->IsMixedContent();
268 }
269 
ShouldAllowDownloadFeedback() const270 bool DownloadItemModel::ShouldAllowDownloadFeedback() const {
271 #if BUILDFLAG(FULL_SAFE_BROWSING)
272   if (!IsDangerous())
273     return false;
274   return safe_browsing::DownloadFeedbackService::IsEnabledForDownload(
275       *download_);
276 #else
277   return false;
278 #endif
279 }
280 
ShouldRemoveFromShelfWhenComplete() const281 bool DownloadItemModel::ShouldRemoveFromShelfWhenComplete() const {
282   switch (download_->GetState()) {
283     case DownloadItem::IN_PROGRESS:
284       // If the download is dangerous or malicious, we should display a warning
285       // on the shelf until the user accepts the download.
286       if (IsDangerous())
287         return false;
288 
289       // If the download is a trusted extension, temporary, or will be opened
290       // automatically, then it should be removed from the shelf on completion.
291       // TODO(crbug.com/1077929): The logic for deciding opening behavior should
292       //                          be in a central location.
293       return (download_crx_util::IsTrustedExtensionDownload(profile(),
294                                                             *download_) ||
295               download_->IsTemporary() || download_->GetOpenWhenComplete() ||
296               download_->ShouldOpenFileBasedOnExtension());
297 
298     case DownloadItem::COMPLETE:
299       // If the download completed, then rely on GetAutoOpened() to check for
300       // opening behavior. This should accurately reflect whether the download
301       // was successfully opened.  Extensions, for example, may fail to open.
302       return download_->GetAutoOpened() || download_->IsTemporary();
303 
304     case DownloadItem::CANCELLED:
305     case DownloadItem::INTERRUPTED:
306       // Interrupted or cancelled downloads should remain on the shelf.
307       return false;
308 
309     case DownloadItem::MAX_DOWNLOAD_STATE:
310       NOTREACHED();
311   }
312 
313   NOTREACHED();
314   return false;
315 }
316 
ShouldShowDownloadStartedAnimation() const317 bool DownloadItemModel::ShouldShowDownloadStartedAnimation() const {
318   return !download_->IsSavePackageDownload() &&
319          !download_crx_util::IsTrustedExtensionDownload(profile(), *download_);
320 }
321 
ShouldShowInShelf() const322 bool DownloadItemModel::ShouldShowInShelf() const {
323   const DownloadItemModelData* data = DownloadItemModelData::Get(download_);
324   if (data)
325     return data->should_show_in_shelf_;
326 
327   return !download_->IsTransient();
328 }
329 
SetShouldShowInShelf(bool should_show)330 void DownloadItemModel::SetShouldShowInShelf(bool should_show) {
331   DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_);
332   data->should_show_in_shelf_ = should_show;
333 }
334 
ShouldNotifyUI() const335 bool DownloadItemModel::ShouldNotifyUI() const {
336   if (download_->IsTransient())
337     return false;
338 
339   // The browser is only interested in new active downloads. History downloads
340   // that are completed or interrupted are not displayed on the shelf. The
341   // downloads page independently listens for new downloads when it is active.
342   // Note that the UI will be notified of downloads even if they are not meant
343   // to be displayed on the shelf (i.e. ShouldShowInShelf() returns false). This
344   // is because: *  The shelf isn't the only UI. E.g. on Android, the UI is the
345   // system
346   //    DownloadManager.
347   // *  There are other UI activities that need to be performed. E.g. if the
348   //    download was initiated from a new tab, then that tab should be closed.
349   return download_->GetDownloadCreationType() !=
350              download::DownloadItem::DownloadCreationType::
351                  TYPE_HISTORY_IMPORT ||
352          download_->GetState() == download::DownloadItem::IN_PROGRESS;
353 }
354 
WasUINotified() const355 bool DownloadItemModel::WasUINotified() const {
356   const DownloadItemModelData* data = DownloadItemModelData::Get(download_);
357   return data && data->was_ui_notified_;
358 }
359 
SetWasUINotified(bool was_ui_notified)360 void DownloadItemModel::SetWasUINotified(bool was_ui_notified) {
361   DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_);
362   data->was_ui_notified_ = was_ui_notified;
363 }
364 
ShouldPreferOpeningInBrowser() const365 bool DownloadItemModel::ShouldPreferOpeningInBrowser() const {
366   const DownloadItemModelData* data = DownloadItemModelData::Get(download_);
367   return data && data->should_prefer_opening_in_browser_;
368 }
369 
SetShouldPreferOpeningInBrowser(bool preference)370 void DownloadItemModel::SetShouldPreferOpeningInBrowser(bool preference) {
371   DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_);
372   data->should_prefer_opening_in_browser_ = preference;
373 }
374 
GetDangerLevel() const375 DownloadFileType::DangerLevel DownloadItemModel::GetDangerLevel() const {
376   const DownloadItemModelData* data = DownloadItemModelData::Get(download_);
377   return data ? data->danger_level_ : DownloadFileType::NOT_DANGEROUS;
378 }
379 
SetDangerLevel(DownloadFileType::DangerLevel danger_level)380 void DownloadItemModel::SetDangerLevel(
381     DownloadFileType::DangerLevel danger_level) {
382   DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_);
383   data->danger_level_ = danger_level;
384 }
385 
386 download::DownloadItem::MixedContentStatus
GetMixedContentStatus() const387 DownloadItemModel::GetMixedContentStatus() const {
388   return download_->GetMixedContentStatus();
389 }
390 
IsBeingRevived() const391 bool DownloadItemModel::IsBeingRevived() const {
392   const DownloadItemModelData* data = DownloadItemModelData::Get(download_);
393   return data && data->is_being_revived_;
394 }
395 
SetIsBeingRevived(bool is_being_revived)396 void DownloadItemModel::SetIsBeingRevived(bool is_being_revived) {
397   DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_);
398   data->is_being_revived_ = is_being_revived;
399 }
400 
download()401 download::DownloadItem* DownloadItemModel::download() {
402   return download_;
403 }
404 
GetFileNameToReportUser() const405 base::FilePath DownloadItemModel::GetFileNameToReportUser() const {
406   return download_->GetFileNameToReportUser();
407 }
408 
GetTargetFilePath() const409 base::FilePath DownloadItemModel::GetTargetFilePath() const {
410   return download_->GetTargetFilePath();
411 }
412 
OpenDownload()413 void DownloadItemModel::OpenDownload() {
414   download_->OpenDownload();
415 }
416 
GetState() const417 download::DownloadItem::DownloadState DownloadItemModel::GetState() const {
418   return download_->GetState();
419 }
420 
IsPaused() const421 bool DownloadItemModel::IsPaused() const {
422   return download_->IsPaused();
423 }
424 
GetDangerType() const425 download::DownloadDangerType DownloadItemModel::GetDangerType() const {
426   return download_->GetDangerType();
427 }
428 
GetOpenWhenComplete() const429 bool DownloadItemModel::GetOpenWhenComplete() const {
430   return download_->GetOpenWhenComplete();
431 }
432 
IsOpenWhenCompleteByPolicy() const433 bool DownloadItemModel::IsOpenWhenCompleteByPolicy() const {
434   return download_->ShouldOpenFileByPolicyBasedOnExtension();
435 }
436 
TimeRemaining(base::TimeDelta * remaining) const437 bool DownloadItemModel::TimeRemaining(base::TimeDelta* remaining) const {
438   return download_->TimeRemaining(remaining);
439 }
440 
GetOpened() const441 bool DownloadItemModel::GetOpened() const {
442   return download_->GetOpened();
443 }
444 
SetOpened(bool opened)445 void DownloadItemModel::SetOpened(bool opened) {
446   download_->SetOpened(opened);
447 }
448 
IsDone() const449 bool DownloadItemModel::IsDone() const {
450   return download_->IsDone();
451 }
452 
Pause()453 void DownloadItemModel::Pause() {
454   download_->Pause();
455 }
456 
Resume()457 void DownloadItemModel::Resume() {
458   download_->Resume(true /* has_user_gesture */);
459 }
460 
Cancel(bool user_cancel)461 void DownloadItemModel::Cancel(bool user_cancel) {
462   download_->Cancel(user_cancel);
463 }
464 
Remove()465 void DownloadItemModel::Remove() {
466   download_->Remove();
467 }
468 
SetOpenWhenComplete(bool open)469 void DownloadItemModel::SetOpenWhenComplete(bool open) {
470   download_->SetOpenWhenComplete(open);
471 }
472 
GetFullPath() const473 base::FilePath DownloadItemModel::GetFullPath() const {
474   return download_->GetFullPath();
475 }
476 
CanResume() const477 bool DownloadItemModel::CanResume() const {
478   return download_->CanResume();
479 }
480 
AllDataSaved() const481 bool DownloadItemModel::AllDataSaved() const {
482   return download_->AllDataSaved();
483 }
484 
GetFileExternallyRemoved() const485 bool DownloadItemModel::GetFileExternallyRemoved() const {
486   return download_->GetFileExternallyRemoved();
487 }
488 
GetURL() const489 GURL DownloadItemModel::GetURL() const {
490   return download_->GetURL();
491 }
492 
OnDownloadUpdated(DownloadItem * download)493 void DownloadItemModel::OnDownloadUpdated(DownloadItem* download) {
494   for (auto& obs : observers_)
495     obs.OnDownloadUpdated();
496 }
497 
OnDownloadOpened(DownloadItem * download)498 void DownloadItemModel::OnDownloadOpened(DownloadItem* download) {
499   for (auto& obs : observers_)
500     obs.OnDownloadOpened();
501 }
502 
OnDownloadDestroyed(DownloadItem * download)503 void DownloadItemModel::OnDownloadDestroyed(DownloadItem* download) {
504   for (auto& obs : observers_)
505     obs.OnDownloadDestroyed();
506   download_ = nullptr;
507 }
508 
OpenUsingPlatformHandler()509 void DownloadItemModel::OpenUsingPlatformHandler() {
510   DownloadCoreService* download_core_service =
511       DownloadCoreServiceFactory::GetForBrowserContext(
512           content::DownloadItemUtils::GetBrowserContext(download_));
513   if (!download_core_service)
514     return;
515 
516   ChromeDownloadManagerDelegate* delegate =
517       download_core_service->GetDownloadManagerDelegate();
518   if (!delegate)
519     return;
520   delegate->OpenDownloadUsingPlatformHandler(download_);
521   RecordDownloadOpenMethod(DOWNLOAD_OPEN_METHOD_USER_PLATFORM);
522 }
523 
524 #if !defined(OS_ANDROID)
IsCommandEnabled(const DownloadCommands * download_commands,DownloadCommands::Command command) const525 bool DownloadItemModel::IsCommandEnabled(
526     const DownloadCommands* download_commands,
527     DownloadCommands::Command command) const {
528   switch (command) {
529     case DownloadCommands::SHOW_IN_FOLDER:
530       return download_->CanShowInFolder();
531     case DownloadCommands::OPEN_WHEN_COMPLETE:
532       return download_->CanOpenDownload() &&
533              !download_crx_util::IsExtensionDownload(*download_);
534     case DownloadCommands::PLATFORM_OPEN:
535       return download_->CanOpenDownload() &&
536              !download_crx_util::IsExtensionDownload(*download_);
537     case DownloadCommands::ALWAYS_OPEN_TYPE:
538       // For temporary downloads, the target filename might be a temporary
539       // filename. Don't base an "Always open" decision based on it. Also
540       // exclude extensions.
541       return download_->CanOpenDownload() &&
542              safe_browsing::FileTypePolicies::GetInstance()
543                  ->IsAllowedToOpenAutomatically(
544                      download_->GetTargetFilePath()) &&
545              !download_crx_util::IsExtensionDownload(*download_);
546     case DownloadCommands::PAUSE:
547       return !download_->IsSavePackageDownload() &&
548              DownloadUIModel::IsCommandEnabled(download_commands, command);
549     case DownloadCommands::CANCEL:
550     case DownloadCommands::RESUME:
551     case DownloadCommands::COPY_TO_CLIPBOARD:
552     case DownloadCommands::ANNOTATE:
553     case DownloadCommands::DISCARD:
554     case DownloadCommands::KEEP:
555     case DownloadCommands::LEARN_MORE_SCANNING:
556     case DownloadCommands::LEARN_MORE_INTERRUPTED:
557     case DownloadCommands::LEARN_MORE_MIXED_CONTENT:
558     case DownloadCommands::DEEP_SCAN:
559     case DownloadCommands::BYPASS_DEEP_SCANNING:
560       return DownloadUIModel::IsCommandEnabled(download_commands, command);
561   }
562   NOTREACHED();
563   return false;
564 }
565 
IsCommandChecked(const DownloadCommands * download_commands,DownloadCommands::Command command) const566 bool DownloadItemModel::IsCommandChecked(
567     const DownloadCommands* download_commands,
568     DownloadCommands::Command command) const {
569   switch (command) {
570     case DownloadCommands::OPEN_WHEN_COMPLETE:
571       return download_->GetOpenWhenComplete() ||
572              download_crx_util::IsExtensionDownload(*download_);
573     case DownloadCommands::ALWAYS_OPEN_TYPE:
574 #if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_BSD) || \
575     defined(OS_MAC)
576       if (download_commands->CanOpenPdfInSystemViewer()) {
577         DownloadPrefs* prefs = DownloadPrefs::FromBrowserContext(profile());
578         return prefs->ShouldOpenPdfInSystemReader();
579       }
580 #endif
581       return download_->ShouldOpenFileBasedOnExtension();
582     case DownloadCommands::PAUSE:
583     case DownloadCommands::RESUME:
584       return IsPaused();
585     case DownloadCommands::SHOW_IN_FOLDER:
586     case DownloadCommands::PLATFORM_OPEN:
587     case DownloadCommands::CANCEL:
588     case DownloadCommands::DISCARD:
589     case DownloadCommands::KEEP:
590     case DownloadCommands::LEARN_MORE_SCANNING:
591     case DownloadCommands::LEARN_MORE_INTERRUPTED:
592     case DownloadCommands::LEARN_MORE_MIXED_CONTENT:
593     case DownloadCommands::COPY_TO_CLIPBOARD:
594     case DownloadCommands::ANNOTATE:
595     case DownloadCommands::DEEP_SCAN:
596     case DownloadCommands::BYPASS_DEEP_SCANNING:
597       return false;
598   }
599   return false;
600 }
601 
ExecuteCommand(DownloadCommands * download_commands,DownloadCommands::Command command)602 void DownloadItemModel::ExecuteCommand(DownloadCommands* download_commands,
603                                        DownloadCommands::Command command) {
604   switch (command) {
605     case DownloadCommands::SHOW_IN_FOLDER:
606       download_->ShowDownloadInShell();
607       break;
608     case DownloadCommands::OPEN_WHEN_COMPLETE:
609       download_->OpenDownload();
610       break;
611     case DownloadCommands::ALWAYS_OPEN_TYPE: {
612       bool is_checked = IsCommandChecked(download_commands,
613                                          DownloadCommands::ALWAYS_OPEN_TYPE);
614       DownloadPrefs* prefs = DownloadPrefs::FromBrowserContext(profile());
615 #if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_BSD) || \
616     defined(OS_MAC)
617       if (download_commands->CanOpenPdfInSystemViewer()) {
618         prefs->SetShouldOpenPdfInSystemReader(!is_checked);
619         SetShouldPreferOpeningInBrowser(is_checked);
620         break;
621       }
622 #endif
623       base::FilePath path = download_->GetTargetFilePath();
624       if (is_checked)
625         prefs->DisableAutoOpenByUserBasedOnExtension(path);
626       else
627         prefs->EnableAutoOpenByUserBasedOnExtension(path);
628       break;
629     }
630     case DownloadCommands::BYPASS_DEEP_SCANNING:
631 #if BUILDFLAG(FULL_SAFE_BROWSING)
632       CompleteSafeBrowsingScan();
633 #endif
634       FALLTHROUGH;
635     case DownloadCommands::KEEP:
636       if (IsMixedContent()) {
637         download_->ValidateMixedContentDownload();
638         break;
639       }
640       DCHECK(IsDangerous());
641 // Only sends uncommon download accept report if :
642 // 1. FULL_SAFE_BROWSING is enabled, and
643 // 2. Download verdict is uncommon, and
644 // 3. Download URL is not empty, and
645 // 4. User is not in incognito mode.
646 #if BUILDFLAG(FULL_SAFE_BROWSING)
647       if (GetDangerType() == download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT &&
648           !GetURL().is_empty() && !profile()->IsOffTheRecord()) {
649         safe_browsing::SafeBrowsingService* sb_service =
650             g_browser_process->safe_browsing_service();
651         // Compiles the uncommon download warning report.
652         safe_browsing::ClientSafeBrowsingReportRequest report;
653         report.set_type(safe_browsing::ClientSafeBrowsingReportRequest::
654                             DANGEROUS_DOWNLOAD_WARNING);
655         report.set_download_verdict(
656             safe_browsing::ClientDownloadResponse::UNCOMMON);
657         report.set_url(GetURL().spec());
658         report.set_did_proceed(true);
659         std::string token =
660             safe_browsing::DownloadProtectionService::GetDownloadPingToken(
661                 download_);
662         if (!token.empty())
663           report.set_token(token);
664         std::string serialized_report;
665         if (report.SerializeToString(&serialized_report)) {
666           sb_service->SendSerializedDownloadReport(profile(),
667                                                    serialized_report);
668         } else {
669           DCHECK(false)
670               << "Unable to serialize the uncommon download warning report.";
671         }
672       }
673 #endif
674       download_->ValidateDangerousDownload();
675       break;
676     case DownloadCommands::LEARN_MORE_SCANNING: {
677 #if BUILDFLAG(FULL_SAFE_BROWSING)
678       using safe_browsing::DownloadProtectionService;
679 
680       safe_browsing::SafeBrowsingService* sb_service =
681           g_browser_process->safe_browsing_service();
682       DownloadProtectionService* protection_service =
683           (sb_service ? sb_service->download_protection_service() : nullptr);
684       if (protection_service)
685         protection_service->ShowDetailsForDownload(
686             download_, download_commands->GetBrowser());
687 #else
688       // Should only be getting invoked if we are using safe browsing.
689       NOTREACHED();
690 #endif
691       break;
692     }
693     case DownloadCommands::PLATFORM_OPEN:
694     case DownloadCommands::CANCEL:
695     case DownloadCommands::DISCARD:
696     case DownloadCommands::LEARN_MORE_INTERRUPTED:
697     case DownloadCommands::LEARN_MORE_MIXED_CONTENT:
698     case DownloadCommands::PAUSE:
699     case DownloadCommands::RESUME:
700     case DownloadCommands::COPY_TO_CLIPBOARD:
701     case DownloadCommands::ANNOTATE:
702       DownloadUIModel::ExecuteCommand(download_commands, command);
703       break;
704     case DownloadCommands::DEEP_SCAN:
705       safe_browsing::SafeBrowsingService* sb_service =
706           g_browser_process->safe_browsing_service();
707       if (!sb_service)
708         break;
709       safe_browsing::DownloadProtectionService* protection_service =
710           sb_service->download_protection_service();
711       if (!protection_service)
712         break;
713       DownloadCoreService* download_core_service =
714           DownloadCoreServiceFactory::GetForBrowserContext(
715               content::DownloadItemUtils::GetBrowserContext(download_));
716       DCHECK(download_core_service);
717       ChromeDownloadManagerDelegate* delegate =
718           download_core_service->GetDownloadManagerDelegate();
719       DCHECK(delegate);
720       enterprise_connectors::AnalysisSettings settings;
721       settings.tags = {"malware"};
722       protection_service->UploadForDeepScanning(
723           download_,
724           base::BindRepeating(
725               &ChromeDownloadManagerDelegate::CheckClientDownloadDone,
726               delegate->GetWeakPtr(), download_->GetId()),
727           safe_browsing::DeepScanningRequest::DeepScanTrigger::
728               TRIGGER_APP_PROMPT,
729           std::move(settings));
730       break;
731   }
732 }
733 #endif
734 
GetLastFailState() const735 offline_items_collection::FailState DownloadItemModel::GetLastFailState()
736     const {
737   return OfflineItemUtils::ConvertDownloadInterruptReasonToFailState(
738       download_->GetLastReason());
739 }
740 
GetMimeType() const741 std::string DownloadItemModel::GetMimeType() const {
742   return download_->GetMimeType();
743 }
744 
IsExtensionDownload() const745 bool DownloadItemModel::IsExtensionDownload() const {
746   return download_crx_util::IsExtensionDownload(*download_);
747 }
748 
749 #if BUILDFLAG(FULL_SAFE_BROWSING)
CompleteSafeBrowsingScan()750 void DownloadItemModel::CompleteSafeBrowsingScan() {
751   ChromeDownloadManagerDelegate::SafeBrowsingState* state =
752       static_cast<ChromeDownloadManagerDelegate::SafeBrowsingState*>(
753           download_->GetUserData(
754               &ChromeDownloadManagerDelegate::SafeBrowsingState::
755                   kSafeBrowsingUserDataKey));
756   state->CompleteDownload();
757 }
758 #endif
759 
ShouldShowDropdown() const760 bool DownloadItemModel::ShouldShowDropdown() const {
761   // We don't show the dropdown for dangerous file types or for files
762   // blocked by enterprise policy.
763   if (IsDangerous() && GetState() != DownloadItem::CANCELLED &&
764       !MightBeMalicious()) {
765     return false;
766   }
767 
768   if (GetDangerType() ==
769           download::DOWNLOAD_DANGER_TYPE_SENSITIVE_CONTENT_BLOCK ||
770       GetDangerType() ==
771           download::DOWNLOAD_DANGER_TYPE_BLOCKED_PASSWORD_PROTECTED ||
772       GetDangerType() == download::DOWNLOAD_DANGER_TYPE_BLOCKED_TOO_LARGE ||
773       GetDangerType() ==
774           download::DOWNLOAD_DANGER_TYPE_BLOCKED_UNSUPPORTED_FILETYPE) {
775     return false;
776   }
777 
778   return true;
779 }
780