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