Add ICU message format support
[chromium-blink-merge.git] / chrome / browser / safe_browsing / ui_manager.cc
blobdbf729b06a1accb378895331934c3d9e7fed32f6
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 struct SafeBrowsingUIManager::WhiteListedEntry {
41 int render_process_host_id;
42 int render_view_id;
43 std::string domain;
44 SBThreatType threat_type;
47 SafeBrowsingUIManager::UnsafeResource::UnsafeResource()
48 : is_subresource(false),
49 threat_type(SB_THREAT_TYPE_SAFE),
50 render_process_host_id(-1),
51 render_view_id(-1) {
54 SafeBrowsingUIManager::UnsafeResource::~UnsafeResource() { }
56 SafeBrowsingUIManager::SafeBrowsingUIManager(
57 const scoped_refptr<SafeBrowsingService>& service)
58 : sb_service_(service) {
61 SafeBrowsingUIManager::~SafeBrowsingUIManager() { }
63 void SafeBrowsingUIManager::StopOnIOThread(bool shutdown) {
64 DCHECK_CURRENTLY_ON(BrowserThread::IO);
66 if (shutdown)
67 sb_service_ = NULL;
70 void SafeBrowsingUIManager::LogPauseDelay(base::TimeDelta time) {
71 UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time);
74 // Only report SafeBrowsing related stats when UMA is enabled. User must also
75 // ensure that safe browsing is enabled from the calling profile.
76 bool SafeBrowsingUIManager::CanReportStats() const {
77 const metrics::MetricsService* metrics = g_browser_process->metrics_service();
78 return metrics && metrics->reporting_active();
81 void SafeBrowsingUIManager::OnBlockingPageDone(
82 const std::vector<UnsafeResource>& resources,
83 bool proceed) {
84 DCHECK_CURRENTLY_ON(BrowserThread::IO);
85 for (std::vector<UnsafeResource>::const_iterator iter = resources.begin();
86 iter != resources.end(); ++iter) {
87 const UnsafeResource& resource = *iter;
88 if (!resource.callback.is_null())
89 resource.callback.Run(proceed);
91 if (proceed) {
92 BrowserThread::PostTask(
93 BrowserThread::UI,
94 FROM_HERE,
95 base::Bind(&SafeBrowsingUIManager::UpdateWhitelist, this, resource));
100 void SafeBrowsingUIManager::DisplayBlockingPage(
101 const UnsafeResource& resource) {
102 DCHECK_CURRENTLY_ON(BrowserThread::UI);
103 if (resource.is_subresource && !resource.is_subframe) {
104 // Sites tagged as serving Unwanted Software should only show a warning for
105 // main-frame or sub-frame resource. Similar warning restrictions should be
106 // applied to malware sites tagged as "landing sites" (see "Types of
107 // Malware sites" under
108 // https://developers.google.com/safe-browsing/developers_guide_v3#UserWarnings).
109 safe_browsing::MalwarePatternType proto;
110 if (resource.threat_type == SB_THREAT_TYPE_URL_UNWANTED ||
111 (resource.threat_type == SB_THREAT_TYPE_URL_MALWARE &&
112 !resource.threat_metadata.empty() &&
113 proto.ParseFromString(resource.threat_metadata) &&
114 proto.pattern_type() == safe_browsing::MalwarePatternType::LANDING)) {
115 if (!resource.callback.is_null()) {
116 BrowserThread::PostTask(
117 BrowserThread::IO, FROM_HERE, base::Bind(resource.callback, true));
119 return;
123 // Indicate to interested observers that the resource in question matched the
124 // SB filters.
125 if (resource.threat_type != SB_THREAT_TYPE_SAFE) {
126 FOR_EACH_OBSERVER(Observer, observer_list_, OnSafeBrowsingMatch(resource));
129 // Check if the user has already ignored our warning for this render_view
130 // and domain.
131 if (IsWhitelisted(resource)) {
132 if (!resource.callback.is_null()) {
133 BrowserThread::PostTask(
134 BrowserThread::IO, FROM_HERE, base::Bind(resource.callback, true));
136 return;
139 // The tab might have been closed.
140 WebContents* web_contents =
141 tab_util::GetWebContentsByID(resource.render_process_host_id,
142 resource.render_view_id);
144 if (!web_contents) {
145 // The tab is gone and we did not have a chance at showing the interstitial.
146 // Just act as if "Don't Proceed" were chosen.
147 std::vector<UnsafeResource> resources;
148 resources.push_back(resource);
149 BrowserThread::PostTask(
150 BrowserThread::IO, FROM_HERE,
151 base::Bind(&SafeBrowsingUIManager::OnBlockingPageDone,
152 this, resources, false));
153 return;
156 Profile* profile =
157 Profile::FromBrowserContext(web_contents->GetBrowserContext());
158 bool is_extended_reporting =
159 profile &&
160 profile->GetPrefs()->GetBoolean(
161 prefs::kSafeBrowsingExtendedReportingEnabled);
162 if (resource.threat_type != SB_THREAT_TYPE_SAFE &&
163 CanReportStats()) {
164 GURL page_url = web_contents->GetURL();
165 GURL referrer_url;
166 NavigationEntry* entry = web_contents->GetController().GetActiveEntry();
167 if (entry)
168 referrer_url = entry->GetReferrer().url;
170 // When the malicious url is on the main frame, and resource.original_url
171 // is not the same as the resource.url, that means we have a redirect from
172 // resource.original_url to resource.url.
173 // Also, at this point, page_url points to the _previous_ page that we
174 // were on. We replace page_url with resource.original_url and referrer
175 // with page_url.
176 if (!resource.is_subresource &&
177 !resource.original_url.is_empty() &&
178 resource.original_url != resource.url) {
179 referrer_url = page_url;
180 page_url = resource.original_url;
183 ReportSafeBrowsingHit(resource.url, page_url, referrer_url,
184 resource.is_subresource, resource.threat_type,
185 std::string(), /* post_data */
186 is_extended_reporting);
189 if (resource.threat_type != SB_THREAT_TYPE_SAFE) {
190 FOR_EACH_OBSERVER(Observer, observer_list_, OnSafeBrowsingHit(resource));
192 SafeBrowsingBlockingPage::ShowBlockingPage(this, resource);
195 // A safebrowsing hit is sent after a blocking page for malware/phishing
196 // or after the warning dialog for download urls, only for UMA users.
197 void SafeBrowsingUIManager::ReportSafeBrowsingHit(const GURL& malicious_url,
198 const GURL& page_url,
199 const GURL& referrer_url,
200 bool is_subresource,
201 SBThreatType threat_type,
202 const std::string& post_data,
203 bool is_extended_reporting) {
204 DCHECK_CURRENTLY_ON(BrowserThread::UI);
205 if (!CanReportStats())
206 return;
207 BrowserThread::PostTask(
208 BrowserThread::IO, FROM_HERE,
209 base::Bind(&SafeBrowsingUIManager::ReportSafeBrowsingHitOnIOThread, this,
210 malicious_url, page_url, referrer_url, is_subresource,
211 threat_type, post_data, is_extended_reporting));
214 void SafeBrowsingUIManager::ReportInvalidCertificateChain(
215 const std::string& serialized_report,
216 const base::Closure& callback) {
217 DCHECK_CURRENTLY_ON(BrowserThread::UI);
218 BrowserThread::PostTaskAndReply(
219 BrowserThread::IO, FROM_HERE,
220 base::Bind(
221 &SafeBrowsingUIManager::ReportInvalidCertificateChainOnIOThread, this,
222 serialized_report),
223 callback);
226 void SafeBrowsingUIManager::AddObserver(Observer* observer) {
227 DCHECK_CURRENTLY_ON(BrowserThread::UI);
228 observer_list_.AddObserver(observer);
231 void SafeBrowsingUIManager::RemoveObserver(Observer* observer) {
232 DCHECK_CURRENTLY_ON(BrowserThread::UI);
233 observer_list_.RemoveObserver(observer);
236 void SafeBrowsingUIManager::ReportSafeBrowsingHitOnIOThread(
237 const GURL& malicious_url,
238 const GURL& page_url,
239 const GURL& referrer_url,
240 bool is_subresource,
241 SBThreatType threat_type,
242 const std::string& post_data,
243 bool is_extended_reporting) {
244 DCHECK_CURRENTLY_ON(BrowserThread::IO);
246 // The service may delete the ping manager (i.e. when user disabling service,
247 // etc). This happens on the IO thread.
248 if (sb_service_.get() == NULL || sb_service_->ping_manager() == NULL)
249 return;
251 DVLOG(1) << "ReportSafeBrowsingHit: " << malicious_url << " " << page_url
252 << " " << referrer_url << " " << is_subresource << " "
253 << threat_type;
254 sb_service_->ping_manager()->ReportSafeBrowsingHit(
255 malicious_url, page_url, referrer_url, is_subresource, threat_type,
256 post_data, is_extended_reporting);
259 void SafeBrowsingUIManager::ReportInvalidCertificateChainOnIOThread(
260 const std::string& serialized_report) {
261 DCHECK_CURRENTLY_ON(BrowserThread::IO);
263 // The service may delete the ping manager (i.e. when user disabling service,
264 // etc). This happens on the IO thread.
265 if (!sb_service_ || !sb_service_->ping_manager())
266 return;
268 sb_service_->ping_manager()->ReportInvalidCertificateChain(serialized_report);
271 // If the user had opted-in to send MalwareDetails, this gets called
272 // when the report is ready.
273 void SafeBrowsingUIManager::SendSerializedMalwareDetails(
274 const std::string& serialized) {
275 DCHECK_CURRENTLY_ON(BrowserThread::IO);
277 // The service may delete the ping manager (i.e. when user disabling service,
278 // etc). This happens on the IO thread.
279 if (sb_service_.get() == NULL || sb_service_->ping_manager() == NULL)
280 return;
282 if (!serialized.empty()) {
283 DVLOG(1) << "Sending serialized malware details.";
284 sb_service_->ping_manager()->ReportMalwareDetails(serialized);
288 void SafeBrowsingUIManager::UpdateWhitelist(const UnsafeResource& resource) {
289 DCHECK_CURRENTLY_ON(BrowserThread::UI);
290 // Whitelist this domain and warning type for the given tab.
291 WhiteListedEntry entry;
292 entry.render_process_host_id = resource.render_process_host_id;
293 entry.render_view_id = resource.render_view_id;
294 entry.domain = net::registry_controlled_domains::GetDomainAndRegistry(
295 resource.url,
296 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
297 entry.threat_type = resource.threat_type;
298 white_listed_entries_.push_back(entry);
301 bool SafeBrowsingUIManager::IsWhitelisted(const UnsafeResource& resource) {
302 DCHECK_CURRENTLY_ON(BrowserThread::UI);
303 // Check if the user has already ignored our warning for this render_view
304 // and domain.
305 for (size_t i = 0; i < white_listed_entries_.size(); ++i) {
306 const WhiteListedEntry& entry = white_listed_entries_[i];
307 if (entry.render_process_host_id == resource.render_process_host_id &&
308 entry.render_view_id == resource.render_view_id) {
309 return entry.domain ==
310 net::registry_controlled_domains::GetDomainAndRegistry(
311 resource.url,
312 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
315 return false;