123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- // 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_url_checker_delegate_impl.h"
- #include <memory>
- #include <string>
- #include <utility>
- #include <vector>
- #include "android_webview/browser/aw_browser_context.h"
- #include "android_webview/browser/aw_contents.h"
- #include "android_webview/browser/aw_contents_client_bridge.h"
- #include "android_webview/browser/aw_contents_io_thread_client.h"
- #include "android_webview/browser/network_service/aw_web_resource_request.h"
- #include "android_webview/browser/safe_browsing/aw_safe_browsing_allowlist_manager.h"
- #include "android_webview/browser/safe_browsing/aw_safe_browsing_ui_manager.h"
- #include "android_webview/browser_jni_headers/AwSafeBrowsingConfigHelper_jni.h"
- #include "base/android/jni_android.h"
- #include "base/bind.h"
- #include "base/feature_list.h"
- #include "components/safe_browsing/core/browser/db/database_manager.h"
- #include "components/safe_browsing/core/browser/db/v4_protocol_manager_util.h"
- #include "components/safe_browsing/core/common/features.h"
- #include "components/safe_browsing/core/common/web_ui_constants.h"
- #include "components/security_interstitials/content/security_interstitial_tab_helper.h"
- #include "components/security_interstitials/content/unsafe_resource_util.h"
- #include "components/security_interstitials/core/unsafe_resource.h"
- #include "components/security_interstitials/core/urls.h"
- #include "content/public/browser/browser_task_traits.h"
- #include "content/public/browser/browser_thread.h"
- #include "content/public/browser/global_routing_id.h"
- #include "content/public/browser/navigation_entry.h"
- #include "content/public/browser/web_contents.h"
- #include "content/public/common/url_constants.h"
- #include "ui/base/page_transition_types.h"
- namespace android_webview {
- namespace {
- void CallOnReceivedError(AwContentsClientBridge* client,
- AwWebResourceRequest request,
- content::NavigationEntry* entry) {
- if (!client)
- return;
- // We have no way of telling if a navigation was renderer initiated if entry
- // is null but OnReceivedError requires the value to be set, we default to
- // false for that case.
- request.is_renderer_initiated =
- entry ? ui::PageTransitionIsWebTriggerable(entry->GetTransitionType())
- : false;
- // We use ERR_ABORTED here since this is only used in cases where no
- // interstitial is shown.
- client->OnReceivedError(request, net::ERR_ABORTED, true, false);
- }
- } // namespace
- AwUrlCheckerDelegateImpl::AwUrlCheckerDelegateImpl(
- scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager,
- scoped_refptr<AwSafeBrowsingUIManager> ui_manager,
- AwSafeBrowsingAllowlistManager* allowlist_manager)
- : database_manager_(std::move(database_manager)),
- ui_manager_(std::move(ui_manager)),
- threat_types_(safe_browsing::CreateSBThreatTypeSet(
- {safe_browsing::SB_THREAT_TYPE_URL_MALWARE,
- safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
- safe_browsing::SB_THREAT_TYPE_URL_UNWANTED,
- safe_browsing::SB_THREAT_TYPE_BILLING})),
- allowlist_manager_(allowlist_manager) {}
- AwUrlCheckerDelegateImpl::~AwUrlCheckerDelegateImpl() = default;
- void AwUrlCheckerDelegateImpl::MaybeDestroyNoStatePrefetchContents(
- content::WebContents::OnceGetter web_contents_getter) {}
- void AwUrlCheckerDelegateImpl::StartDisplayingBlockingPageHelper(
- const security_interstitials::UnsafeResource& resource,
- const std::string& method,
- const net::HttpRequestHeaders& headers,
- bool is_outermost_main_frame,
- bool has_user_gesture) {
- AwWebResourceRequest request(resource.url.spec(), method,
- is_outermost_main_frame, has_user_gesture,
- headers);
- content::GetUIThreadTaskRunner({})->PostTask(
- FROM_HERE,
- base::BindOnce(&AwUrlCheckerDelegateImpl::StartApplicationResponse,
- ui_manager_, resource, std::move(request)));
- }
- void AwUrlCheckerDelegateImpl::
- StartObservingInteractionsForDelayedBlockingPageHelper(
- const security_interstitials::UnsafeResource& resource,
- bool is_main_frame) {
- NOTREACHED() << "Delayed warnings not implemented for WebView";
- }
- bool AwUrlCheckerDelegateImpl::IsUrlAllowlisted(const GURL& url) {
- return allowlist_manager_->IsUrlAllowed(url);
- }
- void AwUrlCheckerDelegateImpl::SetPolicyAllowlistDomains(
- const std::vector<std::string>& allowlist_domains) {
- // The SafeBrowsingAllowlistDomains policy is not supported on AW.
- return;
- }
- bool AwUrlCheckerDelegateImpl::ShouldSkipRequestCheck(
- const GURL& original_url,
- int frame_tree_node_id,
- int render_process_id,
- int render_frame_id,
- bool originated_from_service_worker) {
- const content::GlobalRenderFrameHostId rfh_id(render_process_id,
- render_frame_id);
- std::unique_ptr<AwContentsIoThreadClient> client;
- if (originated_from_service_worker) {
- client = AwContentsIoThreadClient::GetServiceWorkerIoThreadClient();
- } else if (!rfh_id) {
- client = AwContentsIoThreadClient::FromID(frame_tree_node_id);
- } else {
- client = AwContentsIoThreadClient::FromID(rfh_id);
- }
- // If Safe Browsing is disabled by the app, skip the check. Default to
- // performing the check if we can't find the |client|, since the |client| may
- // be null for some service worker requests (see https://crbug.com/979321).
- bool safe_browsing_enabled = client ? client->GetSafeBrowsingEnabled() : true;
- if (!safe_browsing_enabled)
- return true;
- // If this is a hardcoded WebUI URL we use for testing, do not skip the safe
- // browsing check. We do not check user consent here because we do not ever
- // send such URLs to GMS anyway. It's important to ignore user consent in this
- // case because the GMS APIs we rely on to check user consent often get
- // confused during CTS tests, reporting the user has not consented regardless
- // of the on-device setting. See https://crbug.com/938538.
- bool is_hardcoded_url =
- original_url.SchemeIs(content::kChromeUIScheme) &&
- original_url.host() == safe_browsing::kChromeUISafeBrowsingHost;
- if (is_hardcoded_url)
- return false;
- // For other requests, follow user consent.
- JNIEnv* env = base::android::AttachCurrentThread();
- bool safe_browsing_user_consent =
- Java_AwSafeBrowsingConfigHelper_getSafeBrowsingUserOptIn(env);
- return !safe_browsing_user_consent;
- }
- void AwUrlCheckerDelegateImpl::NotifySuspiciousSiteDetected(
- const base::RepeatingCallback<content::WebContents*()>&
- web_contents_getter) {}
- const safe_browsing::SBThreatTypeSet&
- AwUrlCheckerDelegateImpl::GetThreatTypes() {
- return threat_types_;
- }
- safe_browsing::SafeBrowsingDatabaseManager*
- AwUrlCheckerDelegateImpl::GetDatabaseManager() {
- return database_manager_.get();
- }
- safe_browsing::BaseUIManager* AwUrlCheckerDelegateImpl::GetUIManager() {
- return ui_manager_.get();
- }
- // static
- void AwUrlCheckerDelegateImpl::StartApplicationResponse(
- scoped_refptr<AwSafeBrowsingUIManager> ui_manager,
- const security_interstitials::UnsafeResource& resource,
- const AwWebResourceRequest& request) {
- content::WebContents* web_contents =
- security_interstitials::GetWebContentsForResource(resource);
- security_interstitials::SecurityInterstitialTabHelper*
- security_interstitial_tab_helper = security_interstitials::
- SecurityInterstitialTabHelper::FromWebContents(web_contents);
- if (ui_manager->IsAllowlisted(resource) && security_interstitial_tab_helper &&
- security_interstitial_tab_helper->IsDisplayingInterstitial()) {
- // In this case we are about to leave an interstitial due to the user
- // clicking proceed on it, we shouldn't call OnSafeBrowsingHit again.
- resource.callback_sequence->PostTask(
- FROM_HERE, base::BindOnce(resource.callback, true /* proceed */,
- false /* showed_interstitial */));
- return;
- }
- AwContentsClientBridge* client =
- AwContentsClientBridge::FromWebContents(web_contents);
- if (client) {
- base::OnceCallback<void(SafeBrowsingAction, bool)> callback =
- base::BindOnce(&AwUrlCheckerDelegateImpl::DoApplicationResponse,
- ui_manager, resource, request);
- client->OnSafeBrowsingHit(request, resource.threat_type,
- std::move(callback));
- }
- }
- // static
- void AwUrlCheckerDelegateImpl::DoApplicationResponse(
- scoped_refptr<AwSafeBrowsingUIManager> ui_manager,
- const security_interstitials::UnsafeResource& resource,
- const AwWebResourceRequest& request,
- SafeBrowsingAction action,
- bool reporting) {
- content::WebContents* web_contents =
- security_interstitials::GetWebContentsForResource(resource);
- // |web_contents| can be null after RenderFrameHost is destroyed.
- if (!web_contents)
- return;
- if (!reporting) {
- AwBrowserContext* browser_context =
- AwBrowserContext::FromWebContents(web_contents);
- browser_context->SetExtendedReportingAllowed(false);
- }
- content::NavigationEntry* entry = GetNavigationEntryForResource(resource);
- // TODO(ntfschr): fully handle reporting once we add support (crbug/688629)
- bool proceed;
- switch (action) {
- case SafeBrowsingAction::SHOW_INTERSTITIAL: {
- content::GetUIThreadTaskRunner({})->PostTask(
- FROM_HERE,
- base::BindOnce(
- &AwUrlCheckerDelegateImpl::StartDisplayingDefaultBlockingPage,
- ui_manager, resource));
- AwContents* contents = AwContents::FromWebContents(web_contents);
- if (!contents || !contents->CanShowInterstitial()) {
- // With committed interstitials OnReceivedError for safe browsing
- // blocked sites is generally called from the blocking page object.
- // When CanShowInterstitial is false, no blocking page is created from
- // StartDisplayingDefaultBlockingPage, so we handle the call here.
- CallOnReceivedError(
- AwContentsClientBridge::FromWebContents(web_contents), request,
- entry);
- }
- }
- return;
- case SafeBrowsingAction::PROCEED:
- proceed = true;
- break;
- case SafeBrowsingAction::BACK_TO_SAFETY:
- proceed = false;
- break;
- default:
- NOTREACHED();
- }
- if (!proceed) {
- // With committed interstitials OnReceivedError for safe browsing blocked
- // sites is generally called from the blocking page object. Since no
- // blocking page is created in this case, we manually call it here.
- CallOnReceivedError(AwContentsClientBridge::FromWebContents(web_contents),
- request, entry);
- }
- // Navigate back for back-to-safety on subresources
- if (!proceed && resource.is_subframe) {
- if (web_contents->GetController().CanGoBack()) {
- web_contents->GetController().GoBack();
- } else {
- web_contents->GetController().LoadURL(
- ui_manager->default_safe_page(), content::Referrer(),
- ui::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string());
- }
- }
- GURL main_frame_url = entry ? entry->GetURL() : GURL();
- ui_manager->OnBlockingPageDone(
- std::vector<security_interstitials::UnsafeResource>{resource}, proceed,
- web_contents, main_frame_url, false /* showed_interstitial */);
- }
- // static
- void AwUrlCheckerDelegateImpl::StartDisplayingDefaultBlockingPage(
- scoped_refptr<AwSafeBrowsingUIManager> ui_manager,
- const security_interstitials::UnsafeResource& resource) {
- content::WebContents* web_contents =
- security_interstitials::GetWebContentsForResource(resource);
- if (web_contents) {
- ui_manager->DisplayBlockingPage(resource);
- return;
- }
- // Reporting back that it is not okay to proceed with loading the URL.
- content::GetIOThreadTaskRunner({})->PostTask(
- FROM_HERE, base::BindOnce(resource.callback, false /* proceed */,
- false /* showed_interstitial */));
- }
- } // namespace android_webview
|