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.
4 //
5 // Implementation of the SafeBrowsingBlockingPage class.
6
7 #include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
8
9 #include <string>
10
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/i18n/rtl.h"
14 #include "base/lazy_instance.h"
15 #include "base/metrics/field_trial.h"
16 #include "base/metrics/histogram.h"
17 #include "base/prefs/pref_service.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_piece.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/time/time.h"
23 #include "base/values.h"
24 #include "chrome/browser/browser_process.h"
25 #include "chrome/browser/history/history_service_factory.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/browser/renderer_preferences_util.h"
28 #include "chrome/browser/safe_browsing/malware_details.h"
29 #include "chrome/browser/safe_browsing/ui_manager.h"
30 #include "chrome/browser/tab_contents/tab_util.h"
31 #include "chrome/common/chrome_switches.h"
32 #include "chrome/common/pref_names.h"
33 #include "chrome/common/url_constants.h"
34 #include "components/google/core/browser/google_util.h"
35 #include "content/public/browser/browser_thread.h"
36 #include "content/public/browser/interstitial_page.h"
37 #include "content/public/browser/navigation_controller.h"
38 #include "content/public/browser/user_metrics.h"
39 #include "content/public/browser/web_contents.h"
40 #include "grit/browser_resources.h"
41 #include "grit/chromium_strings.h"
42 #include "grit/generated_resources.h"
43 #include "grit/locale_settings.h"
44 #include "net/base/escape.h"
45 #include "ui/base/l10n/l10n_util.h"
46 #include "ui/base/resource/resource_bundle.h"
47 #include "ui/base/webui/jstemplate_builder.h"
48 #include "ui/base/webui/web_ui_util.h"
49
50 using base::UserMetricsAction;
51 using content::BrowserThread;
52 using content::InterstitialPage;
53 using content::OpenURLParams;
54 using content::Referrer;
55 using content::WebContents;
56
57 namespace {
58
59 // For malware interstitial pages, we link the problematic URL to Google's
60 // diagnostic page.
61 #if defined(GOOGLE_CHROME_BUILD)
62 const char* const kSbDiagnosticUrl =
63 "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=%s&client=googlechrome";
64 #else
65 const char* const kSbDiagnosticUrl =
66 "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=%s&client=chromium";
67 #endif
68
69 const char kSbReportPhishingErrorUrl[] =
70 "http://www.google.com/safebrowsing/report_error/";
71
72 // URL for the "Learn more" link on the multi threat malware blocking page.
73 const char kLearnMoreMalwareUrl[] =
74 "https://www.google.com/support/bin/answer.py?answer=45449&topic=360"
75 "&sa=X&oi=malwarewarninglink&resnum=1&ct=help";
76
77 // URL for malware and phishing, V2.
78 const char kLearnMoreMalwareUrlV2[] =
79 "https://www.google.com/transparencyreport/safebrowsing/";
80 const char kLearnMorePhishingUrlV2[] =
81 "https://www.google.com/transparencyreport/safebrowsing/";
82
83 // URL for the "Learn more" link on the phishing blocking page.
84 const char kLearnMorePhishingUrl[] =
85 "https://www.google.com/support/bin/answer.py?answer=106318";
86
87 const char kPrivacyLinkHtml[] =
88 "<a id=\"privacy-link\" href=\"\" onclick=\"sendCommand('showPrivacy'); "
89 "return false;\" onmousedown=\"return false;\">%s</a>";
90
91 // After a malware interstitial where the user opted-in to the report
92 // but clicked "proceed anyway", we delay the call to
93 // MalwareDetails::FinishCollection() by this much time (in
94 // milliseconds).
95 const int64 kMalwareDetailsProceedDelayMilliSeconds = 3000;
96
97 // The commands returned by the page when the user performs an action.
98 const char kDoReportCommand[] = "doReport";
99 const char kDontReportCommand[] = "dontReport";
100 const char kExpandedSeeMoreCommand[] = "expandedSeeMore";
101 const char kLearnMoreCommand[] = "learnMore";
102 const char kLearnMoreCommandV2[] = "learnMore2";
103 const char kProceedCommand[] = "proceed";
104 const char kReportErrorCommand[] = "reportError";
105 const char kShowDiagnosticCommand[] = "showDiagnostic";
106 const char kShowPrivacyCommand[] = "showPrivacy";
107 const char kTakeMeBackCommand[] = "takeMeBack";
108 // Special command that we use when the user navigated away from the
109 // page. E.g., closed the tab or the window. This is only used by
110 // RecordUserReactionTime.
111 const char kNavigatedAwayMetaCommand[] = "closed";
112
113 // Other constants used to communicate with the JavaScript.
114 const char kBoxChecked[] = "boxchecked";
115 const char kDisplayCheckBox[] = "displaycheckbox";
116
117 base::LazyInstance<SafeBrowsingBlockingPage::UnsafeResourceMap>
118 g_unsafe_resource_map = LAZY_INSTANCE_INITIALIZER;
119
120 // This enum is used for a histogram. Don't reorder, delete, or insert
121 // elements. New elements should be added before MAX_ACTION only.
122 enum DetailedDecision {
123 MALWARE_SHOW_NEW_SITE = 0,
124 MALWARE_PROCEED_NEW_SITE,
125 MALWARE_SHOW_CROSS_SITE,
126 MALWARE_PROCEED_CROSS_SITE,
127 PHISHING_SHOW_NEW_SITE,
128 PHISHING_PROCEED_NEW_SITE,
129 PHISHING_SHOW_CROSS_SITE,
130 PHISHING_PROCEED_CROSS_SITE,
131 MAX_DETAILED_ACTION
132 };
133
RecordDetailedUserAction(DetailedDecision decision)134 void RecordDetailedUserAction(DetailedDecision decision) {
135 UMA_HISTOGRAM_ENUMERATION("SB2.InterstitialActionDetails",
136 decision,
137 MAX_DETAILED_ACTION);
138 }
139
140 // Constants for the M37 Finch trial.
141 const char kV3StudyName[] = "MalwareInterstitialVersion";
142 const char kCondV2[] = "V2";
143 const char kCondV3[] = "V3";
144 const char kCondV3Advice[] = "V3Advice";
145 const char kCondV3Social[] = "V3Social";
146 const char kCondV3NotRecommend[] = "V3NotRecommend";
147 const char kCondV3History[] = "V3History";
148
149 // Default to V3 unless a flag or field trial says otherwise. Flags override
150 // field trial settings.
GetTrialCondition()151 const char* GetTrialCondition() {
152 if (CommandLine::ForCurrentProcess()->HasSwitch(
153 switches::kMalwareInterstitialV2)) {
154 return kCondV2;
155 }
156 if (CommandLine::ForCurrentProcess()->HasSwitch(
157 switches::kMalwareInterstitialV3)) {
158 return kCondV3;
159 }
160 if (CommandLine::ForCurrentProcess()->HasSwitch(
161 switches::kMalwareInterstitialV3Advice)) {
162 return kCondV3Advice;
163 }
164 if (CommandLine::ForCurrentProcess()->HasSwitch(
165 switches::kMalwareInterstitialV3Social)) {
166 return kCondV3Social;
167 }
168 if (CommandLine::ForCurrentProcess()->HasSwitch(
169 switches::kMalwareInterstitialV3NotRecommend)) {
170 return kCondV3NotRecommend;
171 }
172 if (CommandLine::ForCurrentProcess()->HasSwitch(
173 switches::kMalwareInterstitialV3History)) {
174 return kCondV3History;
175 }
176
177 // Make sure that the return value is one of the expected types instead of
178 // directly returning base::FieldTrialList::FindFullName.
179 if (base::FieldTrialList::FindFullName(kV3StudyName) == kCondV2)
180 return kCondV2;
181 if (base::FieldTrialList::FindFullName(kV3StudyName) == kCondV3)
182 return kCondV3;
183 if (base::FieldTrialList::FindFullName(kV3StudyName) == kCondV3Advice)
184 return kCondV3Advice;
185 if (base::FieldTrialList::FindFullName(kV3StudyName) == kCondV3Social)
186 return kCondV3Social;
187 if (base::FieldTrialList::FindFullName(kV3StudyName) == kCondV3NotRecommend)
188 return kCondV3NotRecommend;
189 if (base::FieldTrialList::FindFullName(kV3StudyName) == kCondV3History)
190 return kCondV3History;
191 return kCondV3;
192 }
193
194 } // namespace
195
196 // static
197 SafeBrowsingBlockingPageFactory* SafeBrowsingBlockingPage::factory_ = NULL;
198
199 // The default SafeBrowsingBlockingPageFactory. Global, made a singleton so we
200 // don't leak it.
201 class SafeBrowsingBlockingPageFactoryImpl
202 : public SafeBrowsingBlockingPageFactory {
203 public:
CreateSafeBrowsingPage(SafeBrowsingUIManager * ui_manager,WebContents * web_contents,const SafeBrowsingBlockingPage::UnsafeResourceList & unsafe_resources)204 virtual SafeBrowsingBlockingPage* CreateSafeBrowsingPage(
205 SafeBrowsingUIManager* ui_manager,
206 WebContents* web_contents,
207 const SafeBrowsingBlockingPage::UnsafeResourceList& unsafe_resources)
208 OVERRIDE {
209 // Only use the V2 page if the interstitial is for a single malware or
210 // phishing resource, the multi-threat interstitial has not been updated to
211 // V2 yet.
212 if (unsafe_resources.size() == 1 &&
213 (unsafe_resources[0].threat_type == SB_THREAT_TYPE_URL_MALWARE ||
214 unsafe_resources[0].threat_type ==
215 SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL ||
216 unsafe_resources[0].threat_type == SB_THREAT_TYPE_URL_PHISHING ||
217 unsafe_resources[0].threat_type ==
218 SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL)) {
219 if (GetTrialCondition() == kCondV2) {
220 return new SafeBrowsingBlockingPageV2(ui_manager, web_contents,
221 unsafe_resources);
222 } else {
223 return new SafeBrowsingBlockingPageV3(ui_manager, web_contents,
224 unsafe_resources);
225 }
226 }
227 return new SafeBrowsingBlockingPageV1(ui_manager, web_contents,
228 unsafe_resources);
229 }
230
231 private:
232 friend struct base::DefaultLazyInstanceTraits<
233 SafeBrowsingBlockingPageFactoryImpl>;
234
SafeBrowsingBlockingPageFactoryImpl()235 SafeBrowsingBlockingPageFactoryImpl() { }
236
237 DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPageFactoryImpl);
238 };
239
240 static base::LazyInstance<SafeBrowsingBlockingPageFactoryImpl>
241 g_safe_browsing_blocking_page_factory_impl = LAZY_INSTANCE_INITIALIZER;
242
SafeBrowsingBlockingPage(SafeBrowsingUIManager * ui_manager,WebContents * web_contents,const UnsafeResourceList & unsafe_resources)243 SafeBrowsingBlockingPage::SafeBrowsingBlockingPage(
244 SafeBrowsingUIManager* ui_manager,
245 WebContents* web_contents,
246 const UnsafeResourceList& unsafe_resources)
247 : malware_details_proceed_delay_ms_(
248 kMalwareDetailsProceedDelayMilliSeconds),
249 ui_manager_(ui_manager),
250 report_loop_(NULL),
251 is_main_frame_load_blocked_(IsMainPageLoadBlocked(unsafe_resources)),
252 unsafe_resources_(unsafe_resources),
253 proceeded_(false),
254 web_contents_(web_contents),
255 url_(unsafe_resources[0].url),
256 has_expanded_see_more_section_(false),
257 reporting_checkbox_checked_(false),
258 num_visits_(-1) {
259 bool malware = false;
260 bool phishing = false;
261 for (UnsafeResourceList::const_iterator iter = unsafe_resources_.begin();
262 iter != unsafe_resources_.end(); ++iter) {
263 const UnsafeResource& resource = *iter;
264 SBThreatType threat_type = resource.threat_type;
265 if (threat_type == SB_THREAT_TYPE_URL_MALWARE ||
266 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) {
267 malware = true;
268 } else {
269 DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING ||
270 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
271 phishing = true;
272 }
273 }
274 DCHECK(phishing || malware);
275 if (malware && phishing)
276 interstitial_type_ = TYPE_MALWARE_AND_PHISHING;
277 else if (malware)
278 interstitial_type_ = TYPE_MALWARE;
279 else
280 interstitial_type_ = TYPE_PHISHING;
281
282 RecordUserAction(SHOW);
283 HistoryService* history_service = HistoryServiceFactory::GetForProfile(
284 Profile::FromBrowserContext(web_contents->GetBrowserContext()),
285 Profile::EXPLICIT_ACCESS);
286 if (history_service) {
287 history_service->GetVisibleVisitCountToHost(
288 url_,
289 &request_consumer_,
290 base::Bind(&SafeBrowsingBlockingPage::OnGotHistoryCount,
291 base::Unretained(this)));
292 }
293
294 if (!is_main_frame_load_blocked_) {
295 navigation_entry_index_to_remove_ =
296 web_contents->GetController().GetLastCommittedEntryIndex();
297 } else {
298 navigation_entry_index_to_remove_ = -1;
299 }
300
301 // Start computing malware details. They will be sent only
302 // if the user opts-in on the blocking page later.
303 // If there's more than one malicious resources, it means the user
304 // clicked through the first warning, so we don't prepare additional
305 // reports.
306 if (unsafe_resources.size() == 1 &&
307 unsafe_resources[0].threat_type == SB_THREAT_TYPE_URL_MALWARE &&
308 malware_details_.get() == NULL && CanShowMalwareDetailsOption()) {
309 malware_details_ = MalwareDetails::NewMalwareDetails(
310 ui_manager_, web_contents, unsafe_resources[0]);
311 }
312
313 interstitial_page_ = InterstitialPage::Create(
314 web_contents, IsMainPageLoadBlocked(unsafe_resources), url_, this);
315 }
316
CanShowMalwareDetailsOption()317 bool SafeBrowsingBlockingPage::CanShowMalwareDetailsOption() {
318 return (!web_contents_->GetBrowserContext()->IsOffTheRecord() &&
319 web_contents_->GetURL().SchemeIs(url::kHttpScheme));
320 }
321
~SafeBrowsingBlockingPage()322 SafeBrowsingBlockingPage::~SafeBrowsingBlockingPage() {
323 }
324
CommandReceived(const std::string & cmd)325 void SafeBrowsingBlockingPage::CommandReceived(const std::string& cmd) {
326 std::string command(cmd); // Make a local copy so we can modify it.
327 // The Jasonified response has quotes, remove them.
328 if (command.length() > 1 && command[0] == '"') {
329 command = command.substr(1, command.length() - 2);
330 }
331 RecordUserReactionTime(command);
332 if (command == kDoReportCommand) {
333 SetReportingPreference(true);
334 return;
335 }
336
337 if (command == kDontReportCommand) {
338 SetReportingPreference(false);
339 return;
340 }
341
342 if (command == kLearnMoreCommand) {
343 // User pressed "Learn more".
344 GURL url;
345 SBThreatType threat_type = unsafe_resources_[0].threat_type;
346 if (threat_type == SB_THREAT_TYPE_URL_MALWARE ||
347 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) {
348 url = GURL(kLearnMoreMalwareUrl);
349 } else if (threat_type == SB_THREAT_TYPE_URL_PHISHING ||
350 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL) {
351 url = GURL(kLearnMorePhishingUrl);
352 } else {
353 NOTREACHED();
354 }
355
356 OpenURLParams params(
357 url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_LINK, false);
358 web_contents_->OpenURL(params);
359 return;
360 }
361
362 if (command == kLearnMoreCommandV2) {
363 // User pressed "Learn more".
364 GURL url;
365 SBThreatType threat_type = unsafe_resources_[0].threat_type;
366 if (threat_type == SB_THREAT_TYPE_URL_MALWARE ||
367 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) {
368 url = GURL(kLearnMoreMalwareUrlV2);
369 } else if (threat_type == SB_THREAT_TYPE_URL_PHISHING ||
370 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL) {
371 url = GURL(kLearnMorePhishingUrlV2);
372 } else {
373 NOTREACHED();
374 }
375
376 OpenURLParams params(
377 url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_LINK, false);
378 web_contents_->OpenURL(params);
379 return;
380 }
381
382 if (command == kShowPrivacyCommand) {
383 // User pressed "Safe Browsing privacy policy".
384 GURL url(l10n_util::GetStringUTF8(IDS_SAFE_BROWSING_PRIVACY_POLICY_URL));
385 OpenURLParams params(
386 url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_LINK, false);
387 web_contents_->OpenURL(params);
388 return;
389 }
390
391 bool proceed_blocked = false;
392 if (command == kProceedCommand) {
393 if (IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled)) {
394 proceed_blocked = true;
395 } else {
396 interstitial_page_->Proceed();
397 // |this| has been deleted after Proceed() returns.
398 return;
399 }
400 }
401
402 if (command == kTakeMeBackCommand || proceed_blocked) {
403 if (is_main_frame_load_blocked_) {
404 // If the load is blocked, we want to close the interstitial and discard
405 // the pending entry.
406 interstitial_page_->DontProceed();
407 // |this| has been deleted after DontProceed() returns.
408 return;
409 }
410
411 // Otherwise the offending entry has committed, and we need to go back or
412 // to a safe page. We will close the interstitial when that page commits.
413 if (web_contents_->GetController().CanGoBack()) {
414 web_contents_->GetController().GoBack();
415 } else {
416 web_contents_->GetController().LoadURL(
417 GURL(chrome::kChromeUINewTabURL),
418 content::Referrer(),
419 content::PAGE_TRANSITION_AUTO_TOPLEVEL,
420 std::string());
421 }
422 return;
423 }
424
425 // The "report error" and "show diagnostic" commands can have a number
426 // appended to them, which is the index of the element they apply to.
427 size_t element_index = 0;
428 size_t colon_index = command.find(':');
429 if (colon_index != std::string::npos) {
430 DCHECK(colon_index < command.size() - 1);
431 int result_int = 0;
432 bool result = base::StringToInt(base::StringPiece(command.begin() +
433 colon_index + 1,
434 command.end()),
435 &result_int);
436 command = command.substr(0, colon_index);
437 if (result)
438 element_index = static_cast<size_t>(result_int);
439 }
440
441 if (element_index >= unsafe_resources_.size()) {
442 NOTREACHED();
443 return;
444 }
445
446 std::string bad_url_spec = unsafe_resources_[element_index].url.spec();
447 if (command == kReportErrorCommand) {
448 // User pressed "Report error" for a phishing site.
449 // Note that we cannot just put a link in the interstitial at this point.
450 // It is not OK to navigate in the context of an interstitial page.
451 SBThreatType threat_type = unsafe_resources_[element_index].threat_type;
452 DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING ||
453 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
454 GURL report_url =
455 safe_browsing_util::GeneratePhishingReportUrl(
456 kSbReportPhishingErrorUrl,
457 bad_url_spec,
458 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
459 OpenURLParams params(
460 report_url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_LINK,
461 false);
462 web_contents_->OpenURL(params);
463 return;
464 }
465
466 if (command == kShowDiagnosticCommand) {
467 // We're going to take the user to Google's SafeBrowsing diagnostic page.
468 std::string diagnostic =
469 base::StringPrintf(kSbDiagnosticUrl,
470 net::EscapeQueryParamValue(bad_url_spec, true).c_str());
471 GURL diagnostic_url(diagnostic);
472 diagnostic_url = google_util::AppendGoogleLocaleParam(
473 diagnostic_url, g_browser_process->GetApplicationLocale());
474 DCHECK(unsafe_resources_[element_index].threat_type ==
475 SB_THREAT_TYPE_URL_MALWARE ||
476 unsafe_resources_[element_index].threat_type ==
477 SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL);
478 OpenURLParams params(
479 diagnostic_url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_LINK,
480 false);
481 web_contents_->OpenURL(params);
482 return;
483 }
484
485 if (command == kExpandedSeeMoreCommand) {
486 // User expanded the "see more info" section of the page. We don't actually
487 // do any action based on this, it's just so that RecordUserReactionTime can
488 // track it.
489 return;
490 }
491
492 NOTREACHED() << "Unexpected command: " << command;
493 }
494
OverrideRendererPrefs(content::RendererPreferences * prefs)495 void SafeBrowsingBlockingPage::OverrideRendererPrefs(
496 content::RendererPreferences* prefs) {
497 Profile* profile = Profile::FromBrowserContext(
498 web_contents_->GetBrowserContext());
499 renderer_preferences_util::UpdateFromSystemSettings(prefs, profile);
500 }
501
SetReportingPreference(bool report)502 void SafeBrowsingBlockingPage::SetReportingPreference(bool report) {
503 Profile* profile = Profile::FromBrowserContext(
504 web_contents_->GetBrowserContext());
505 PrefService* pref = profile->GetPrefs();
506 pref->SetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled, report);
507 UMA_HISTOGRAM_BOOLEAN("SB2.SetExtendedReportingEnabled", report);
508 reporting_checkbox_checked_ = report;
509 pref->ClearPref(prefs::kSafeBrowsingReportingEnabled);
510 pref->ClearPref(prefs::kSafeBrowsingDownloadFeedbackEnabled);
511 }
512
513 // If the reporting checkbox was left checked on close, the new pref
514 // kSafeBrowsingExtendedReportingEnabled should be updated.
515 // TODO(felt): Remove this in M-39. crbug.com/384668
UpdateReportingPref()516 void SafeBrowsingBlockingPage::UpdateReportingPref() {
517 if (!reporting_checkbox_checked_)
518 return;
519 if (IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingEnabled))
520 return;
521 Profile* profile = Profile::FromBrowserContext(
522 web_contents_->GetBrowserContext());
523 if (profile->GetPrefs()->HasPrefPath(
524 prefs::kSafeBrowsingExtendedReportingEnabled))
525 return;
526 SetReportingPreference(true);
527 }
528
OnProceed()529 void SafeBrowsingBlockingPage::OnProceed() {
530 proceeded_ = true;
531 RecordUserAction(PROCEED);
532 UpdateReportingPref();
533 // Send the malware details, if we opted to.
534 FinishMalwareDetails(malware_details_proceed_delay_ms_);
535
536 NotifySafeBrowsingUIManager(ui_manager_, unsafe_resources_, true);
537
538 // Check to see if some new notifications of unsafe resources have been
539 // received while we were showing the interstitial.
540 UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
541 UnsafeResourceMap::iterator iter = unsafe_resource_map->find(web_contents_);
542 SafeBrowsingBlockingPage* blocking_page = NULL;
543 if (iter != unsafe_resource_map->end() && !iter->second.empty()) {
544 // Build an interstitial for all the unsafe resources notifications.
545 // Don't show it now as showing an interstitial while an interstitial is
546 // already showing would cause DontProceed() to be invoked.
547 blocking_page = factory_->CreateSafeBrowsingPage(ui_manager_, web_contents_,
548 iter->second);
549 unsafe_resource_map->erase(iter);
550 }
551
552 // Now that this interstitial is gone, we can show the new one.
553 if (blocking_page)
554 blocking_page->interstitial_page_->Show();
555 }
556
OnDontProceed()557 void SafeBrowsingBlockingPage::OnDontProceed() {
558 // Calling this method twice will not double-count.
559 RecordUserReactionTime(kNavigatedAwayMetaCommand);
560 // We could have already called Proceed(), in which case we must not notify
561 // the SafeBrowsingUIManager again, as the client has been deleted.
562 if (proceeded_)
563 return;
564
565 RecordUserAction(DONT_PROCEED);
566 UpdateReportingPref();
567 // Send the malware details, if we opted to.
568 FinishMalwareDetails(0); // No delay
569
570 NotifySafeBrowsingUIManager(ui_manager_, unsafe_resources_, false);
571
572 // The user does not want to proceed, clear the queued unsafe resources
573 // notifications we received while the interstitial was showing.
574 UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
575 UnsafeResourceMap::iterator iter = unsafe_resource_map->find(web_contents_);
576 if (iter != unsafe_resource_map->end() && !iter->second.empty()) {
577 NotifySafeBrowsingUIManager(ui_manager_, iter->second, false);
578 unsafe_resource_map->erase(iter);
579 }
580
581 // We don't remove the navigation entry if the tab is being destroyed as this
582 // would trigger a navigation that would cause trouble as the render view host
583 // for the tab has by then already been destroyed. We also don't delete the
584 // current entry if it has been committed again, which is possible on a page
585 // that had a subresource warning.
586 int last_committed_index =
587 web_contents_->GetController().GetLastCommittedEntryIndex();
588 if (navigation_entry_index_to_remove_ != -1 &&
589 navigation_entry_index_to_remove_ != last_committed_index &&
590 !web_contents_->IsBeingDestroyed()) {
591 CHECK(web_contents_->GetController().RemoveEntryAtIndex(
592 navigation_entry_index_to_remove_));
593 navigation_entry_index_to_remove_ = -1;
594 }
595 }
596
OnGotHistoryCount(HistoryService::Handle handle,bool success,int num_visits,base::Time first_visit)597 void SafeBrowsingBlockingPage::OnGotHistoryCount(HistoryService::Handle handle,
598 bool success,
599 int num_visits,
600 base::Time first_visit) {
601 if (success)
602 num_visits_ = num_visits;
603 }
604
RecordUserAction(BlockingPageEvent event)605 void SafeBrowsingBlockingPage::RecordUserAction(BlockingPageEvent event) {
606 // This enum is used for a histogram. Don't reorder, delete, or insert
607 // elements. New elements should be added before MAX_ACTION only.
608 enum {
609 MALWARE_SHOW = 0,
610 MALWARE_DONT_PROCEED,
611 MALWARE_FORCED_DONT_PROCEED,
612 MALWARE_PROCEED,
613 MULTIPLE_SHOW,
614 MULTIPLE_DONT_PROCEED,
615 MULTIPLE_FORCED_DONT_PROCEED,
616 MULTIPLE_PROCEED,
617 PHISHING_SHOW,
618 PHISHING_DONT_PROCEED,
619 PHISHING_FORCED_DONT_PROCEED,
620 PHISHING_PROCEED,
621 MALWARE_SHOW_ADVANCED,
622 MULTIPLE_SHOW_ADVANCED,
623 PHISHING_SHOW_ADVANCED,
624 MAX_ACTION
625 } histogram_action = MAX_ACTION;
626
627 switch (event) {
628 case SHOW:
629 switch (interstitial_type_) {
630 case TYPE_MALWARE_AND_PHISHING:
631 histogram_action = MULTIPLE_SHOW;
632 break;
633 case TYPE_MALWARE:
634 histogram_action = MALWARE_SHOW;
635 break;
636 case TYPE_PHISHING:
637 histogram_action = PHISHING_SHOW;
638 break;
639 }
640 break;
641 case PROCEED:
642 switch (interstitial_type_) {
643 case TYPE_MALWARE_AND_PHISHING:
644 histogram_action = MULTIPLE_PROCEED;
645 break;
646 case TYPE_MALWARE:
647 histogram_action = MALWARE_PROCEED;
648 break;
649 case TYPE_PHISHING:
650 histogram_action = PHISHING_PROCEED;
651 break;
652 }
653 break;
654 case DONT_PROCEED:
655 if (IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled)) {
656 switch (interstitial_type_) {
657 case TYPE_MALWARE_AND_PHISHING:
658 histogram_action = MULTIPLE_FORCED_DONT_PROCEED;
659 break;
660 case TYPE_MALWARE:
661 histogram_action = MALWARE_FORCED_DONT_PROCEED;
662 break;
663 case TYPE_PHISHING:
664 histogram_action = PHISHING_FORCED_DONT_PROCEED;
665 break;
666 }
667 } else {
668 switch (interstitial_type_) {
669 case TYPE_MALWARE_AND_PHISHING:
670 histogram_action = MULTIPLE_DONT_PROCEED;
671 break;
672 case TYPE_MALWARE:
673 histogram_action = MALWARE_DONT_PROCEED;
674 break;
675 case TYPE_PHISHING:
676 histogram_action = PHISHING_DONT_PROCEED;
677 break;
678 }
679 }
680 break;
681 case SHOW_ADVANCED:
682 switch (interstitial_type_) {
683 case TYPE_MALWARE_AND_PHISHING:
684 histogram_action = MULTIPLE_SHOW_ADVANCED;
685 break;
686 case TYPE_MALWARE:
687 histogram_action = MALWARE_SHOW_ADVANCED;
688 break;
689 case TYPE_PHISHING:
690 histogram_action = PHISHING_SHOW_ADVANCED;
691 break;
692 }
693 break;
694 default:
695 NOTREACHED() << "Unexpected event: " << event;
696 }
697 if (histogram_action == MAX_ACTION) {
698 NOTREACHED();
699 } else {
700 UMA_HISTOGRAM_ENUMERATION("SB2.InterstitialAction", histogram_action,
701 MAX_ACTION);
702 }
703
704 if (event == PROCEED || event == DONT_PROCEED) {
705 if (num_visits_ == 0 && interstitial_type_ != TYPE_MALWARE_AND_PHISHING) {
706 RecordDetailedUserAction((interstitial_type_ == TYPE_MALWARE) ?
707 MALWARE_SHOW_NEW_SITE : PHISHING_SHOW_NEW_SITE);
708 if (event == PROCEED) {
709 RecordDetailedUserAction((interstitial_type_ == TYPE_MALWARE) ?
710 MALWARE_PROCEED_NEW_SITE : PHISHING_PROCEED_NEW_SITE);
711 }
712 }
713 if (unsafe_resources_[0].is_subresource &&
714 interstitial_type_ != TYPE_MALWARE_AND_PHISHING) {
715 RecordDetailedUserAction((interstitial_type_ == TYPE_MALWARE) ?
716 MALWARE_SHOW_CROSS_SITE : PHISHING_SHOW_CROSS_SITE);
717 if (event == PROCEED) {
718 RecordDetailedUserAction((interstitial_type_ == TYPE_MALWARE) ?
719 MALWARE_PROCEED_CROSS_SITE : PHISHING_PROCEED_CROSS_SITE);
720 }
721 }
722 }
723
724 // TODO(felt): Get rid of the old interstitial histogram.
725 std::string action = "SBInterstitial";
726 switch (interstitial_type_) {
727 case TYPE_MALWARE_AND_PHISHING:
728 action.append("Multiple");
729 break;
730 case TYPE_MALWARE:
731 action.append("Malware");
732 break;
733 case TYPE_PHISHING:
734 action.append("Phishing");
735 break;
736 }
737
738 switch (event) {
739 case SHOW:
740 action.append("Show");
741 break;
742 case PROCEED:
743 action.append("Proceed");
744 break;
745 case DONT_PROCEED:
746 if (IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled))
747 action.append("ForcedDontProceed");
748 else
749 action.append("DontProceed");
750 break;
751 case SHOW_ADVANCED:
752 break;
753 default:
754 NOTREACHED() << "Unexpected event: " << event;
755 }
756
757 content::RecordComputedAction(action);
758 }
759
RecordUserReactionTime(const std::string & command)760 void SafeBrowsingBlockingPage::RecordUserReactionTime(
761 const std::string& command) {
762 if (interstitial_show_time_.is_null())
763 return; // We already reported the user reaction time.
764 base::TimeDelta dt = base::TimeTicks::Now() - interstitial_show_time_;
765 DVLOG(1) << "User reaction time for command:" << command
766 << " on interstitial_type_:" << interstitial_type_
767 << " warning took " << dt.InMilliseconds() << "ms";
768 bool recorded = true;
769 if (interstitial_type_ == TYPE_MALWARE ||
770 interstitial_type_ == TYPE_MALWARE_AND_PHISHING) {
771 // There are six ways in which the malware interstitial can go
772 // away. We handle all of them here but we group two together: closing the
773 // tag / browser window and clicking on the back button in the browser (not
774 // the big green button) are considered the same action.
775 if (command == kProceedCommand) {
776 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialTimeProceed", dt);
777 } else if (command == kTakeMeBackCommand) {
778 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialTimeTakeMeBack", dt);
779 } else if (command == kShowDiagnosticCommand) {
780 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialTimeDiagnostic", dt);
781 } else if (command == kShowPrivacyCommand) {
782 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialTimePrivacyPolicy",
783 dt);
784 } else if (command == kLearnMoreCommand || command == kLearnMoreCommandV2) {
785 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialLearnMore",
786 dt);
787 } else if (command == kNavigatedAwayMetaCommand) {
788 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialTimeClosed", dt);
789 } else if (command == kExpandedSeeMoreCommand) {
790 // Only record the expanded histogram once per display of the
791 // interstitial.
792 if (has_expanded_see_more_section_)
793 return;
794 RecordUserAction(SHOW_ADVANCED);
795 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialTimeExpandedSeeMore",
796 dt);
797 has_expanded_see_more_section_ = true;
798 // Expanding the "See More" section doesn't finish the interstitial, so
799 // don't mark the reaction time as recorded.
800 recorded = false;
801 } else {
802 recorded = false;
803 }
804 } else {
805 // Same as above but for phishing warnings.
806 if (command == kProceedCommand) {
807 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.PhishingInterstitialTimeProceed", dt);
808 } else if (command == kTakeMeBackCommand) {
809 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.PhishingInterstitialTimeTakeMeBack", dt);
810 } else if (command == kShowDiagnosticCommand) {
811 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.PhishingInterstitialTimeReportError", dt);
812 } else if (command == kLearnMoreCommand || command == kLearnMoreCommandV2) {
813 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.PhishingInterstitialTimeLearnMore", dt);
814 } else if (command == kNavigatedAwayMetaCommand) {
815 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.PhishingInterstitialTimeClosed", dt);
816 } else if (command == kExpandedSeeMoreCommand) {
817 // Only record the expanded histogram once per display of the
818 // interstitial.
819 if (has_expanded_see_more_section_)
820 return;
821 RecordUserAction(SHOW_ADVANCED);
822 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.PhishingInterstitialTimeExpandedSeeMore",
823 dt);
824 has_expanded_see_more_section_ = true;
825 // Expanding the "See More" section doesn't finish the interstitial, so
826 // don't mark the reaction time as recorded.
827 recorded = false;
828 } else {
829 recorded = false;
830 }
831 }
832 if (recorded) // Making sure we don't double-count reaction times.
833 interstitial_show_time_ = base::TimeTicks(); // Resets the show time.
834 }
835
FinishMalwareDetails(int64 delay_ms)836 void SafeBrowsingBlockingPage::FinishMalwareDetails(int64 delay_ms) {
837 if (malware_details_.get() == NULL)
838 return; // Not all interstitials have malware details (eg phishing).
839
840 const bool enabled =
841 IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingEnabled);
842 UMA_HISTOGRAM_BOOLEAN("SB2.ExtendedReportingIsEnabled", enabled);
843 if (enabled) {
844 // Finish the malware details collection, send it over.
845 BrowserThread::PostDelayedTask(
846 BrowserThread::IO, FROM_HERE,
847 base::Bind(&MalwareDetails::FinishCollection, malware_details_.get()),
848 base::TimeDelta::FromMilliseconds(delay_ms));
849 }
850 }
851
IsPrefEnabled(const char * pref)852 bool SafeBrowsingBlockingPage::IsPrefEnabled(const char* pref) {
853 Profile* profile =
854 Profile::FromBrowserContext(web_contents_->GetBrowserContext());
855 return profile->GetPrefs()->GetBoolean(pref);
856 }
857
858 // static
NotifySafeBrowsingUIManager(SafeBrowsingUIManager * ui_manager,const UnsafeResourceList & unsafe_resources,bool proceed)859 void SafeBrowsingBlockingPage::NotifySafeBrowsingUIManager(
860 SafeBrowsingUIManager* ui_manager,
861 const UnsafeResourceList& unsafe_resources,
862 bool proceed) {
863 BrowserThread::PostTask(
864 BrowserThread::IO, FROM_HERE,
865 base::Bind(&SafeBrowsingUIManager::OnBlockingPageDone,
866 ui_manager, unsafe_resources, proceed));
867 }
868
869 // static
870 SafeBrowsingBlockingPage::UnsafeResourceMap*
GetUnsafeResourcesMap()871 SafeBrowsingBlockingPage::GetUnsafeResourcesMap() {
872 return g_unsafe_resource_map.Pointer();
873 }
874
875 // static
ShowBlockingPage(SafeBrowsingUIManager * ui_manager,const UnsafeResource & unsafe_resource)876 void SafeBrowsingBlockingPage::ShowBlockingPage(
877 SafeBrowsingUIManager* ui_manager,
878 const UnsafeResource& unsafe_resource) {
879 DVLOG(1) << __FUNCTION__ << " " << unsafe_resource.url.spec();
880 WebContents* web_contents = tab_util::GetWebContentsByID(
881 unsafe_resource.render_process_host_id, unsafe_resource.render_view_id);
882
883 InterstitialPage* interstitial =
884 InterstitialPage::GetInterstitialPage(web_contents);
885 if (interstitial && !unsafe_resource.is_subresource) {
886 // There is already an interstitial showing and we are about to display a
887 // new one for the main frame. Just hide the current one, it is now
888 // irrelevent
889 interstitial->DontProceed();
890 interstitial = NULL;
891 }
892
893 if (!interstitial) {
894 // There are no interstitial currently showing in that tab, go ahead and
895 // show this interstitial.
896 std::vector<UnsafeResource> resources;
897 resources.push_back(unsafe_resource);
898 // Set up the factory if this has not been done already (tests do that
899 // before this method is called).
900 if (!factory_)
901 factory_ = g_safe_browsing_blocking_page_factory_impl.Pointer();
902 SafeBrowsingBlockingPage* blocking_page =
903 factory_->CreateSafeBrowsingPage(ui_manager, web_contents, resources);
904 blocking_page->interstitial_page_->Show();
905 return;
906 }
907
908 // This is an interstitial for a page's resource, let's queue it.
909 UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
910 (*unsafe_resource_map)[web_contents].push_back(unsafe_resource);
911 }
912
913 // static
IsMainPageLoadBlocked(const UnsafeResourceList & unsafe_resources)914 bool SafeBrowsingBlockingPage::IsMainPageLoadBlocked(
915 const UnsafeResourceList& unsafe_resources) {
916 // Client-side phishing detection interstitials never block the main frame
917 // load, since they happen after the page is finished loading.
918 if (unsafe_resources[0].threat_type ==
919 SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL) {
920 return false;
921 }
922
923 // Otherwise, check the threat type.
924 return unsafe_resources.size() == 1 && !unsafe_resources[0].is_subresource;
925 }
926
SafeBrowsingBlockingPageV1(SafeBrowsingUIManager * ui_manager,WebContents * web_contents,const UnsafeResourceList & unsafe_resources)927 SafeBrowsingBlockingPageV1::SafeBrowsingBlockingPageV1(
928 SafeBrowsingUIManager* ui_manager,
929 WebContents* web_contents,
930 const UnsafeResourceList& unsafe_resources)
931 : SafeBrowsingBlockingPage(ui_manager, web_contents, unsafe_resources) {
932 }
933
GetHTMLContents()934 std::string SafeBrowsingBlockingPageV1::GetHTMLContents() {
935 // Load the HTML page and create the template components.
936 base::DictionaryValue strings;
937 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
938 std::string html;
939
940 if (unsafe_resources_.empty()) {
941 NOTREACHED();
942 return std::string();
943 }
944
945 DCHECK_GT(unsafe_resources_.size(), 1U);
946 PopulateMultipleThreatStringDictionary(&strings);
947 html = rb.GetRawDataResource(
948 IDR_SAFE_BROWSING_MULTIPLE_THREAT_BLOCK).as_string();
949 interstitial_show_time_ = base::TimeTicks::Now();
950 return webui::GetTemplatesHtml(html, &strings, "template_root");
951 }
952
PopulateStringDictionary(base::DictionaryValue * strings,const base::string16 & title,const base::string16 & headline,const base::string16 & description1,const base::string16 & description2,const base::string16 & description3)953 void SafeBrowsingBlockingPageV1::PopulateStringDictionary(
954 base::DictionaryValue* strings,
955 const base::string16& title,
956 const base::string16& headline,
957 const base::string16& description1,
958 const base::string16& description2,
959 const base::string16& description3) {
960 strings->SetString("title", title);
961 strings->SetString("headLine", headline);
962 strings->SetString("description1", description1);
963 strings->SetString("description2", description2);
964 strings->SetString("description3", description3);
965 strings->SetBoolean("proceedDisabled",
966 IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled));
967 }
968
PopulateMultipleThreatStringDictionary(base::DictionaryValue * strings)969 void SafeBrowsingBlockingPageV1::PopulateMultipleThreatStringDictionary(
970 base::DictionaryValue* strings) {
971
972 base::string16 malware_label =
973 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_LABEL);
974 base::string16 malware_link =
975 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_DIAGNOSTIC_PAGE);
976 base::string16 phishing_label =
977 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_LABEL);
978 base::string16 phishing_link =
979 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_REPORT_ERROR);
980
981 base::ListValue* error_strings = new base::ListValue;
982 for (UnsafeResourceList::const_iterator iter = unsafe_resources_.begin();
983 iter != unsafe_resources_.end(); ++iter) {
984 const UnsafeResource& resource = *iter;
985 SBThreatType threat_type = resource.threat_type;
986 base::DictionaryValue* current_error_strings = new base::DictionaryValue;
987 if (threat_type == SB_THREAT_TYPE_URL_MALWARE ||
988 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) {
989 current_error_strings->SetString("type", "malware");
990 current_error_strings->SetString("typeLabel", malware_label);
991 current_error_strings->SetString("errorLink", malware_link);
992 } else {
993 DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING ||
994 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
995 current_error_strings->SetString("type", "phishing");
996 current_error_strings->SetString("typeLabel", phishing_label);
997 current_error_strings->SetString("errorLink", phishing_link);
998 }
999 current_error_strings->SetString("url", resource.url.spec());
1000 error_strings->Append(current_error_strings);
1001 }
1002 strings->Set("errors", error_strings);
1003
1004 switch (interstitial_type_) {
1005 case TYPE_MALWARE_AND_PHISHING:
1006 PopulateStringDictionary(
1007 strings,
1008 // Use the malware headline, it is the scariest one.
1009 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MULTI_THREAT_TITLE),
1010 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_HEADLINE),
1011 l10n_util::GetStringFUTF16(
1012 IDS_SAFE_BROWSING_MULTI_THREAT_DESCRIPTION1,
1013 base::UTF8ToUTF16(web_contents_->GetURL().host())),
1014 l10n_util::GetStringUTF16(
1015 IDS_SAFE_BROWSING_MULTI_THREAT_DESCRIPTION2),
1016 base::string16());
1017 break;
1018 case TYPE_MALWARE:
1019 PopulateStringDictionary(
1020 strings,
1021 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_TITLE),
1022 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_HEADLINE),
1023 l10n_util::GetStringFUTF16(
1024 IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION1,
1025 base::UTF8ToUTF16(web_contents_->GetURL().host())),
1026 l10n_util::GetStringUTF16(
1027 IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION2),
1028 l10n_util::GetStringUTF16(
1029 IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION3));
1030 break;
1031 case TYPE_PHISHING:
1032 PopulateStringDictionary(
1033 strings,
1034 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_TITLE),
1035 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_HEADLINE),
1036 l10n_util::GetStringFUTF16(
1037 IDS_SAFE_BROWSING_MULTI_PHISHING_DESCRIPTION1,
1038 base::UTF8ToUTF16(web_contents_->GetURL().host())),
1039 base::string16(),
1040 base::string16());
1041 break;
1042 }
1043
1044 strings->SetString("confirm_text",
1045 l10n_util::GetStringUTF16(
1046 IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION_AGREE));
1047 strings->SetString("continue_button",
1048 l10n_util::GetStringUTF16(
1049 IDS_SAFE_BROWSING_MULTI_MALWARE_PROCEED_BUTTON));
1050 strings->SetString("back_button",
1051 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_BACK_BUTTON));
1052 strings->SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
1053 }
1054
PopulateMalwareStringDictionary(base::DictionaryValue * strings)1055 void SafeBrowsingBlockingPageV1::PopulateMalwareStringDictionary(
1056 base::DictionaryValue* strings) {
1057 NOTREACHED();
1058 }
1059
PopulatePhishingStringDictionary(base::DictionaryValue * strings)1060 void SafeBrowsingBlockingPageV1::PopulatePhishingStringDictionary(
1061 base::DictionaryValue* strings) {
1062 NOTREACHED();
1063 }
1064
SafeBrowsingBlockingPageV2(SafeBrowsingUIManager * ui_manager,WebContents * web_contents,const UnsafeResourceList & unsafe_resources)1065 SafeBrowsingBlockingPageV2::SafeBrowsingBlockingPageV2(
1066 SafeBrowsingUIManager* ui_manager,
1067 WebContents* web_contents,
1068 const UnsafeResourceList& unsafe_resources)
1069 : SafeBrowsingBlockingPage(ui_manager, web_contents, unsafe_resources) {
1070 }
1071
GetHTMLContents()1072 std::string SafeBrowsingBlockingPageV2::GetHTMLContents() {
1073 // Load the HTML page and create the template components.
1074 base::DictionaryValue strings;
1075 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
1076 std::string html;
1077
1078 if (unsafe_resources_.empty()) {
1079 NOTREACHED();
1080 return std::string();
1081 }
1082
1083 if (unsafe_resources_.size() > 1) {
1084 // TODO(felt): Implement new multi-threat interstitial and remove
1085 // SafeBrowsingBlockingPageV1 entirely. (http://crbug.com/160336)
1086 NOTREACHED();
1087 } else {
1088 SBThreatType threat_type = unsafe_resources_[0].threat_type;
1089 if (threat_type == SB_THREAT_TYPE_URL_MALWARE ||
1090 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) {
1091 PopulateMalwareStringDictionary(&strings);
1092 } else { // Phishing.
1093 DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING ||
1094 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
1095 PopulatePhishingStringDictionary(&strings);
1096 }
1097 html = rb.GetRawDataResource(IDR_SAFE_BROWSING_MALWARE_BLOCK_V2).
1098 as_string();
1099 }
1100 interstitial_show_time_ = base::TimeTicks::Now();
1101 return webui::GetTemplatesHtml(html, &strings, "template-root");
1102 }
1103
PopulateStringDictionary(base::DictionaryValue * strings,const base::string16 & title,const base::string16 & headline,const base::string16 & description1,const base::string16 & description2,const base::string16 & description3)1104 void SafeBrowsingBlockingPageV2::PopulateStringDictionary(
1105 base::DictionaryValue* strings,
1106 const base::string16& title,
1107 const base::string16& headline,
1108 const base::string16& description1,
1109 const base::string16& description2,
1110 const base::string16& description3) {
1111 strings->SetString("title", title);
1112 strings->SetString("headLine", headline);
1113 strings->SetString("description1", description1);
1114 strings->SetString("description2", description2);
1115 strings->SetString("description3", description3);
1116 strings->SetBoolean("proceedDisabled",
1117 IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled));
1118 strings->SetBoolean("isMainFrame", is_main_frame_load_blocked_);
1119 strings->SetBoolean("isPhishing", interstitial_type_ == TYPE_PHISHING);
1120
1121 strings->SetString("back_button",
1122 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_BACK_BUTTON));
1123 strings->SetString("seeMore", l10n_util::GetStringUTF16(
1124 IDS_SAFE_BROWSING_MALWARE_V2_SEE_MORE));
1125 strings->SetString("proceed",
1126 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_V2_PROCEED_LINK));
1127 webui::SetFontAndTextDirection(strings);
1128 }
1129
PopulateMultipleThreatStringDictionary(base::DictionaryValue * strings)1130 void SafeBrowsingBlockingPageV2::PopulateMultipleThreatStringDictionary(
1131 base::DictionaryValue* strings) {
1132 NOTREACHED();
1133 }
1134
PopulateMalwareStringDictionary(base::DictionaryValue * strings)1135 void SafeBrowsingBlockingPageV2::PopulateMalwareStringDictionary(
1136 base::DictionaryValue* strings) {
1137 // Check to see if we're blocking the main page, or a sub-resource on the
1138 // main page.
1139 base::string16 headline, description1, description2, description3;
1140
1141
1142 description3 = l10n_util::GetStringUTF16(
1143 IDS_SAFE_BROWSING_MALWARE_V2_DESCRIPTION3);
1144 if (is_main_frame_load_blocked_) {
1145 headline = l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_V2_HEADLINE);
1146 description1 = l10n_util::GetStringFUTF16(
1147 IDS_SAFE_BROWSING_MALWARE_V2_DESCRIPTION1,
1148 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
1149 base::UTF8ToUTF16(url_.host()));
1150 description2 = l10n_util::GetStringUTF16(
1151 IDS_SAFE_BROWSING_MALWARE_V2_DESCRIPTION2);
1152 strings->SetString("details", l10n_util::GetStringUTF16(
1153 IDS_SAFE_BROWSING_MALWARE_V2_DETAILS));
1154 } else {
1155 headline = l10n_util::GetStringUTF16(
1156 IDS_SAFE_BROWSING_MALWARE_V2_HEADLINE_SUBRESOURCE);
1157 description1 = l10n_util::GetStringFUTF16(
1158 IDS_SAFE_BROWSING_MALWARE_V2_DESCRIPTION1_SUBRESOURCE,
1159 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
1160 base::UTF8ToUTF16(web_contents_->GetURL().host()));
1161 description2 = l10n_util::GetStringFUTF16(
1162 IDS_SAFE_BROWSING_MALWARE_V2_DESCRIPTION2_SUBRESOURCE,
1163 base::UTF8ToUTF16(url_.host()));
1164 strings->SetString("details", l10n_util::GetStringFUTF16(
1165 IDS_SAFE_BROWSING_MALWARE_V2_DETAILS_SUBRESOURCE,
1166 base::UTF8ToUTF16(url_.host())));
1167 }
1168
1169 PopulateStringDictionary(
1170 strings,
1171 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_V2_TITLE),
1172 headline,
1173 description1,
1174 description2,
1175 description3);
1176
1177 if (!CanShowMalwareDetailsOption()) {
1178 strings->SetBoolean(kDisplayCheckBox, false);
1179 strings->SetString("confirm_text", std::string());
1180 strings->SetString(kBoxChecked, std::string());
1181 } else {
1182 // Show the checkbox for sending malware details.
1183 strings->SetBoolean(kDisplayCheckBox, true);
1184
1185 std::string privacy_link = base::StringPrintf(
1186 kPrivacyLinkHtml,
1187 l10n_util::GetStringUTF8(
1188 IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE_V2).c_str());
1189
1190 strings->SetString("confirm_text",
1191 l10n_util::GetStringFUTF16(
1192 IDS_SAFE_BROWSING_MALWARE_V2_REPORTING_AGREE,
1193 base::UTF8ToUTF16(privacy_link)));
1194 Profile* profile = Profile::FromBrowserContext(
1195 web_contents_->GetBrowserContext());
1196 if (profile->GetPrefs()->HasPrefPath(
1197 prefs::kSafeBrowsingExtendedReportingEnabled)) {
1198 reporting_checkbox_checked_ =
1199 IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingEnabled);
1200 } else if (IsPrefEnabled(prefs::kSafeBrowsingReportingEnabled) ||
1201 IsPrefEnabled(prefs::kSafeBrowsingDownloadFeedbackEnabled)) {
1202 reporting_checkbox_checked_ = true;
1203 }
1204 strings->SetString(kBoxChecked,
1205 reporting_checkbox_checked_ ? "yes" : std::string());
1206 }
1207
1208 strings->SetString("report_error", base::string16());
1209 strings->SetString("learnMore",
1210 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_V2_LEARN_MORE));
1211 }
1212
PopulatePhishingStringDictionary(base::DictionaryValue * strings)1213 void SafeBrowsingBlockingPageV2::PopulatePhishingStringDictionary(
1214 base::DictionaryValue* strings) {
1215 PopulateStringDictionary(
1216 strings,
1217 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_V2_TITLE),
1218 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_V2_HEADLINE),
1219 l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_PHISHING_V2_DESCRIPTION1,
1220 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
1221 base::UTF8ToUTF16(url_.host())),
1222 base::string16(),
1223 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_V2_DESCRIPTION2));
1224
1225 strings->SetString("details", std::string());
1226 strings->SetString("confirm_text", std::string());
1227 strings->SetString(kBoxChecked, std::string());
1228 strings->SetString(
1229 "report_error",
1230 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_V2_REPORT_ERROR));
1231 strings->SetBoolean(kDisplayCheckBox, false);
1232 strings->SetString("learnMore",
1233 l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_V2_LEARN_MORE));
1234 }
1235
SafeBrowsingBlockingPageV3(SafeBrowsingUIManager * ui_manager,WebContents * web_contents,const UnsafeResourceList & unsafe_resources)1236 SafeBrowsingBlockingPageV3::SafeBrowsingBlockingPageV3(
1237 SafeBrowsingUIManager* ui_manager,
1238 WebContents* web_contents,
1239 const UnsafeResourceList& unsafe_resources)
1240 : SafeBrowsingBlockingPage(ui_manager, web_contents, unsafe_resources),
1241 trial_condition_(GetTrialCondition()) {
1242 }
1243
GetHTMLContents()1244 std::string SafeBrowsingBlockingPageV3::GetHTMLContents() {
1245 if (unsafe_resources_.empty() || unsafe_resources_.size() > 1) {
1246 // TODO(felt): Implement new multi-threat interstitial. crbug.com/160336
1247 NOTIMPLEMENTED();
1248 return std::string();
1249 }
1250
1251 // Fill in the shared values.
1252 base::DictionaryValue load_time_data;
1253 webui::SetFontAndTextDirection(&load_time_data);
1254 load_time_data.SetBoolean("ssl", false);
1255 load_time_data.SetString(
1256 "tabTitle", l10n_util::GetStringUTF16(IDS_SAFEBROWSING_V3_TITLE));
1257 load_time_data.SetString(
1258 "openDetails",
1259 l10n_util::GetStringUTF16(IDS_SAFEBROWSING_V3_OPEN_DETAILS_BUTTON));
1260 load_time_data.SetString(
1261 "closeDetails",
1262 l10n_util::GetStringUTF16(IDS_SAFEBROWSING_V3_CLOSE_DETAILS_BUTTON));
1263 load_time_data.SetString(
1264 "primaryButtonText",
1265 l10n_util::GetStringUTF16(IDS_SAFEBROWSING_OVERRIDABLE_SAFETY_BUTTON));
1266 load_time_data.SetBoolean(
1267 "overridable",
1268 !IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled));
1269
1270 // Fill in the values that are specific to malware or phishing.
1271 SBThreatType threat_type = unsafe_resources_[0].threat_type;
1272 switch (threat_type) {
1273 case SB_THREAT_TYPE_URL_MALWARE:
1274 case SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL:
1275 PopulateMalwareLoadTimeData(&load_time_data);
1276 break;
1277 case SB_THREAT_TYPE_URL_PHISHING:
1278 case SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL:
1279 PopulatePhishingLoadTimeData(&load_time_data);
1280 break;
1281 case SB_THREAT_TYPE_SAFE:
1282 case SB_THREAT_TYPE_BINARY_MALWARE_URL:
1283 case SB_THREAT_TYPE_EXTENSION:
1284 NOTREACHED();
1285 }
1286
1287 interstitial_show_time_ = base::TimeTicks::Now();
1288
1289 base::StringPiece html(
1290 ResourceBundle::GetSharedInstance().GetRawDataResource(
1291 IRD_SSL_INTERSTITIAL_V2_HTML));
1292 webui::UseVersion2 version;
1293 return webui::GetI18nTemplateHtml(html, &load_time_data);
1294 }
1295
PopulateMalwareLoadTimeData(base::DictionaryValue * load_time_data)1296 void SafeBrowsingBlockingPageV3::PopulateMalwareLoadTimeData(
1297 base::DictionaryValue* load_time_data) {
1298 load_time_data->SetString("trialCondition", trial_condition_);
1299 load_time_data->SetBoolean("phishing", false);
1300 load_time_data->SetString(
1301 "heading", l10n_util::GetStringUTF16(IDS_MALWARE_V3_HEADING));
1302 load_time_data->SetString(
1303 "primaryParagraph",
1304 l10n_util::GetStringFUTF16(
1305 IDS_MALWARE_V3_PRIMARY_PARAGRAPH,
1306 base::UTF8ToUTF16(url_.host())));
1307 if (trial_condition_ == kCondV3History) {
1308 load_time_data->SetString(
1309 "explanationParagraph",
1310 is_main_frame_load_blocked_ ?
1311 l10n_util::GetStringFUTF16(
1312 IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_HISTORY,
1313 base::UTF8ToUTF16(url_.host())) :
1314 l10n_util::GetStringFUTF16(
1315 IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_SUBRESOURCE_HISTORY,
1316 base::UTF8ToUTF16(web_contents_->GetURL().host()),
1317 base::UTF8ToUTF16(url_.host())));
1318 } else if (trial_condition_ == kCondV3Advice) {
1319 load_time_data->SetString(
1320 "explanationParagraph",
1321 is_main_frame_load_blocked_ ?
1322 l10n_util::GetStringFUTF16(
1323 IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_ADVICE,
1324 base::UTF8ToUTF16(url_.host())) :
1325 l10n_util::GetStringFUTF16(
1326 IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_SUBRESOURCE_ADVICE,
1327 base::UTF8ToUTF16(web_contents_->GetURL().host()),
1328 base::UTF8ToUTF16(url_.host())));
1329 load_time_data->SetString(
1330 "adviceHeading",
1331 l10n_util::GetStringUTF16(IDS_MALWARE_V3_ADVICE_HEADING));
1332 } else {
1333 load_time_data->SetString(
1334 "explanationParagraph",
1335 is_main_frame_load_blocked_ ?
1336 l10n_util::GetStringFUTF16(
1337 IDS_MALWARE_V3_EXPLANATION_PARAGRAPH,
1338 base::UTF8ToUTF16(url_.host())) :
1339 l10n_util::GetStringFUTF16(
1340 IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_SUBRESOURCE,
1341 base::UTF8ToUTF16(web_contents_->GetURL().host()),
1342 base::UTF8ToUTF16(url_.host())));
1343 }
1344 if (trial_condition_ == kCondV3Social) {
1345 load_time_data->SetString(
1346 "finalParagraph",
1347 l10n_util::GetStringUTF16(IDS_MALWARE_V3_PROCEED_PARAGRAPH_SOCIAL));
1348 } else if (trial_condition_ == kCondV3NotRecommend) {
1349 load_time_data->SetString(
1350 "finalParagraph",
1351 l10n_util::GetStringUTF16(
1352 IDS_MALWARE_V3_PROCEED_PARAGRAPH_NOT_RECOMMEND));
1353 } else {
1354 load_time_data->SetString(
1355 "finalParagraph",
1356 l10n_util::GetStringUTF16(IDS_MALWARE_V3_PROCEED_PARAGRAPH));
1357 }
1358
1359 load_time_data->SetBoolean(kDisplayCheckBox, CanShowMalwareDetailsOption());
1360 if (CanShowMalwareDetailsOption()) {
1361 std::string privacy_link = base::StringPrintf(
1362 kPrivacyLinkHtml,
1363 l10n_util::GetStringUTF8(
1364 IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE_V2).c_str());
1365 load_time_data->SetString(
1366 "optInLink",
1367 l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_MALWARE_V2_REPORTING_AGREE,
1368 base::UTF8ToUTF16(privacy_link)));
1369 Profile* profile = Profile::FromBrowserContext(
1370 web_contents_->GetBrowserContext());
1371 if (profile->GetPrefs()->HasPrefPath(
1372 prefs::kSafeBrowsingExtendedReportingEnabled)) {
1373 reporting_checkbox_checked_ =
1374 IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingEnabled);
1375 } else if (IsPrefEnabled(prefs::kSafeBrowsingReportingEnabled) ||
1376 IsPrefEnabled(prefs::kSafeBrowsingDownloadFeedbackEnabled)) {
1377 reporting_checkbox_checked_ = true;
1378 }
1379 load_time_data->SetBoolean(
1380 kBoxChecked, reporting_checkbox_checked_);
1381 }
1382 }
1383
PopulatePhishingLoadTimeData(base::DictionaryValue * load_time_data)1384 void SafeBrowsingBlockingPageV3::PopulatePhishingLoadTimeData(
1385 base::DictionaryValue* load_time_data) {
1386 load_time_data->SetString("trialCondition", std::string());
1387 load_time_data->SetBoolean("phishing", true);
1388 load_time_data->SetString(
1389 "heading",
1390 l10n_util::GetStringUTF16(IDS_PHISHING_V3_HEADING));
1391 load_time_data->SetString(
1392 "primaryParagraph",
1393 l10n_util::GetStringFUTF16(
1394 IDS_PHISHING_V3_PRIMARY_PARAGRAPH,
1395 base::UTF8ToUTF16(url_.host())));
1396 load_time_data->SetString(
1397 "explanationParagraph",
1398 l10n_util::GetStringFUTF16(IDS_PHISHING_V3_EXPLANATION_PARAGRAPH,
1399 base::UTF8ToUTF16(url_.host())));
1400 load_time_data->SetString(
1401 "finalParagraph",
1402 l10n_util::GetStringUTF16(IDS_PHISHING_V3_PROCEED_PARAGRAPH));
1403 }
1404