1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
|
// 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_SAFE_BROWSING_CORE_BROWSER_PING_MANAGER_H_
#define COMPONENTS_SAFE_BROWSING_CORE_BROWSER_PING_MANAGER_H_
// A class that reports basic safebrowsing statistics to Google's SafeBrowsing
// servers.
#include <memory>
#include <set>
#include <string>
#include "base/containers/unique_ptr_adapters.h"
#include "base/files/file_util.h"
#include "base/functional/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/task/sequenced_task_runner.h"
#include "base/threading/sequence_bound.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/safe_browsing/core/browser/db/hit_report.h"
#include "components/safe_browsing/core/browser/db/util.h"
#include "components/safe_browsing/core/browser/safe_browsing_hats_delegate.h"
#include "components/safe_browsing/core/browser/safe_browsing_token_fetcher.h"
#include "components/safe_browsing/core/common/proto/csd.pb.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "url/gurl.h"
namespace network {
class SimpleURLLoader;
} // namespace network
namespace safe_browsing {
class PingManager : public KeyedService {
public:
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class ReportThreatDetailsResult {
SUCCESS = 0,
// There was a problem serializing the report to a string.
SERIALIZATION_ERROR = 1,
// The report is empty, so it is not sent.
EMPTY_REPORT = 2,
kMaxValue = EMPTY_REPORT,
};
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class PersistThreatDetailsResult {
// The task to persist the report has posted. The actual file write
// operation may still fail.
kPersistTaskPosted = 0,
// There was a problem serializing the report to a string.
kSerializationError = 1,
// The report is empty, so it is not sent.
kEmptyReport = 2,
kMaxValue = kEmptyReport,
};
// Interface via which a client of this class can surface relevant events in
// WebUI. All methods must be called on the UI thread.
class WebUIDelegate {
public:
virtual ~WebUIDelegate() = default;
// Track a client safe browsing report being sent.
virtual void AddToCSBRRsSent(
std::unique_ptr<ClientSafeBrowsingReportRequest> csbrr) = 0;
// Track a hit report being sent.
virtual void AddToHitReportsSent(std::unique_ptr<HitReport> hit_report) = 0;
};
// Helper class to read/write a report on disk.
class Persister {
public:
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class WriteResult {
kSuccess = 0,
kFailedCreateDirectory = 1,
kFailedWriteFile = 2,
kMaxValue = kFailedWriteFile,
};
explicit Persister(const base::FilePath& persister_root_path);
Persister(const Persister&) = delete;
Persister& operator=(const Persister&) = delete;
~Persister() = default;
// Writes |serialized_report| to a new file in |dir_path_|.
void WriteReport(const std::string& serialized_report);
// Reads all persisted reports in |dir_path_|. The reports are deleted
// regardless of whether the read was successful or not.
// Returns a list of string representation of the reports.
std::vector<std::string> ReadAndDeleteReports();
private:
// The directory that the files will be written in.
base::FilePath dir_path_;
};
explicit PingManager(
const V4ProtocolConfig& config,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
std::unique_ptr<SafeBrowsingTokenFetcher> token_fetcher,
base::RepeatingCallback<bool()> get_should_fetch_access_token,
WebUIDelegate* webui_delegate,
scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
base::RepeatingCallback<ChromeUserPopulation()>
get_user_population_callback,
base::RepeatingCallback<ChromeUserPopulation::PageLoadToken(GURL)>
get_page_load_token_callback,
std::unique_ptr<SafeBrowsingHatsDelegate> hats_delegate,
const base::FilePath& persister_root_path,
base::RepeatingCallback<bool()> get_should_send_persisted_report);
PingManager(const PingManager&) = delete;
PingManager& operator=(const PingManager&) = delete;
~PingManager() override;
// Create an instance of the safe browsing ping manager.
static std::unique_ptr<PingManager> Create(
const V4ProtocolConfig& config,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
std::unique_ptr<SafeBrowsingTokenFetcher> token_fetcher,
base::RepeatingCallback<bool()> get_should_fetch_access_token,
WebUIDelegate* webui_delegate,
scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
base::RepeatingCallback<ChromeUserPopulation()>
get_user_population_callback,
base::RepeatingCallback<ChromeUserPopulation::PageLoadToken(GURL)>
get_page_load_token_callback,
std::unique_ptr<SafeBrowsingHatsDelegate> hats_delegate,
const base::FilePath& persister_root_path,
base::RepeatingCallback<bool()> get_should_send_persisted_report);
void OnURLLoaderComplete(network::SimpleURLLoader* source,
std::unique_ptr<std::string> response_body);
void OnSafeBrowsingHitURLLoaderComplete(
network::SimpleURLLoader* source,
std::unique_ptr<std::string> response_body);
void OnThreatDetailsReportURLLoaderComplete(
network::SimpleURLLoader* source,
bool has_access_token,
std::unique_ptr<std::string> response_body);
// Report to Google when a SafeBrowsing warning is shown to the user.
// |hit_report.threat_type| should be one of the types known by
// SafeBrowsingtHitUrl. This method will also sanitize the URLs in the report
// before sending it.
void ReportSafeBrowsingHit(
std::unique_ptr<safe_browsing::HitReport> hit_report);
// Sends a detailed threat report after performing validation, sanitizing
// contained URLs, and adding extra details to the report. The returned object
// provides details on whether the report was successful.
virtual ReportThreatDetailsResult ReportThreatDetails(
std::unique_ptr<ClientSafeBrowsingReportRequest> report);
// Similar to |ReportThreatDetails|, but persists the report on disk and sends
// it on next startup.
virtual PersistThreatDetailsResult PersistThreatDetailsAndReportOnNextStartup(
std::unique_ptr<ClientSafeBrowsingReportRequest> report);
// Launches a survey and attaches ThreatDetails to the survey response.
virtual void AttachThreatDetailsAndLaunchSurvey(
std::unique_ptr<ClientSafeBrowsingReportRequest> report);
// Only used for tests
void SetURLLoaderFactoryForTesting(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
void SetTokenFetcherForTesting(
std::unique_ptr<SafeBrowsingTokenFetcher> token_fetcher);
void SetHatsDelegateForTesting(
std::unique_ptr<SafeBrowsingHatsDelegate> hats_delegate);
void SetOnURLLoaderCompleteCallbackForTesting(
base::OnceCallback<void()> callback);
protected:
friend class PingManagerTest;
private:
FRIEND_TEST_ALL_PREFIXES(PingManagerTest, TestSafeBrowsingHitUrl);
FRIEND_TEST_ALL_PREFIXES(PingManagerTest, TestThreatDetailsUrl);
FRIEND_TEST_ALL_PREFIXES(PingManagerTest, TestReportThreatDetails);
FRIEND_TEST_ALL_PREFIXES(PingManagerTest, TestReportSafeBrowsingHit);
FRIEND_TEST_ALL_PREFIXES(PingManagerTest, TestSanitizeHitReport);
FRIEND_TEST_ALL_PREFIXES(PingManagerTest, TestSanitizeThreatDetailsReport);
const V4ProtocolConfig config_;
using Reports = std::set<std::unique_ptr<network::SimpleURLLoader>,
base::UniquePtrComparator>;
// Generates URL for reporting safe browsing hits.
GURL SafeBrowsingHitUrl(safe_browsing::HitReport* hit_report) const;
// Generates URL for reporting threat details for users who opt-in.
GURL ThreatDetailsUrl() const;
// Sanitizes the URLs in the client safe browsing report.
void SanitizeThreatDetailsReport(
safe_browsing::ClientSafeBrowsingReportRequest* report);
// Sanitizes the URLs in the hit report.
void SanitizeHitReport(HitReport* hit_report);
// Once the user's access_token has been fetched by ReportThreatDetails (or
// intentionally not fetched), attaches the token and sends the report.
void ReportThreatDetailsOnGotAccessToken(const std::string& serialized_report,
const std::string& access_token);
// Reads persisted reports from disk.
void ReadPersistedReports();
// Sends `serialized_reports` to Safe Browsing.
void OnReadPersistedReportsDone(std::vector<std::string> serialized_reports);
// Track outstanding SafeBrowsing report fetchers for clean up.
// We add both "hit" and "detail" fetchers in this set.
Reports safebrowsing_reports_;
// Used to issue network requests.
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
// The token fetcher used for getting access token.
std::unique_ptr<SafeBrowsingTokenFetcher> token_fetcher_;
// Determines whether it's relevant to fetch the access token for the user
// based on whether they're a signed-in ESB user.
base::RepeatingCallback<bool()> get_should_fetch_access_token_;
// WebUIInfoSingleton extends PingManager::WebUIDelegate to enable the
// workaround of calling methods in WebUIInfoSingleton without /core having a
// dependency on /content.
raw_ptr<WebUIDelegate> webui_delegate_;
// The task runner for the UI thread.
scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
// Pulls the user population.
base::RepeatingCallback<ChromeUserPopulation()> get_user_population_callback_;
// Pulls the page load token.
base::RepeatingCallback<ChromeUserPopulation::PageLoadToken(GURL)>
get_page_load_token_callback_;
// Launches HaTS surveys.
std::unique_ptr<SafeBrowsingHatsDelegate> hats_delegate_;
base::SequenceBound<Persister> persister_;
// Determines whether the user has opted in to send persisted reports.
base::RepeatingCallback<bool()> get_should_send_persisted_report_;
// If populated, called once the URL loader completes.
base::OnceCallback<void()> on_url_loader_complete_callback_;
base::WeakPtrFactory<PingManager> weak_factory_{this};
};
} // namespace safe_browsing
#endif // COMPONENTS_SAFE_BROWSING_CORE_BROWSER_PING_MANAGER_H_
|