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

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

Issue 2623733002: Componentize SafeBrowsingBlockingPage for WebView use (Closed)
Patch Set: rebase again + nits 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 #include "components/safe_browsing/base_blocking_page.h"
6
7 #include "base/bind.h"
8 #include "base/lazy_instance.h"
9 #include "base/memory/ptr_util.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/time/time.h"
12 #include "components/safe_browsing_db/safe_browsing_prefs.h"
13 #include "components/security_interstitials/content/security_interstitial_contro ller_client.h"
14 #include "components/security_interstitials/core/metrics_helper.h"
15 #include "content/public/browser/interstitial_page.h"
16 #include "content/public/browser/navigation_entry.h"
17 #include "content/public/browser/user_metrics.h"
18 #include "content/public/browser/web_contents.h"
19
20 using base::UserMetricsAction;
21 using content::InterstitialPage;
22 using content::WebContents;
23 using security_interstitials::SafeBrowsingErrorUI;
24 using security_interstitials::SecurityInterstitialControllerClient;
25
26 namespace safe_browsing {
27
28 namespace {
29
30 base::LazyInstance<BaseBlockingPage::UnsafeResourceMap>::Leaky
31 g_unsafe_resource_map = LAZY_INSTANCE_INITIALIZER;
32
33 } // namespace
34
35 BaseBlockingPage::BaseBlockingPage(
36 BaseUIManager* ui_manager,
37 WebContents* web_contents,
38 const GURL& main_frame_url,
39 const UnsafeResourceList& unsafe_resources,
40 std::unique_ptr<SecurityInterstitialControllerClient> controller_client,
41 SafeBrowsingErrorUI::SBErrorDisplayOptions* display_options)
meacer 2017/01/11 01:33:30 I'm still not fully convinced |display_options| sh
Jialiu Lin 2017/01/11 02:53:15 Yes, make sense, I'll also make that unit test pas
42 : SecurityInterstitialPage(web_contents,
43 unsafe_resources[0].url,
44 std::move(controller_client)),
45 ui_manager_(ui_manager),
46 main_frame_url_(main_frame_url),
47 navigation_entry_index_to_remove_(
48 IsMainPageLoadBlocked(unsafe_resources) ?
49 -1 :
50 web_contents->GetController().GetLastCommittedEntryIndex()),
51 unsafe_resources_(unsafe_resources),
52 sb_error_ui_(base::MakeUnique<SafeBrowsingErrorUI>(
53 unsafe_resources_[0].url, main_frame_url_,
54 GetInterstitialReason(unsafe_resources_),
55 display_options ?
56 *display_options :
57 *CreateDefaultDisplayOptions(unsafe_resources),
58 ui_manager_->app_locale(),
59 base::Time::NowFromSystemTime(),
60 controller())),
61 proceeded_(false) {}
62
63 BaseBlockingPage::~BaseBlockingPage() {}
64
65 // static
66 BaseBlockingPage* BaseBlockingPage::CreateBlockingPage(
67 BaseUIManager* ui_manager,
68 WebContents* web_contents,
69 const GURL& main_frame_url,
70 const UnsafeResource& unsafe_resource) {
71 const std::vector<UnsafeResource> resources{unsafe_resource};
72 return new BaseBlockingPage(
73 ui_manager, web_contents, main_frame_url, resources,
74 CreateControllerClient(
75 web_contents, resources, ui_manager->history_service(web_contents),
76 ui_manager->app_locale(), ui_manager->default_safe_page()),
77 CreateDefaultDisplayOptions(resources));
78 }
79
80 // static
81 void BaseBlockingPage::ShowBlockingPage(
82 BaseUIManager* ui_manager,
83 const UnsafeResource& unsafe_resource) {
84 WebContents* web_contents = unsafe_resource.web_contents_getter.Run();
85
86 if (!InterstitialPage::GetInterstitialPage(web_contents) ||
87 !unsafe_resource.is_subresource) {
88 // There is no interstitial currently showing in that tab, or we are about
89 // to display a new one for the main frame. If there is already an
90 // interstitial, showing the new one will automatically hide the old one.
91 content::NavigationEntry* entry =
92 unsafe_resource.GetNavigationEntryForResource();
93 BaseBlockingPage* blocking_page =
94 CreateBlockingPage(ui_manager, web_contents,
95 entry ? entry->GetURL() : GURL(), unsafe_resource);
96 blocking_page->Show();
97 return;
98 }
99
100 // This is an interstitial for a page's resource, let's queue it.
101 UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
102 (*unsafe_resource_map)[web_contents].push_back(unsafe_resource);
103 }
104
105 // static
106 bool BaseBlockingPage::IsMainPageLoadBlocked(
107 const UnsafeResourceList& unsafe_resources) {
108 // If there is more than one unsafe resource, the main page load must not be
109 // blocked. Otherwise, check if the one resource is.
110 return unsafe_resources.size() == 1 &&
111 unsafe_resources[0].IsMainPageLoadBlocked();
112 }
113
114 void BaseBlockingPage::OnProceed() {
115 proceeded_ = true;
116
117 ui_manager_->OnBlockingPageDone(unsafe_resources_, true /* proceed */,
118 web_contents(), main_frame_url_);
119 }
120
121 void BaseBlockingPage::OnDontProceed() {
122 // We could have already called Proceed(), in which case we must not notify
123 // the SafeBrowsingUIManager again, as the client has been deleted.
124 if (proceeded_)
125 return;
126
127 if (!sb_error_ui_->is_proceed_anyway_disabled()) {
128 controller()->metrics_helper()->RecordUserDecision(
129 security_interstitials::MetricsHelper::DONT_PROCEED);
130 }
131
132 // Send the malware details, if we opted to.
133 FinishThreatDetails(0, false /* did_proceed */,
134 controller()->metrics_helper()->NumVisits()); // No delay
135
136 ui_manager_->OnBlockingPageDone(unsafe_resources_, false /* proceed */,
137 web_contents(), main_frame_url_);
138
139 // The user does not want to proceed, clear the queued unsafe resources
140 // notifications we received while the interstitial was showing.
141 UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
142 UnsafeResourceMap::iterator iter = unsafe_resource_map->find(web_contents());
143 if (iter != unsafe_resource_map->end() && !iter->second.empty()) {
144 ui_manager_->OnBlockingPageDone(iter->second, false, web_contents(),
145 main_frame_url_);
146 unsafe_resource_map->erase(iter);
147 }
148
149 // We don't remove the navigation entry if the tab is being destroyed as this
150 // would trigger a navigation that would cause trouble as the render view host
151 // for the tab has by then already been destroyed. We also don't delete the
152 // current entry if it has been committed again, which is possible on a page
153 // that had a subresource warning.
154 int last_committed_index =
meacer 2017/01/11 01:33:30 nit: const int
Jialiu Lin 2017/01/11 02:53:15 Done.
155 web_contents()->GetController().GetLastCommittedEntryIndex();
156 if (navigation_entry_index_to_remove_ != -1 &&
157 navigation_entry_index_to_remove_ != last_committed_index &&
158 !web_contents()->IsBeingDestroyed()) {
159 CHECK(web_contents()->GetController().RemoveEntryAtIndex(
160 navigation_entry_index_to_remove_));
161 }
162 }
163
164 void BaseBlockingPage::CommandReceived(
165 const std::string& page_cmd) {
166 if (page_cmd == "\"pageLoadComplete\"") {
167 // content::WaitForRenderFrameReady sends this message when the page
168 // load completes. Ignore it.
169 return;
170 }
171
172 int command = 0;
173 bool retval = base::StringToInt(page_cmd, &command);
174 DCHECK(retval) << page_cmd;
175
176 sb_error_ui_->HandleCommand(
177 static_cast<security_interstitials::SecurityInterstitialCommands>(
178 command));
179 }
180
181 bool BaseBlockingPage::ShouldCreateNewNavigation() const {
182 return sb_error_ui_->is_main_frame_load_blocked();
183 }
184
185 void BaseBlockingPage::PopulateInterstitialStrings(
186 base::DictionaryValue* load_time_data) {
187 sb_error_ui_->PopulateStringsForHTML(load_time_data);
188 }
189
190 void BaseBlockingPage::FinishThreatDetails(int64_t delay_ms,
191 bool did_proceed,
192 int num_visits) {}
193
194 // static
195 BaseBlockingPage::UnsafeResourceMap*
196 BaseBlockingPage::GetUnsafeResourcesMap() {
197 return g_unsafe_resource_map.Pointer();
198 }
199
200 // static
201 std::string BaseBlockingPage::GetMetricPrefix(
202 const UnsafeResourceList& unsafe_resources,
203 SafeBrowsingErrorUI::SBInterstitialReason interstitial_reason) {
204 bool primary_subresource = unsafe_resources[0].is_subresource;
205 switch (interstitial_reason) {
206 case SafeBrowsingErrorUI::SB_REASON_MALWARE:
207 return primary_subresource ? "malware_subresource" : "malware";
208 case SafeBrowsingErrorUI::SB_REASON_HARMFUL:
209 return primary_subresource ? "harmful_subresource" : "harmful";
210 case SafeBrowsingErrorUI::SB_REASON_PHISHING:
211 ThreatPatternType threat_pattern_type =
212 unsafe_resources[0].threat_metadata.threat_pattern_type;
213 if (threat_pattern_type == ThreatPatternType::PHISHING ||
214 threat_pattern_type == ThreatPatternType::NONE)
215 return primary_subresource ? "phishing_subresource" : "phishing";
216 else if (threat_pattern_type == ThreatPatternType::SOCIAL_ENGINEERING_ADS)
217 return primary_subresource ? "social_engineering_ads_subresource"
218 : "social_engineering_ads";
219 else if (threat_pattern_type ==
220 ThreatPatternType::SOCIAL_ENGINEERING_LANDING)
221 return primary_subresource ? "social_engineering_landing_subresource"
222 : "social_engineering_landing";
223 }
224 NOTREACHED();
225 return "unkown_metric_prefix";
226 }
227
228 // We populate a parallel set of metrics to differentiate some threat sources.
229 // static
230 std::string BaseBlockingPage::GetExtraMetricsSuffix(
231 const UnsafeResourceList& unsafe_resources) {
232 switch (unsafe_resources[0].threat_source) {
233 case safe_browsing::ThreatSource::DATA_SAVER:
234 return "from_data_saver";
235 case safe_browsing::ThreatSource::REMOTE:
236 case safe_browsing::ThreatSource::LOCAL_PVER3:
237 // REMOTE and LOCAL_PVER3 can be distinguished in the logs
238 // by platform type: Remote is mobile, local_pver3 is desktop.
239 return "from_device";
240 case safe_browsing::ThreatSource::LOCAL_PVER4:
241 return "from_device_v4";
242 case safe_browsing::ThreatSource::CLIENT_SIDE_DETECTION:
243 return "from_client_side_detection";
244 case safe_browsing::ThreatSource::UNKNOWN:
245 break;
246 }
247 NOTREACHED();
248 return std::string();
249 }
250
251 // static
252 // Return the most severe interstitial reason from a list of unsafe resources.
253 // Severity ranking: malware > UwS (harmful) > phishing.
meacer 2017/01/11 01:33:31 nit: It would be better to put this comment in the
Jialiu Lin 2017/01/11 02:53:15 Done.
254 SafeBrowsingErrorUI::SBInterstitialReason
255 BaseBlockingPage::GetInterstitialReason(
256 const UnsafeResourceList& unsafe_resources) {
257 bool harmful = false;
258 for (UnsafeResourceList::const_iterator iter = unsafe_resources.begin();
259 iter != unsafe_resources.end(); ++iter) {
260 const BaseUIManager::UnsafeResource& resource = *iter;
261 safe_browsing::SBThreatType threat_type = resource.threat_type;
262 if (threat_type == SB_THREAT_TYPE_URL_MALWARE ||
263 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) {
264 return SafeBrowsingErrorUI::SB_REASON_MALWARE;
265 } else if (threat_type == SB_THREAT_TYPE_URL_UNWANTED) {
266 harmful = true;
267 } else {
268 DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING ||
269 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
270 }
271 }
272
273 if (harmful)
274 return SafeBrowsingErrorUI::SB_REASON_HARMFUL;
275 return SafeBrowsingErrorUI::SB_REASON_PHISHING;
276 }
277
278 // static
279 std::unique_ptr<SecurityInterstitialControllerClient>
280 BaseBlockingPage::CreateControllerClient(
281 content::WebContents* web_contents,
282 const UnsafeResourceList& unsafe_resources,
283 history::HistoryService* history_service,
284 const std::string& app_locale,
285 const GURL& default_safe_page) {
286 SafeBrowsingErrorUI::SBInterstitialReason interstitial_reason =
287 GetInterstitialReason(unsafe_resources);
288 security_interstitials::MetricsHelper::ReportDetails reporting_info;
289 reporting_info.metric_prefix =
290 GetMetricPrefix(unsafe_resources, interstitial_reason);
291 reporting_info.extra_suffix = GetExtraMetricsSuffix(unsafe_resources);
292
293 std::unique_ptr<security_interstitials::MetricsHelper> metrics_helper =
294 base::MakeUnique<security_interstitials::MetricsHelper>(
295 unsafe_resources[0].url, reporting_info, history_service);
296
297 return base::MakeUnique<SecurityInterstitialControllerClient>(
298 web_contents, std::move(metrics_helper), nullptr, app_locale,
299 default_safe_page);
300 }
301
302 // static
303 SafeBrowsingErrorUI::SBErrorDisplayOptions*
304 BaseBlockingPage::CreateDefaultDisplayOptions(
305 const UnsafeResourceList& unsafe_resources) {
306 return new SafeBrowsingErrorUI::SBErrorDisplayOptions(
307 IsMainPageLoadBlocked(unsafe_resources),
308 true, // kSafeBrowsingExtendedReportingOptInAllowed
309 false, // is_off_the_record
310 false, // is_extended_reporting
311 false, // is_scout
312 false); // kSafeBrowsingProceedAnywayDisabled
313 }
314
315 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698