blob: 44ca62b87fbddfc349780934533167f79f102bb4 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_BLOCKED_CONTENT_SAFE_BROWSING_TRIGGERED_POPUP_BLOCKER_H_
#define COMPONENTS_BLOCKED_CONTENT_SAFE_BROWSING_TRIGGERED_POPUP_BLOCKER_H_
#include "base/feature_list.h"
#include "base/gtest_prod_util.h"
#include "base/scoped_observation.h"
#include "components/safe_browsing/core/browser/db/util.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
#include "content/public/browser/navigation_handle_user_data.h"
#include "content/public/browser/page_user_data.h"
#include "content/public/browser/web_contents_observer.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace content {
class WebContents;
} // namespace content
namespace user_prefs {
class PrefRegistrySyncable;
}
namespace blocked_content {
BASE_DECLARE_FEATURE(kAbusiveExperienceEnforce);
constexpr char kAbusiveEnforceMessage[] =
"Chrome prevented this site from opening a new tab or window. Learn more "
"at https://www.chromestatus.com/feature/5243055179300864";
constexpr char kAbusiveWarnMessage[] =
"Chrome might start preventing this site from opening new tabs or "
"windows in the future. Learn more at "
"https://www.chromestatus.com/feature/5243055179300864";
// This class observes main frame navigation checks incoming from safe browsing
// (currently implemented by the subresource_filter component). For navigations
// which match the ABUSIVE safe browsing list, this class will help the popup
// tab helper in applying a stronger policy for blocked popups.
class SafeBrowsingTriggeredPopupBlocker
: public content::WebContentsObserver,
public content::WebContentsUserData<SafeBrowsingTriggeredPopupBlocker>,
public subresource_filter::SubresourceFilterObserver {
public:
// This enum backs a histogram. Please append new entries to the end, and
// update enums.xml when making changes.
enum class Action : int {
// User committed a navigation to a non-error page.
kNavigation,
// Safe Browsing considered this page abusive and the page should be warned.
// Logged at navigation commit.
kWarningSite,
// Safe Browsing considered this page abusive and the page should be be
// blocked against. Logged at navigation commit.
kEnforcedSite,
// The popup blocker called into this object to ask if the strong blocking
// should be applied.
kConsidered,
// This object responded to the popup blocker in the affirmative, and the
// popup was blocked.
kBlocked,
// Add new entries before this one
kCount
};
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
// Creates a SafeBrowsingTriggeredPopupBlocker and attaches it (via UserData)
// to |web_contents|.
static void MaybeCreate(content::WebContents* web_contents);
SafeBrowsingTriggeredPopupBlocker(const SafeBrowsingTriggeredPopupBlocker&) =
delete;
SafeBrowsingTriggeredPopupBlocker& operator=(
const SafeBrowsingTriggeredPopupBlocker&) = delete;
~SafeBrowsingTriggeredPopupBlocker() override;
bool ShouldApplyAbusivePopupBlocker(content::Page& page);
private:
FRIEND_TEST_ALL_PREFIXES(SafeBrowsingTriggeredPopupBlockerTest,
NonPrimaryFrameTree);
friend class content::WebContentsUserData<SafeBrowsingTriggeredPopupBlocker>;
// The |web_contents| and |observer_manager| are expected to be
// non-nullptr.
SafeBrowsingTriggeredPopupBlocker(
content::WebContents* web_contents,
subresource_filter::SubresourceFilterObserverManager* observer_manager);
// content::WebContentsObserver:
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
// subresource_filter::SubresourceFilterObserver:
void OnSafeBrowsingChecksComplete(
content::NavigationHandle* navigation_handle,
const subresource_filter::SubresourceFilterSafeBrowsingClient::
CheckResult& result) override;
void OnSubresourceFilterGoingAway() override;
// Enabled state is governed by both a feature flag and a pref (which can be
// controlled by enterprise policy).
static bool IsEnabled(content::WebContents* web_contents);
// Data scoped to a single page. PageData has the same lifetime as the page's
// main document.
class PageData : public content::PageUserData<PageData> {
public:
explicit PageData(content::Page& page);
PageData(const PageData&) = delete;
PageData& operator=(const PageData&) = delete;
// Logs UMA in the destructor based on the number of popups blocked.
~PageData() override;
void inc_num_popups_blocked() { ++num_popups_blocked_; }
void set_is_triggered(bool is_triggered) { is_triggered_ = is_triggered; }
bool is_triggered() const { return is_triggered_; }
PAGE_USER_DATA_KEY_DECL();
private:
// How many popups are blocked in this page.
int num_popups_blocked_ = 0;
// Whether the current committed page load should trigger the stronger popup
// blocker.
bool is_triggered_ = false;
};
class NavigationHandleData
: public content::NavigationHandleUserData<NavigationHandleData> {
public:
explicit NavigationHandleData(content::NavigationHandle&);
~NavigationHandleData() override;
absl::optional<safe_browsing::SubresourceFilterLevel>&
level_for_next_committed_navigation() {
return level_for_next_committed_navigation_;
}
NAVIGATION_HANDLE_USER_DATA_KEY_DECL();
private:
// Whether this navigation should trigger the stronger popup blocker in
// enforce or warn mode.
absl::optional<safe_browsing::SubresourceFilterLevel>
level_for_next_committed_navigation_;
};
// Returns the PageData for the specified |page|.
PageData& GetPageData(content::Page& page);
base::ScopedObservation<subresource_filter::SubresourceFilterObserverManager,
subresource_filter::SubresourceFilterObserver>
scoped_observation_{this};
WEB_CONTENTS_USER_DATA_KEY_DECL();
};
} // namespace blocked_content
#endif // COMPONENTS_BLOCKED_CONTENT_SAFE_BROWSING_TRIGGERED_POPUP_BLOCKER_H_