910e62b5创建于 1月15日历史提交
// 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());
}