Refactor WebsiteSettings to operate on a SecurityInfo
[chromium-blink-merge.git] / chrome / browser / safe_browsing / ui_manager.cc
blob16831148fb7b99afe8ce71d631c26588bd4c18a3
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/safe_browsing/ui_manager.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/debug/leak_tracker.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_util.h"
14 #include "base/threading/thread.h"
15 #include "base/threading/thread_restrictions.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/safe_browsing/malware_details.h"
19 #include "chrome/browser/safe_browsing/metadata.pb.h"
20 #include "chrome/browser/safe_browsing/ping_manager.h"
21 #include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
22 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
23 #include "chrome/browser/tab_contents/tab_util.h"
24 #include "chrome/common/pref_names.h"
25 #include "chrome/common/url_constants.h"
26 #include "components/metrics/metrics_service.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/navigation_entry.h"
29 #include "content/public/browser/notification_service.h"
30 #include "content/public/browser/web_contents.h"
31 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
32 #include "net/ssl/ssl_info.h"
33 #include "net/url_request/url_request_context.h"
34 #include "net/url_request/url_request_context_getter.h"
36 using content::BrowserThread;
37 using content::NavigationEntry;
38 using content::WebContents;
40 namespace {
41 const void* kWhitelistKey = &kWhitelistKey;
43 class WhitelistUrlSet : public base::SupportsUserData::Data {
44 public:
45 WhitelistUrlSet() {}
47 bool Contains(const GURL url) {
48 auto iter = set_.find(url.GetWithEmptyPath());
49 return iter != set_.end();
52 void Insert(const GURL url) { set_.insert(url.GetWithEmptyPath()); }
54 private:
55 std::set<GURL> set_;
57 DISALLOW_COPY_AND_ASSIGN(WhitelistUrlSet);
60 } // namespace
62 // SafeBrowsingUIManager::UnsafeResource ---------------------------------------
64 SafeBrowsingUIManager::UnsafeResource::UnsafeResource()
65 : is_subresource(false),
66 threat_type(SB_THREAT_TYPE_SAFE),
67 render_process_host_id(-1),
68 render_view_id(-1),
69 threat_source(FROM_UNKNOWN) {
72 SafeBrowsingUIManager::UnsafeResource::~UnsafeResource() { }
74 // SafeBrowsingUIManager -------------------------------------------------------
76 SafeBrowsingUIManager::SafeBrowsingUIManager(
77 const scoped_refptr<SafeBrowsingService>& service)
78 : sb_service_(service) {
81 SafeBrowsingUIManager::~SafeBrowsingUIManager() {}
83 void SafeBrowsingUIManager::StopOnIOThread(bool shutdown) {
84 DCHECK_CURRENTLY_ON(BrowserThread::IO);
86 if (shutdown)
87 sb_service_ = NULL;
90 void SafeBrowsingUIManager::LogPauseDelay(base::TimeDelta time) {
91 UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time);
94 // Only report SafeBrowsing related stats when UMA is enabled. User must also
95 // ensure that safe browsing is enabled from the calling profile.
96 bool SafeBrowsingUIManager::CanReportStats() const {
97 const metrics::MetricsService* metrics = g_browser_process->metrics_service();
98 return metrics && metrics->reporting_active();
101 void SafeBrowsingUIManager::OnBlockingPageDone(
102 const std::vector<UnsafeResource>& resources,
103 bool proceed) {
104 DCHECK_CURRENTLY_ON(BrowserThread::IO);
105 for (std::vector<UnsafeResource>::const_iterator iter = resources.begin();
106 iter != resources.end(); ++iter) {
107 const UnsafeResource& resource = *iter;
108 if (!resource.callback.is_null())
109 resource.callback.Run(proceed);
111 if (proceed) {
112 BrowserThread::PostTask(
113 BrowserThread::UI, FROM_HERE,
114 base::Bind(&SafeBrowsingUIManager::AddToWhitelist, this, resource));
119 void SafeBrowsingUIManager::DisplayBlockingPage(
120 const UnsafeResource& resource) {
121 DCHECK_CURRENTLY_ON(BrowserThread::UI);
122 if (resource.is_subresource && !resource.is_subframe) {
123 // Sites tagged as serving Unwanted Software should only show a warning for
124 // main-frame or sub-frame resource. Similar warning restrictions should be
125 // applied to malware sites tagged as "landing sites" (see "Types of
126 // Malware sites" under
127 // https://developers.google.com/safe-browsing/developers_guide_v3#UserWarnings).
128 safe_browsing::MalwarePatternType proto;
129 if (resource.threat_type == SB_THREAT_TYPE_URL_UNWANTED ||
130 (resource.threat_type == SB_THREAT_TYPE_URL_MALWARE &&
131 !resource.threat_metadata.empty() &&
132 proto.ParseFromString(resource.threat_metadata) &&
133 proto.pattern_type() == safe_browsing::MalwarePatternType::LANDING)) {
134 if (!resource.callback.is_null()) {
135 BrowserThread::PostTask(
136 BrowserThread::IO, FROM_HERE, base::Bind(resource.callback, true));
138 return;
142 // Indicate to interested observers that the resource in question matched the
143 // SB filters.
144 if (resource.threat_type != SB_THREAT_TYPE_SAFE) {
145 FOR_EACH_OBSERVER(Observer, observer_list_, OnSafeBrowsingMatch(resource));
148 // The tab might have been closed. If it was closed, just act as if "Don't
149 // Proceed" had been chosen.
150 WebContents* web_contents =
151 tab_util::GetWebContentsByID(resource.render_process_host_id,
152 resource.render_view_id);
153 if (!web_contents) {
154 std::vector<UnsafeResource> resources;
155 resources.push_back(resource);
156 BrowserThread::PostTask(
157 BrowserThread::IO, FROM_HERE,
158 base::Bind(&SafeBrowsingUIManager::OnBlockingPageDone,
159 this, resources, false));
160 return;
163 // Check if the user has already ignored a SB warning for the same WebContents
164 // and top-level domain.
165 if (IsWhitelisted(resource)) {
166 if (!resource.callback.is_null()) {
167 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
168 base::Bind(resource.callback, true));
170 return;
173 if (resource.threat_type != SB_THREAT_TYPE_SAFE &&
174 CanReportStats()) {
175 GURL page_url = web_contents->GetURL();
176 GURL referrer_url;
177 NavigationEntry* entry = web_contents->GetController().GetActiveEntry();
178 if (entry)
179 referrer_url = entry->GetReferrer().url;
181 // When the malicious url is on the main frame, and resource.original_url
182 // is not the same as the resource.url, that means we have a redirect from
183 // resource.original_url to resource.url.
184 // Also, at this point, page_url points to the _previous_ page that we
185 // were on. We replace page_url with resource.original_url and referrer
186 // with page_url.
187 if (!resource.is_subresource &&
188 !resource.original_url.is_empty() &&
189 resource.original_url != resource.url) {
190 referrer_url = page_url;
191 page_url = resource.original_url;
194 Profile* profile =
195 Profile::FromBrowserContext(web_contents->GetBrowserContext());
196 bool is_extended_reporting =
197 profile &&
198 profile->GetPrefs()->GetBoolean(
199 prefs::kSafeBrowsingExtendedReportingEnabled);
201 ReportSafeBrowsingHit(resource.url, page_url, referrer_url,
202 resource.is_subresource, resource.threat_type,
203 std::string(), /* post_data */
204 is_extended_reporting);
207 if (resource.threat_type != SB_THREAT_TYPE_SAFE) {
208 FOR_EACH_OBSERVER(Observer, observer_list_, OnSafeBrowsingHit(resource));
210 SafeBrowsingBlockingPage::ShowBlockingPage(this, resource);
213 // A safebrowsing hit is sent after a blocking page for malware/phishing
214 // or after the warning dialog for download urls, only for UMA users.
215 void SafeBrowsingUIManager::ReportSafeBrowsingHit(const GURL& malicious_url,
216 const GURL& page_url,
217 const GURL& referrer_url,
218 bool is_subresource,
219 SBThreatType threat_type,
220 const std::string& post_data,
221 bool is_extended_reporting) {
222 DCHECK_CURRENTLY_ON(BrowserThread::UI);
223 if (!CanReportStats())
224 return;
225 BrowserThread::PostTask(
226 BrowserThread::IO, FROM_HERE,
227 base::Bind(&SafeBrowsingUIManager::ReportSafeBrowsingHitOnIOThread, this,
228 malicious_url, page_url, referrer_url, is_subresource,
229 threat_type, post_data, is_extended_reporting));
232 void SafeBrowsingUIManager::ReportInvalidCertificateChain(
233 const std::string& serialized_report,
234 const base::Closure& callback) {
235 DCHECK_CURRENTLY_ON(BrowserThread::UI);
236 BrowserThread::PostTaskAndReply(
237 BrowserThread::IO, FROM_HERE,
238 base::Bind(
239 &SafeBrowsingUIManager::ReportInvalidCertificateChainOnIOThread, this,
240 serialized_report),
241 callback);
244 void SafeBrowsingUIManager::AddObserver(Observer* observer) {
245 DCHECK_CURRENTLY_ON(BrowserThread::UI);
246 observer_list_.AddObserver(observer);
249 void SafeBrowsingUIManager::RemoveObserver(Observer* observer) {
250 DCHECK_CURRENTLY_ON(BrowserThread::UI);
251 observer_list_.RemoveObserver(observer);
254 void SafeBrowsingUIManager::ReportSafeBrowsingHitOnIOThread(
255 const GURL& malicious_url,
256 const GURL& page_url,
257 const GURL& referrer_url,
258 bool is_subresource,
259 SBThreatType threat_type,
260 const std::string& post_data,
261 bool is_extended_reporting) {
262 DCHECK_CURRENTLY_ON(BrowserThread::IO);
264 // The service may delete the ping manager (i.e. when user disabling service,
265 // etc). This happens on the IO thread.
266 if (sb_service_.get() == NULL || sb_service_->ping_manager() == NULL)
267 return;
269 DVLOG(1) << "ReportSafeBrowsingHit: " << malicious_url << " " << page_url
270 << " " << referrer_url << " " << is_subresource << " "
271 << threat_type;
272 sb_service_->ping_manager()->ReportSafeBrowsingHit(
273 malicious_url, page_url, referrer_url, is_subresource, threat_type,
274 post_data, is_extended_reporting);
277 void SafeBrowsingUIManager::ReportInvalidCertificateChainOnIOThread(
278 const std::string& serialized_report) {
279 DCHECK_CURRENTLY_ON(BrowserThread::IO);
281 // The service may delete the ping manager (i.e. when user disabling service,
282 // etc). This happens on the IO thread.
283 if (!sb_service_ || !sb_service_->ping_manager())
284 return;
286 sb_service_->ping_manager()->ReportInvalidCertificateChain(serialized_report);
289 // If the user had opted-in to send MalwareDetails, this gets called
290 // when the report is ready.
291 void SafeBrowsingUIManager::SendSerializedMalwareDetails(
292 const std::string& serialized) {
293 DCHECK_CURRENTLY_ON(BrowserThread::IO);
295 // The service may delete the ping manager (i.e. when user disabling service,
296 // etc). This happens on the IO thread.
297 if (sb_service_.get() == NULL || sb_service_->ping_manager() == NULL)
298 return;
300 if (!serialized.empty()) {
301 DVLOG(1) << "Sending serialized malware details.";
302 sb_service_->ping_manager()->ReportMalwareDetails(serialized);
306 // Whitelist this domain in the current WebContents. Either add the
307 // domain to an existing WhitelistUrlSet, or create a new WhitelistUrlSet.
308 void SafeBrowsingUIManager::AddToWhitelist(const UnsafeResource& resource) {
309 DCHECK_CURRENTLY_ON(BrowserThread::UI);
310 WebContents* web_contents = tab_util::GetWebContentsByID(
311 resource.render_process_host_id, resource.render_view_id);
313 WhitelistUrlSet* site_list =
314 static_cast<WhitelistUrlSet*>(web_contents->GetUserData(kWhitelistKey));
315 if (!site_list) {
316 site_list = new WhitelistUrlSet;
317 web_contents->SetUserData(kWhitelistKey, site_list);
320 GURL whitelisted_url(resource.is_subresource ? web_contents->GetVisibleURL()
321 : resource.url);
322 site_list->Insert(whitelisted_url);
325 // Check if the user has already ignored a SB warning for this WebContents and
326 // top-level domain.
327 bool SafeBrowsingUIManager::IsWhitelisted(const UnsafeResource& resource) {
328 DCHECK_CURRENTLY_ON(BrowserThread::UI);
329 WebContents* web_contents = tab_util::GetWebContentsByID(
330 resource.render_process_host_id, resource.render_view_id);
332 GURL maybe_whitelisted_url(
333 resource.is_subresource ? web_contents->GetVisibleURL() : resource.url);
334 WhitelistUrlSet* site_list =
335 static_cast<WhitelistUrlSet*>(web_contents->GetUserData(kWhitelistKey));
336 if (!site_list)
337 return false;
338 return site_list->Contains(maybe_whitelisted_url);