blob: 60600f468c0f2f3e3a41ff0f72ba88a0d1e2d819 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/downloads/downloads_ui.h"
#include <memory>
#include <utility>
#include "base/functional/bind.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/singleton.h"
#include "base/metrics/histogram_functions.h"
#include "base/threading/thread.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/enterprise/connectors/connectors_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/safe_browsing/advanced_protection_status_manager.h"
#include "chrome/browser/safe_browsing/advanced_protection_status_manager_factory.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/webui/downloads/downloads.mojom.h"
#include "chrome/browser/ui/webui/downloads/downloads_dom_handler.h"
#include "chrome/browser/ui/webui/managed_ui_handler.h"
#include "chrome/browser/ui/webui/metrics_handler.h"
#include "chrome/browser/ui/webui/theme_source.h"
#include "chrome/common/buildflags.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/branded_strings.h"
#include "chrome/grit/downloads_resources.h"
#include "chrome/grit/downloads_resources_map.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/grit/theme_resources.h"
#include "components/download/public/common/download_features.h"
#include "components/feature_engagement/public/feature_constants.h"
#include "components/feature_engagement/public/feature_list.h"
#include "components/google/core/common/google_util.h"
#include "components/history/core/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/profile_metrics/browser_profile_type.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/url_data_source.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_data_source.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/webui/web_ui_util.h"
#include "ui/webui/webui_util.h"
#include "url/gurl.h"
using content::BrowserContext;
using content::DownloadManager;
using content::WebContents;
namespace {
content::WebUIDataSource* CreateAndAddDownloadsUIHTMLSource(Profile* profile) {
content::WebUIDataSource* source = content::WebUIDataSource::CreateAndAdd(
profile, chrome::kChromeUIDownloadsHost);
webui::SetupWebUIDataSource(source, kDownloadsResources,
IDR_DOWNLOADS_DOWNLOADS_HTML);
bool requests_ap_verdicts =
safe_browsing::AdvancedProtectionStatusManagerFactory::GetForProfile(
profile)
->IsUnderAdvancedProtection();
source->AddBoolean("requestsApVerdicts", requests_ap_verdicts);
static constexpr webui::LocalizedString kStrings[] = {
{"title", IDS_DOWNLOAD_HISTORY_TITLE},
{"searchResultsPlural", IDS_SEARCH_RESULTS_PLURAL},
{"searchResultsSingular", IDS_SEARCH_RESULTS_SINGULAR},
{"actionMenuDescription", IDS_DOWNLOAD_ACTION_MENU_DESCRIPTION},
{"clearAll", IDS_DOWNLOAD_LINK_CLEAR_ALL},
{"clearSearch", IDS_CLEAR_SEARCH},
{"openDownloadsFolder", IDS_DOWNLOAD_LINK_OPEN_DOWNLOADS_FOLDER},
{"moreActions", IDS_DOWNLOAD_MORE_ACTIONS},
{"search", IDS_DOWNLOAD_HISTORY_SEARCH},
{"inIncognito", IDS_DOWNLOAD_IN_INCOGNITO},
// No results message that shows instead of the downloads list.
{"noDownloads", IDS_DOWNLOAD_NO_DOWNLOADS},
{"noSearchResults", IDS_SEARCH_NO_RESULTS},
// Status.
{"statusCancelled", IDS_DOWNLOAD_TAB_CANCELLED},
{"statusRemoved", IDS_DOWNLOAD_FILE_REMOVED},
// Dangerous file.
{"dangerDiscard", IDS_DISCARD_DOWNLOAD},
{"dangerReview", IDS_REVIEW_DOWNLOAD},
// Deep scanning strings.
{"deepScannedFailedDesc", IDS_DEEP_SCANNED_FAILED_DESCRIPTION},
{"deepScannedOpenedDangerousDesc",
IDS_DEEP_SCANNED_OPENED_DANGEROUS_DESCRIPTION},
{"sensitiveContentWarningDesc",
IDS_BLOCK_REASON_SENSITIVE_CONTENT_WARNING},
{"sensitiveContentBlockedDesc",
IDS_SENSITIVE_CONTENT_BLOCKED_DESCRIPTION},
{"forcedSaveToGdriveDesc", IDS_FORCED_SAVE_TO_GDRIVE_DESCRIPTION},
{"blockedTooLargeDesc", IDS_BLOCKED_TOO_LARGE_DESCRIPTION},
{"blockedPasswordProtectedDesc",
IDS_BLOCKED_PASSWORD_PROTECTED_DESCRIPTION},
{"asyncScanningDownloadDesc", IDS_BLOCK_REASON_DEEP_SCANNING_UPDATED},
{"asyncScanningDownloadDescSecond",
IDS_BLOCK_REASON_DEEP_SCANNING_SECOND_UPDATED},
{"promptForScanningDesc", IDS_BLOCK_REASON_PROMPT_FOR_SCANNING_UPDATED},
{"promptForLocalPasswordScanningDesc",
IDS_BLOCK_REASON_PROMPT_FOR_LOCAL_PASSWORD_SCANNING},
{"controlDeepScan", IDS_DOWNLOAD_DEEP_SCAN_UPDATED},
{"controlLocalPasswordScan", IDS_DOWNLOAD_LOCAL_PASSWORD_SCAN},
// Controls.
{"controlPause", IDS_DOWNLOAD_LINK_PAUSE},
{"controlCancel", IDS_DOWNLOAD_LINK_CANCEL},
{"controlResume", IDS_DOWNLOAD_LINK_RESUME},
{"controlRetry", IDS_DOWNLOAD_LINK_RETRY},
{"controlledByUrl", IDS_DOWNLOAD_BY_EXTENSION_URL},
{"controlOpenNow", IDS_OPEN_DOWNLOAD_NOW},
{"controlOpenAnyway", IDS_OPEN_DOWNLOAD_ANYWAY},
{"toastClearedAll", IDS_DOWNLOAD_TOAST_CLEARED_ALL},
{"toastDeletedFromHistoryStillOnDevice",
IDS_DOWNLOADS_TOAST_DELETED_FROM_HISTORY_STILL_ON_DEVICE},
{"toastDeletedFromHistory", IDS_DOWNLOADS_TOAST_DELETED_FROM_HISTORY},
{"toastCopiedDownloadLink", IDS_DOWNLOADS_TOAST_COPIED_DOWNLOAD_LINK},
{"toastCopyDownloadLinkFailed",
IDS_DOWNLOADS_TOAST_COPY_DOWNLOAD_LINK_FAILED},
{"undo", IDS_DOWNLOAD_UNDO},
{"controlKeepDangerous", IDS_DOWNLOAD_KEEP_DANGEROUS_FILE},
{"controlKeepSuspicious", IDS_DOWNLOAD_KEEP_SUSPICIOUS_FILE},
{"controlKeepUnverified", IDS_DOWNLOAD_KEEP_UNVERIFIED_FILE},
{"controlKeepInsecure", IDS_DOWNLOAD_KEEP_INSECURE_FILE},
{"controlDeleteFromHistory", IDS_DOWNLOAD_DELETE_FROM_HISTORY},
{"controlCopyDownloadLink", IDS_DOWNLOAD_COPY_DOWNLOAD_LINK},
// Accessible labels for file icons.
{"accessibleLabelDangerous",
IDS_DOWNLOAD_DANGEROUS_ICON_ACCESSIBLE_LABEL},
{"accessibleLabelSuspicious",
IDS_DOWNLOAD_SUSPICIOUS_ICON_ACCESSIBLE_LABEL},
{"accessibleLabelInsecure", IDS_DOWNLOAD_INSECURE_ICON_ACCESSIBLE_LABEL},
{"accessibleLabelUnverified",
IDS_DOWNLOAD_UNVERIFIED_ICON_ACCESSIBLE_LABEL},
// Screenreader announcements.
{"screenreaderSavedDangerous", IDS_DOWNLOAD_SCREENREADER_SAVED_DANGEROUS},
{"screenreaderSavedSuspicious",
IDS_DOWNLOAD_SCREENREADER_SAVED_SUSPICIOUS},
{"screenreaderSavedInsecure", IDS_DOWNLOAD_SCREENREADER_SAVED_INSECURE},
{"screenreaderSavedUnverified",
IDS_DOWNLOAD_SCREENREADER_SAVED_UNVERIFIED},
{"screenreaderPaused", IDS_DOWNLOAD_SCREENREADER_PAUSED},
{"screenreaderResumed", IDS_DOWNLOAD_SCREENREADER_RESUMED},
{"screenreaderCanceled", IDS_DOWNLOAD_SCREENREADER_CANCELED},
// Warning bypass prompt dialog.
{"warningBypassPromptLearnMoreLink",
IDS_DOWNLOAD_WARNING_BYPASS_PROMPT_LEARN_MORE_LINK},
{"warningBypassPromptDescription",
IDS_DOWNLOAD_WARNING_BYPASS_PROMPT_DESCRIPTION},
// Warning bypass prompt accessibility text.
{"warningBypassPromptLearnMoreLinkAccessible",
IDS_DOWNLOAD_WARNING_BYPASS_PROMPT_LEARN_MORE_LINK_ACCESSIBLE},
// Warning bypass dialog.
{"warningBypassDialogTitle", IDS_DOWNLOAD_WARNING_BYPASS_DIALOG_TITLE},
{"warningBypassDialogCancel", IDS_CANCEL},
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
// ESB Download Row Promo
{"esbDownloadRowPromoString", IDS_DOWNLOAD_ROW_ESB_PROMOTION},
{"esbDownloadRowPromoA11y", IDS_DOWNLOAD_ROW_ESB_PROMO_A11Y},
#endif
// Strings describing reasons for blocked downloads.
{"noSafeBrowsingDesc",
IDS_BLOCK_DOWNLOAD_REASON_UNVERIFIED_NO_SAFE_BROWSING},
{"dangerFileDesc", IDS_BLOCK_DOWNLOAD_REASON_DANGEROUS_FILETYPE},
{"dangerDownloadDesc", IDS_BLOCK_DOWNLOAD_REASON_DANGEROUS},
{"dangerDownloadCookieTheft",
IDS_BLOCK_DOWNLOAD_REASON_DANGEROUS_COOKIE_THEFT},
{"dangerSettingsDesc", IDS_BLOCK_DOWNLOAD_REASON_POTENTIALLY_UNWANTED},
{"insecureDownloadDesc", IDS_BLOCK_DOWNLOAD_REASON_INSECURE},
// Format string for showing the "source" of the downloaded file as the
// initiator origin of the download request.
{"initiatorLine", IDS_DOWNLOADS_PAGE_INITIATOR_LINE},
};
source->AddLocalizedStrings(kStrings);
source->AddBoolean("showInitiatorOrigin",
base::FeatureList::IsEnabled(
download::features::kDisplayInitiatorOrigin));
source->AddLocalizedString(
"dangerUncommonDesc",
requests_ap_verdicts
? IDS_BLOCK_REASON_UNCOMMON_DOWNLOAD_IN_ADVANCED_PROTECTION
: IDS_BLOCK_DOWNLOAD_REASON_UNCOMMON);
source->AddLocalizedString(
"dangerUncommonSuspiciousArchiveDesc",
requests_ap_verdicts
? IDS_BLOCK_REASON_UNCOMMON_DOWNLOAD_IN_ADVANCED_PROTECTION
: IDS_BLOCK_DOWNLOAD_REASON_UNCOMMON_SUSPICIOUS_ARCHIVE);
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
// Download Row ESB Promo:
source->AddBoolean("esbDownloadRowPromo",
base::FeatureList::IsEnabled(
feature_engagement::kEsbDownloadRowPromoFeature));
#endif
// Build an Accelerator to describe undo shortcut
// NOTE: the undo shortcut is also defined in downloads/downloads.html
// TODO(crbug.com/40597071): de-duplicate shortcut by moving all shortcut
// definitions from JS to C++.
ui::Accelerator undo_accelerator(ui::VKEY_Z, ui::EF_PLATFORM_ACCELERATOR);
source->AddString("undoDescription", l10n_util::GetStringFUTF16(
IDS_UNDO_DESCRIPTION,
undo_accelerator.GetShortcutText()));
PrefService* prefs = profile->GetPrefs();
source->AddBoolean("allowDeletingHistory",
prefs->GetBoolean(prefs::kAllowDeletingBrowserHistory) &&
!profile->IsChild());
// The URL to open when the user clicks on "Learn more" for a blocked
// dangerous file.
source->AddString("blockedLearnMoreUrl",
google_util::AppendGoogleLocaleParam(
GURL(chrome::kDownloadBlockedLearnMoreURL),
g_browser_process->GetApplicationLocale())
.spec());
return source;
}
} // namespace
///////////////////////////////////////////////////////////////////////////////
//
// DownloadsUIConfig
//
///////////////////////////////////////////////////////////////////////////////
DownloadsUIConfig::DownloadsUIConfig()
: DefaultWebUIConfig(content::kChromeUIScheme,
chrome::kChromeUIDownloadsHost) {}
DownloadsUIConfig::~DownloadsUIConfig() = default;
///////////////////////////////////////////////////////////////////////////////
//
// DownloadsUI
//
///////////////////////////////////////////////////////////////////////////////
DownloadsUI::DownloadsUI(content::WebUI* web_ui)
: ui::MojoWebUIController(web_ui, true),
webui_load_timer_(web_ui->GetWebContents(),
"Download.WebUi.DocumentLoadedInMainFrameTime",
"Download.WebUi.LoadCompletedInMainFrame") {
Profile* profile = Profile::FromWebUI(web_ui);
web_ui->AddMessageHandler(std::make_unique<MetricsHandler>());
// Set up the chrome://downloads/ source.
content::WebUIDataSource* source = CreateAndAddDownloadsUIHTMLSource(profile);
ManagedUIHandler::Initialize(web_ui, source);
content::URLDataSource::Add(profile, std::make_unique<ThemeSource>(profile));
base::UmaHistogramEnumeration(
"Download.OpenDownloads.PerProfileType",
profile_metrics::GetBrowserProfileType(profile));
}
WEB_UI_CONTROLLER_TYPE_IMPL(DownloadsUI)
DownloadsUI::~DownloadsUI() = default;
// static
base::RefCountedMemory* DownloadsUI::GetFaviconResourceBytes(
ui::ResourceScaleFactor scale_factor) {
return ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale(
IDR_DOWNLOADS_FAVICON, scale_factor);
}
void DownloadsUI::BindInterface(
mojo::PendingReceiver<downloads::mojom::PageHandlerFactory> receiver) {
page_factory_receiver_.reset();
page_factory_receiver_.Bind(std::move(receiver));
}
void DownloadsUI::CreatePageHandler(
mojo::PendingRemote<downloads::mojom::Page> page,
mojo::PendingReceiver<downloads::mojom::PageHandler> receiver) {
DCHECK(page);
Profile* profile = Profile::FromWebUI(web_ui());
DownloadManager* dlm = profile->GetDownloadManager();
page_handler_ = std::make_unique<DownloadsDOMHandler>(
std::move(receiver), std::move(page), dlm, web_ui());
}