| // 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_ |