Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(271)

Side by Side Diff: components/safe_browsing/base_safe_browsing_blocking_page.cc

Issue 2623733002: Componentize SafeBrowsingBlockingPage for WebView use (Closed)
Patch Set: address comments from ntfischer Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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.
4 //
5 // Implementation of the BaseSafeBrowsingBlockingPage class.
6
7 #include "components/safe_browsing/base_safe_browsing_blocking_page.h"
8
9 #include "base/bind.h"
10 #include "base/lazy_instance.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/time/time.h"
14 #include "components/safe_browsing_db/safe_browsing_prefs.h"
15 #include "components/security_interstitials/content/security_interstitial_contro ller_client.h"
16 #include "components/security_interstitials/core/metrics_helper.h"
17 #include "content/public/browser/interstitial_page.h"
18 #include "content/public/browser/navigation_entry.h"
19 #include "content/public/browser/user_metrics.h"
20 #include "content/public/browser/web_contents.h"
21
22 using base::UserMetricsAction;
23 using content::InterstitialPage;
24 using content::WebContents;
25 using security_interstitials::SafeBrowsingErrorUI;
26 using security_interstitials::SecurityInterstitialControllerClient;
27
28 namespace safe_browsing {
29
30 namespace {
31
32 base::LazyInstance<BaseSafeBrowsingBlockingPage::UnsafeResourceMap>
33 g_unsafe_resource_map = LAZY_INSTANCE_INITIALIZER;
meacer 2017/01/10 21:18:21 You can make this leaky so that it's not destructe
Jialiu Lin 2017/01/11 00:50:06 Good to know. Thanks!
34
35 } // namespace
36
37 BaseSafeBrowsingBlockingPage::BaseSafeBrowsingBlockingPage(
38 BaseSafeBrowsingUIManager* ui_manager,
39 WebContents* web_contents,
40 const GURL& main_frame_url,
41 const UnsafeResourceList& unsafe_resources,
42 std::unique_ptr<SecurityInterstitialControllerClient> controller_client,
43 SafeBrowsingErrorUI::SBErrorDisplayOptions* display_options)
44 : SecurityInterstitialPage(web_contents,
45 unsafe_resources[0].url,
meacer 2017/01/10 21:18:20 nit: While you are at it, I wonder if it makes sen
Jialiu Lin 2017/01/11 00:50:06 Good thinking. Let's come back to this idea later,
46 std::move(controller_client)),
47 ui_manager_(ui_manager),
48 main_frame_url_(main_frame_url),
meacer 2017/01/10 21:18:21 Actually, it looks like we have two URLs here: uns
Jialiu Lin 2017/01/11 00:50:06 No, they can be different things. For example, if
meacer 2017/01/11 01:33:30 Sounds good, thanks for updating SecurityInterstit
49 unsafe_resources_(unsafe_resources),
50 proceeded_(false) {
51 if (display_options) {
52 sb_error_ui_ = base::MakeUnique<SafeBrowsingErrorUI>(
vakh (use Gerrit instead) 2017/01/10 20:44:26 To avoid repetition, re-write as: sb_error_ui_ =
Jialiu Lin 2017/01/11 00:50:05 Done. Thanks!
53 unsafe_resources_[0].url, main_frame_url_,
meacer 2017/01/10 21:18:20 Same here, would be nice to use only one of these.
Jialiu Lin 2017/01/11 00:50:06 Similar to the above, they could be different URLs
meacer 2017/01/11 01:33:30 Acknowledged.
54 GetInterstitialReason(unsafe_resources_), *display_options,
55 ui_manager_->app_locale(), base::Time::NowFromSystemTime(),
56 controller());
57 } else {
58 sb_error_ui_ = base::MakeUnique<SafeBrowsingErrorUI>(
59 unsafe_resources_[0].url, main_frame_url_,
60 GetInterstitialReason(unsafe_resources_),
61 CreateDefaultDisplayOptions(unsafe_resources),
62 ui_manager_->app_locale(), base::Time::NowFromSystemTime(),
63 controller());
meacer 2017/01/10 21:18:21 It could be slightly cleaner to create display_opt
Jialiu Lin 2017/01/11 00:50:06 Done.
64 }
65
66 if (!IsMainPageLoadBlocked(unsafe_resources)) {
67 navigation_entry_index_to_remove_ =
68 web_contents->GetController().GetLastCommittedEntryIndex();
69 } else {
70 navigation_entry_index_to_remove_ = -1;
meacer 2017/01/10 21:18:21 nit: I wonder if navigation_entry_index_to_remove_
Jialiu Lin 2017/01/11 00:50:06 You're right. Done.
71 }
72 }
73
74 BaseSafeBrowsingBlockingPage::~BaseSafeBrowsingBlockingPage() {}
75
76 // static
77 BaseSafeBrowsingBlockingPage* BaseSafeBrowsingBlockingPage::CreateBlockingPage(
78 BaseSafeBrowsingUIManager* ui_manager,
79 WebContents* web_contents,
80 const GURL& main_frame_url,
81 const UnsafeResource& unsafe_resource) {
82 std::vector<UnsafeResource> resources;
vakh (use Gerrit instead) 2017/01/10 20:44:26 This should work and avoid the explicit call to pu
Jialiu Lin 2017/01/11 00:50:05 Done.
83 resources.push_back(unsafe_resource);
meacer 2017/01/10 21:18:20 nit: const std::vector<UnsafeResource> resources{
Jialiu Lin 2017/01/11 00:50:06 Done.
84 auto display_options = CreateDefaultDisplayOptions(resources);
meacer 2017/01/10 21:18:20 If you decide to change display_options as a const
Jialiu Lin 2017/01/11 00:50:06 Changed CreateDefaultDisplayOptions(..) to return
85 return new BaseSafeBrowsingBlockingPage(
86 ui_manager, web_contents, main_frame_url, resources,
87 CreateControllerClient(
88 web_contents, resources, ui_manager->history_service(web_contents),
89 ui_manager->app_locale(), ui_manager->default_safe_page()),
90 &display_options);
91 }
92
93 // static
94 void BaseSafeBrowsingBlockingPage::ShowBlockingPage(
95 BaseSafeBrowsingUIManager* ui_manager,
96 const UnsafeResource& unsafe_resource) {
97 DVLOG(1) << __func__ << " " << unsafe_resource.url.spec();
vakh (use Gerrit instead) 2017/01/10 20:44:26 Remove DVLOG?
Jialiu Lin 2017/01/11 00:50:05 Done.
98 WebContents* web_contents = unsafe_resource.web_contents_getter.Run();
99
100 if (!InterstitialPage::GetInterstitialPage(web_contents) ||
101 !unsafe_resource.is_subresource) {
102 // There is no interstitial currently showing in that tab, or we are about
103 // to display a new one for the main frame. If there is already an
104 // interstitial, showing the new one will automatically hide the old one.
105 content::NavigationEntry* entry =
106 unsafe_resource.GetNavigationEntryForResource();
107 BaseSafeBrowsingBlockingPage* blocking_page =
108 CreateBlockingPage(ui_manager, web_contents,
109 entry ? entry->GetURL() : GURL(), unsafe_resource);
110 blocking_page->Show();
111 return;
112 }
113
114 // This is an interstitial for a page's resource, let's queue it.
115 UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
116 (*unsafe_resource_map)[web_contents].push_back(unsafe_resource);
117 }
118
119 // static
120 bool BaseSafeBrowsingBlockingPage::IsMainPageLoadBlocked(
121 const UnsafeResourceList& unsafe_resources) {
122 // If there is more than one unsafe resource, the main page load must not be
123 // blocked. Otherwise, check if the one resource is.
124 return unsafe_resources.size() == 1 &&
125 unsafe_resources[0].IsMainPageLoadBlocked();
126 }
127
128 void BaseSafeBrowsingBlockingPage::OnProceed() {
129 proceeded_ = true;
130
131 ui_manager_->OnBlockingPageDone(unsafe_resources_, true, web_contents(),
vakh (use Gerrit instead) 2017/01/10 20:44:26 Add: /* proceed */
Jialiu Lin 2017/01/11 00:50:06 Done.
132 main_frame_url_);
133 }
134
135 void BaseSafeBrowsingBlockingPage::OnDontProceed() {
136 // We could have already called Proceed(), in which case we must not notify
137 // the SafeBrowsingUIManager again, as the client has been deleted.
138 if (proceeded_)
139 return;
140
141 if (!sb_error_ui_->is_proceed_anyway_disabled()) {
142 controller()->metrics_helper()->RecordUserDecision(
143 security_interstitials::MetricsHelper::DONT_PROCEED);
144 }
145
146 // Send the malware details, if we opted to.
147 FinishThreatDetails(0, false /* did_proceed */,
148 controller()->metrics_helper()->NumVisits()); // No delay
149
150 ui_manager_->OnBlockingPageDone(unsafe_resources_, false, web_contents(),
vakh (use Gerrit instead) 2017/01/10 20:44:26 Add: /* proceed */
Jialiu Lin 2017/01/11 00:50:05 Done.
151 main_frame_url_);
152
153 // The user does not want to proceed, clear the queued unsafe resources
154 // notifications we received while the interstitial was showing.
155 UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
156 UnsafeResourceMap::iterator iter = unsafe_resource_map->find(web_contents());
157 if (iter != unsafe_resource_map->end() && !iter->second.empty()) {
158 ui_manager_->OnBlockingPageDone(iter->second, false, web_contents(),
159 main_frame_url_);
160 unsafe_resource_map->erase(iter);
161 }
162
163 // We don't remove the navigation entry if the tab is being destroyed as this
164 // would trigger a navigation that would cause trouble as the render view host
165 // for the tab has by then already been destroyed. We also don't delete the
166 // current entry if it has been committed again, which is possible on a page
167 // that had a subresource warning.
168 int last_committed_index =
169 web_contents()->GetController().GetLastCommittedEntryIndex();
170 if (navigation_entry_index_to_remove_ != -1 &&
171 navigation_entry_index_to_remove_ != last_committed_index &&
172 !web_contents()->IsBeingDestroyed()) {
173 CHECK(web_contents()->GetController().RemoveEntryAtIndex(
174 navigation_entry_index_to_remove_));
175 navigation_entry_index_to_remove_ = -1;
meacer 2017/01/10 21:18:21 nit: As I mentioned above, I wonder if this is nec
Jialiu Lin 2017/01/11 00:50:05 You're right. the final assignment of navigation_e
176 }
177 }
178
179 void BaseSafeBrowsingBlockingPage::CommandReceived(
180 const std::string& page_cmd) {
181 if (page_cmd == "\"pageLoadComplete\"") {
182 // content::WaitForRenderFrameReady sends this message when the page
183 // load completes. Ignore it.
184 return;
185 }
186
187 int command = 0;
188 bool retval = base::StringToInt(page_cmd, &command);
189 DCHECK(retval) << page_cmd;
190
191 sb_error_ui_->HandleCommand(
192 static_cast<security_interstitials::SecurityInterstitialCommands>(
193 command));
194 }
195
196 bool BaseSafeBrowsingBlockingPage::ShouldCreateNewNavigation() const {
197 return sb_error_ui_->is_main_frame_load_blocked();
198 }
199
200 void BaseSafeBrowsingBlockingPage::PopulateInterstitialStrings(
201 base::DictionaryValue* load_time_data) {
202 sb_error_ui_->PopulateStringsForHTML(load_time_data);
203 }
204
205 void BaseSafeBrowsingBlockingPage::FinishThreatDetails(int64_t delay_ms,
206 bool did_proceed,
207 int num_visits) {}
208
209 // static
210 BaseSafeBrowsingBlockingPage::UnsafeResourceMap*
211 BaseSafeBrowsingBlockingPage::GetUnsafeResourcesMap() {
212 return g_unsafe_resource_map.Pointer();
213 }
214
215
216 // static
217 std::string BaseSafeBrowsingBlockingPage::GetMetricPrefix(
218 const UnsafeResourceList& unsafe_resources,
219 SafeBrowsingErrorUI::SBInterstitialReason interstitial_reason) {
220 bool primary_subresource = unsafe_resources[0].is_subresource;
221 switch (interstitial_reason) {
222 case SafeBrowsingErrorUI::SB_REASON_MALWARE:
223 return primary_subresource ? "malware_subresource" : "malware";
224 case SafeBrowsingErrorUI::SB_REASON_HARMFUL:
225 return primary_subresource ? "harmful_subresource" : "harmful";
226 case SafeBrowsingErrorUI::SB_REASON_PHISHING:
227 ThreatPatternType threat_pattern_type =
228 unsafe_resources[0].threat_metadata.threat_pattern_type;
229 if (threat_pattern_type == ThreatPatternType::PHISHING ||
230 threat_pattern_type == ThreatPatternType::NONE)
231 return primary_subresource ? "phishing_subresource" : "phishing";
232 else if (threat_pattern_type == ThreatPatternType::SOCIAL_ENGINEERING_ADS)
233 return primary_subresource ? "social_engineering_ads_subresource"
234 : "social_engineering_ads";
235 else if (threat_pattern_type ==
236 ThreatPatternType::SOCIAL_ENGINEERING_LANDING)
237 return primary_subresource ? "social_engineering_landing_subresource"
238 : "social_engineering_landing";
239 }
240 NOTREACHED();
241 return "unkown_metric_prefix";
242 }
243
244 // We populate a parallel set of metrics to differentiate some threat sources.
245 // static
246 std::string BaseSafeBrowsingBlockingPage::GetExtraMetricsSuffix(
247 const UnsafeResourceList& unsafe_resources) {
248 switch (unsafe_resources[0].threat_source) {
249 case safe_browsing::ThreatSource::DATA_SAVER:
250 return "from_data_saver";
251 case safe_browsing::ThreatSource::REMOTE:
252 case safe_browsing::ThreatSource::LOCAL_PVER3:
253 // REMOTE and LOCAL_PVER3 can be distinguished in the logs
254 // by platform type: Remote is mobile, local_pver3 is desktop.
255 return "from_device";
256 case safe_browsing::ThreatSource::LOCAL_PVER4:
257 return "from_device_v4";
258 case safe_browsing::ThreatSource::CLIENT_SIDE_DETECTION:
259 return "from_client_side_detection";
260 case safe_browsing::ThreatSource::UNKNOWN:
261 break;
262 }
263 NOTREACHED();
264 return std::string();
265 }
266
267 // static
268 SafeBrowsingErrorUI::SBInterstitialReason
269 BaseSafeBrowsingBlockingPage::GetInterstitialReason(
270 const UnsafeResourceList& unsafe_resources) {
271 bool malware = false;
272 bool harmful = false;
273 bool phishing = false;
274 for (UnsafeResourceList::const_iterator iter = unsafe_resources.begin();
275 iter != unsafe_resources.end(); ++iter) {
276 const BaseSafeBrowsingUIManager::UnsafeResource& resource = *iter;
277 safe_browsing::SBThreatType threat_type = resource.threat_type;
278 if (threat_type == SB_THREAT_TYPE_URL_MALWARE ||
279 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) {
280 malware = true;
vakh (use Gerrit instead) 2017/01/10 20:44:26 You could shortcut the method here with: return Sa
Jialiu Lin 2017/01/11 00:50:06 You're right. I just copied it down without taking
281 } else if (threat_type == SB_THREAT_TYPE_URL_UNWANTED) {
282 harmful = true;
283 } else {
284 DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING ||
285 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
286 phishing = true;
287 }
288 }
289 DCHECK(phishing || malware || harmful);
290 if (malware)
291 return SafeBrowsingErrorUI::SB_REASON_MALWARE;
292 else if (harmful)
293 return SafeBrowsingErrorUI::SB_REASON_HARMFUL;
294 return SafeBrowsingErrorUI::SB_REASON_PHISHING;
295 }
296
297 // static
298 std::unique_ptr<SecurityInterstitialControllerClient>
299 BaseSafeBrowsingBlockingPage::CreateControllerClient(
300 content::WebContents* web_contents,
301 const UnsafeResourceList& unsafe_resources,
302 history::HistoryService* history_service,
303 const std::string& app_locale,
304 const GURL& default_safe_page) {
305 SafeBrowsingErrorUI::SBInterstitialReason interstitial_reason =
306 GetInterstitialReason(unsafe_resources);
307 GURL request_url(unsafe_resources[0].url);
vakh (use Gerrit instead) 2017/01/10 20:44:26 request_url is only being used in one place so we
Jialiu Lin 2017/01/11 00:50:06 Done.
308 security_interstitials::MetricsHelper::ReportDetails reporting_info;
309 reporting_info.metric_prefix =
310 GetMetricPrefix(unsafe_resources, interstitial_reason);
311 reporting_info.extra_suffix = GetExtraMetricsSuffix(unsafe_resources);
312
313 std::unique_ptr<security_interstitials::MetricsHelper> metrics_helper =
314 base::MakeUnique<security_interstitials::MetricsHelper>(
315 request_url, reporting_info, history_service);
316
317 return base::MakeUnique<SecurityInterstitialControllerClient>(
318 web_contents, std::move(metrics_helper), nullptr, app_locale,
319 default_safe_page);
320 }
321
322 // static
323 const SafeBrowsingErrorUI::SBErrorDisplayOptions
324 BaseSafeBrowsingBlockingPage::CreateDefaultDisplayOptions(
325 const UnsafeResourceList& unsafe_resources) {
326 SafeBrowsingErrorUI::SBErrorDisplayOptions display_options(
327 IsMainPageLoadBlocked(unsafe_resources),
328 true, // kSafeBrowsingExtendedReportingOptInAllowed
329 false, // is_off_the_record
330 false, // is_extended_reporting
331 false, // is_scout
332 false); // kSafeBrowsingProceedAnywayDisabled
333 return display_options;
vakh (use Gerrit instead) 2017/01/10 20:44:26 directly return?
Jialiu Lin 2017/01/11 00:50:05 Sure. Done.
334 }
335
336 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698