blob: 057819a0c3823e2575fd19bed9edc687445c049a [file] [log] [blame]
// Copyright (c) 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.
#ifndef COMPONENTS_SAFE_BROWSING_TRIGGERS_TRIGGER_MANAGER_H_
#define COMPONENTS_SAFE_BROWSING_TRIGGERS_TRIGGER_MANAGER_H_
#include <unordered_map>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "components/safe_browsing/browser/referrer_chain_provider.h"
#include "components/safe_browsing/triggers/trigger_throttler.h"
#include "components/security_interstitials/content/unsafe_resource.h"
#include "components/security_interstitials/core/base_safe_browsing_error_ui.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
class PrefService;
namespace history {
class HistoryService;
}
namespace network {
class SharedURLLoaderFactory;
}
namespace safe_browsing {
class BaseUIManager;
class ThreatDetails;
// A wrapper around different kinds of data collectors that can be active on a
// given browser tab. Any given field can be null or empty if the associated
// data is not being collected.
struct DataCollectorsContainer {
public:
DataCollectorsContainer();
~DataCollectorsContainer();
// Note: new data collection types should be added below as additional fields.
// Collects ThreatDetails which contains resource URLs and partial DOM.
std::unique_ptr<ThreatDetails> threat_details;
private:
DISALLOW_COPY_AND_ASSIGN(DataCollectorsContainer);
};
// Stores the data collectors that are active on each WebContents (ie: browser
// tab).
using DataCollectorsMap =
std::unordered_map<content::WebContents*, DataCollectorsContainer>;
using SBErrorOptions =
security_interstitials::BaseSafeBrowsingErrorUI::SBErrorDisplayOptions;
// The reasons that trigger manager fails to create or finish a report.
// These values are written to logs. New enum values can be added, but
// existing enums must never be renumbered or deleted and reused.
enum class TriggerManagerReason {
// Default value, used when there is no failure.
NO_REASON = 0,
// User preferences do not allow the report to be started or finished.
USER_PREFERENCES = 1,
// A report is already started on this tab, so no new report is started.
REPORT_ALREADY_STARTED = 2,
// There is no report to finish on this tab.
NO_REPORT_TO_FINISH = 3,
// No report is started because the user has exceeded their daily quota.
DAILY_QUOTA_EXCEEDED = 4,
// New reasons must be added before kMaxValue and the value of kMaxValue
// updated.
kMaxValue = DAILY_QUOTA_EXCEEDED
};
// This class manages SafeBrowsing data-reporting triggers. Triggers are
// activated for users opted-in to Extended Reporting and when security-related
// data collection is required.
//
// The TriggerManager has two main responsibilities: 1) ensuring triggers only
// run when appropriate, by honouring user opt-ins and incognito state, and 2)
// tracking how often triggers fire and throttling them when necessary.
class TriggerManager {
public:
TriggerManager(BaseUIManager* ui_manager,
ReferrerChainProvider* referrer_chain_provider,
PrefService* local_state_prefs);
virtual ~TriggerManager();
// Returns a SBErrorDisplayOptions struct containing user state that is
// relevant for TriggerManager to decide whether to start/finish data
// collection. Looks at incognito state from |web_contents|, and opt-ins from
// |pref_service|. Only the fields needed by TriggerManager will be set.
static SBErrorOptions GetSBErrorDisplayOptions(
const PrefService& pref_service,
content::WebContents* web_contents);
// Returns whether data collection can be started for the |trigger_type| based
// on the settings specified in |error_display_options| as well as quota.
// If false is returned, |out_reason| will be specify the reason.
bool CanStartDataCollectionWithReason(
const SBErrorOptions& error_display_options,
const TriggerType trigger_type,
TriggerManagerReason* out_reason);
// Simplified signature for |CanStartDataCollectionWithReason| for callers
// that don't care about the reason.
bool CanStartDataCollection(const SBErrorOptions& error_display_options,
const TriggerType trigger_type);
// Begins collecting a ThreatDetails report on the specified |web_contents|.
// |resource| is the unsafe resource that cause the collection to occur.
// |url_loader_factory| is used to retrieve data from the HTTP cache.
// |history_service| is used to get data about redirects.
// |error_display_options| contains the current state of relevant user
// preferences. We use this object for interop with WebView, in Chrome it
// should be created by TriggerManager::GetSBErrorDisplayOptions().
// Returns true if the collection began, or false if it didn't.
// If false is returned, |out_reason| is set to the reason the report didn't
// start.
virtual bool StartCollectingThreatDetailsWithReason(
TriggerType trigger_type,
content::WebContents* web_contents,
const security_interstitials::UnsafeResource& resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
const SBErrorOptions& error_display_options,
TriggerManagerReason* out_reason);
// Simplified signature for |StartCollectingThreatDetailsWithReason| for
// callers that don't care about the reason.
virtual bool StartCollectingThreatDetails(
TriggerType trigger_type,
content::WebContents* web_contents,
const security_interstitials::UnsafeResource& resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
const SBErrorOptions& error_display_options);
// Completes the collection of a ThreatDetails report on the specified
// |web_contents| and sends the report. |delay| can be used to wait a period
// of time before finishing the report. |did_proceed| indicates whether the
// user proceeded through the security interstitial associated with this
// report. |num_visits| is how many times the user has visited the site
// before. |error_display_options| contains the current state of relevant user
// preferences. We use this object for interop with WebView, in Chrome it
// should be created by TriggerManager::GetSBErrorDisplayOptions().
// Returns true if the report was completed and sent, or false otherwise (eg:
// the user was not opted-in to extended reporting after collection began).
virtual bool FinishCollectingThreatDetails(
TriggerType trigger_type,
content::WebContents* web_contents,
const base::TimeDelta& delay,
bool did_proceed,
int num_visits,
const SBErrorOptions& error_display_options);
// Called when a ThreatDetails report finishes for the specified
// |web_contents|.
void ThreatDetailsDone(content::WebContents* web_contents);
// Called when the specified |web_contents| is being destroyed. Used to clean
// up our map.
void WebContentsDestroyed(content::WebContents* web_contents);
private:
friend class TriggerManagerTest;
// For testing only - allows injecting a mock Throttler.
void set_trigger_throttler(TriggerThrottler* throttler);
// The UI manager is used to send reports to Google. Not owned.
// TODO(lpz): we may only need a the PingManager here.
BaseUIManager* ui_manager_;
// The Referrer Chain Provider is used to retrieve the referrer chain for
// reports that require it. Not owned.
ReferrerChainProvider* referrer_chain_provider_;
// Map of the data collectors running on each tabs. New keys are added the
// first time any trigger tries to collect data on a tab and are removed when
// the tab is destroyed. The values can be null if a trigger has finished on
// a tab but the tab remains open.
DataCollectorsMap data_collectors_map_;
// Keeps track of how often triggers fire and throttles them when needed.
std::unique_ptr<TriggerThrottler> trigger_throttler_;
base::WeakPtrFactory<TriggerManager> weak_factory_;
// WeakPtrFactory should be last, don't add any members below it.
DISALLOW_COPY_AND_ASSIGN(TriggerManager);
};
// A helper class that listens for events happening on a WebContents and can
// notify TriggerManager of any that are relevant.
class TriggerManagerWebContentsHelper
: public content::WebContentsObserver,
public content::WebContentsUserData<TriggerManagerWebContentsHelper> {
public:
~TriggerManagerWebContentsHelper() override;
// Creates a TriggerManagerWebContentsHelper and scopes its lifetime to the
// specified |web_contents|.
static void CreateForWebContents(content::WebContents* web_contents,
TriggerManager* trigger_manager);
// WebContentsObserver implementation.
void WebContentsDestroyed() override;
private:
friend class content::WebContentsUserData<TriggerManagerWebContentsHelper>;
TriggerManagerWebContentsHelper(content::WebContents* web_contents,
TriggerManager* trigger_manager);
// Trigger Manager will be notified of any relevant WebContents events.
TriggerManager* trigger_manager_;
WEB_CONTENTS_USER_DATA_KEY_DECL();
};
} // namespace safe_browsing
#endif // COMPONENTS_SAFE_BROWSING_TRIGGERS_TRIGGER_MANAGER_H_