blob: 897c4a10579e7e6bab5d03d329d8c3cd16b8e0c8 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.h"
#include <memory>
#include <utility>
#include "android_webview/browser/aw_browser_context.h"
#include "android_webview/browser/aw_browser_process.h"
#include "android_webview/browser/aw_contents_client_bridge.h"
#include "android_webview/browser/network_service/aw_web_resource_request.h"
#include "android_webview/browser/safe_browsing/aw_safe_browsing_ui_manager.h"
#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "components/prefs/pref_service.h"
#include "components/safe_browsing/content/browser/threat_details.h"
#include "components/safe_browsing/content/browser/triggers/trigger_manager.h"
#include "components/safe_browsing/core/common/features.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "components/safe_browsing/core/common/utils.h"
#include "components/security_interstitials/content/security_interstitial_controller_client.h"
#include "components/security_interstitials/content/settings_page_helper.h"
#include "components/security_interstitials/content/unsafe_resource_util.h"
#include "components/security_interstitials/core/base_safe_browsing_error_ui.h"
#include "components/security_interstitials/core/safe_browsing_quiet_error_ui.h"
#include "components/security_interstitials/core/unsafe_resource.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "net/base/net_errors.h"
using content::WebContents;
using security_interstitials::BaseSafeBrowsingErrorUI;
using security_interstitials::SafeBrowsingQuietErrorUI;
using security_interstitials::SecurityInterstitialControllerClient;
namespace android_webview {
AwSafeBrowsingBlockingPage::AwSafeBrowsingBlockingPage(
AwSafeBrowsingUIManager* ui_manager,
WebContents* web_contents,
const GURL& main_frame_url,
const UnsafeResourceList& unsafe_resources,
std::unique_ptr<SecurityInterstitialControllerClient> controller_client,
const BaseSafeBrowsingErrorUI::SBErrorDisplayOptions& display_options,
ErrorUiType errorUiType,
std::unique_ptr<AwWebResourceRequest> resource_request)
: BaseBlockingPage(ui_manager,
web_contents,
main_frame_url,
unsafe_resources,
std::move(controller_client),
display_options),
threat_details_in_progress_(false),
resource_request_(std::move(resource_request)) {
if (errorUiType == ErrorUiType::QUIET_SMALL ||
errorUiType == ErrorUiType::QUIET_GIANT) {
set_sb_error_ui(std::make_unique<SafeBrowsingQuietErrorUI>(
unsafe_resources[0].url, main_frame_url,
GetInterstitialReason(unsafe_resources), display_options,
ui_manager->app_locale(), base::Time::NowFromSystemTime(), controller(),
errorUiType == ErrorUiType::QUIET_GIANT));
}
if (unsafe_resources.size() == 1 &&
ShouldReportThreatDetails(unsafe_resources[0].threat_type)) {
AwBrowserContext* aw_browser_context =
AwBrowserContext::FromWebContents(web_contents);
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory =
aw_browser_context->GetDefaultStoragePartition()
->GetURLLoaderFactoryForBrowserProcess();
// TODO(timvolodine): create a proper history service; currently the
// HistoryServiceFactory lives in the chrome/ layer and relies on Profile
// which we don't have in Android WebView (crbug.com/731744).
threat_details_in_progress_ =
AwBrowserProcess::GetInstance()
->GetSafeBrowsingTriggerManager()
->StartCollectingThreatDetails(
safe_browsing::TriggerType::SECURITY_INTERSTITIAL, web_contents,
unsafe_resources[0], url_loader_factory,
/*history_service*/ nullptr,
/*referrer_chain_provider*/ nullptr,
sb_error_ui()->get_error_display_options());
}
}
AwSafeBrowsingBlockingPage* AwSafeBrowsingBlockingPage::CreateBlockingPage(
AwSafeBrowsingUIManager* ui_manager,
content::WebContents* web_contents,
const GURL& main_frame_url,
const UnsafeResource& unsafe_resource,
std::unique_ptr<AwWebResourceRequest> resource_request) {
// Log the request destination that triggers the safe browsing blocking page.
UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.BlockingPage.RequestDestination",
unsafe_resource.request_destination);
const UnsafeResourceList unsafe_resources{unsafe_resource};
AwBrowserContext* browser_context =
AwBrowserContext::FromWebContents(web_contents);
PrefService* pref_service = browser_context->GetPrefService();
// TODO(crbug.com/1134678): Set is_enhanced_protection_message_enabled once
// enhanced protection is supported on aw.
BaseSafeBrowsingErrorUI::SBErrorDisplayOptions display_options =
BaseSafeBrowsingErrorUI::SBErrorDisplayOptions(
IsMainPageLoadBlocked(unsafe_resources),
safe_browsing::IsExtendedReportingOptInAllowed(*pref_service),
browser_context->IsOffTheRecord(),
safe_browsing::IsExtendedReportingEnabled(*pref_service),
safe_browsing::IsExtendedReportingPolicyManaged(*pref_service),
safe_browsing::IsEnhancedProtectionEnabled(*pref_service),
pref_service->GetBoolean(::prefs::kSafeBrowsingProceedAnywayDisabled),
false, // should_open_links_in_new_tab
false, // always_show_back_to_safety
false, // is_enhanced_protection_message_enabled
safe_browsing::IsSafeBrowsingPolicyManaged(*pref_service),
"cpn_safe_browsing_wv"); // help_center_article_link
ErrorUiType errorType =
static_cast<ErrorUiType>(ui_manager->GetErrorUiType(web_contents));
// TODO(carlosil): This logic is necessary to support committed and non
// committed interstitials, it can be cleaned up when removing non-committed
// interstitials.
content::NavigationEntry* entry =
GetNavigationEntryForResource(unsafe_resource);
GURL url =
(main_frame_url.is_empty() && entry) ? entry->GetURL() : main_frame_url;
// TODO(crbug.com/1134678): Set settings_page_helper once enhanced protection
// is supported on aw.
return new AwSafeBrowsingBlockingPage(
ui_manager, web_contents, url, unsafe_resources,
CreateControllerClient(web_contents, unsafe_resources, ui_manager,
pref_service, /*settings_page_helper*/ nullptr),
display_options, errorType, std::move(resource_request));
}
AwSafeBrowsingBlockingPage::~AwSafeBrowsingBlockingPage() {}
void AwSafeBrowsingBlockingPage::FinishThreatDetails(
const base::TimeDelta& delay,
bool did_proceed,
int num_visits) {
// Not all interstitials collect threat details, e.g. when not opted in.
if (!threat_details_in_progress_)
return;
// Finish computing threat details. TriggerManager will decide if it is safe
// to send the report.
bool report_sent = AwBrowserProcess::GetInstance()
->GetSafeBrowsingTriggerManager()
->FinishCollectingThreatDetails(
safe_browsing::TriggerType::SECURITY_INTERSTITIAL,
web_contents(), delay, did_proceed, num_visits,
sb_error_ui()->get_error_display_options());
if (report_sent) {
controller()->metrics_helper()->RecordUserInteraction(
security_interstitials::MetricsHelper::EXTENDED_REPORTING_IS_ENABLED);
}
}
void AwSafeBrowsingBlockingPage::OnInterstitialClosing() {
if (resource_request_ && !proceeded()) {
AwContentsClientBridge* client =
AwContentsClientBridge::FromWebContents(web_contents());
// With committed interstitials, the navigation to the site is failed before
// showing the interstitial so we omit notifications to embedders at that
// time, and manually trigger them here.
if (client) {
client->OnReceivedError(*resource_request_,
safe_browsing::kNetErrorCodeForSafeBrowsing, true,
false);
}
}
safe_browsing::BaseBlockingPage::OnInterstitialClosing();
}
} // namespace android_webview