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// This test creates a fake safebrowsing service, where we can inject
6// malware and phishing urls.  It then uses a real browser to go to
7// these urls, and sends "goback" or "proceed" commands and verifies
8// they work.
9
10#include "base/bind.h"
11#include "base/command_line.h"
12#include "base/prefs/pref_service.h"
13#include "base/strings/utf_string_conversions.h"
14#include "base/values.h"
15#include "chrome/browser/browser_process.h"
16#include "chrome/browser/profiles/profile.h"
17#include "chrome/browser/safe_browsing/database_manager.h"
18#include "chrome/browser/safe_browsing/malware_details.h"
19#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
20#include "chrome/browser/safe_browsing/safe_browsing_service.h"
21#include "chrome/browser/safe_browsing/safe_browsing_util.h"
22#include "chrome/browser/safe_browsing/ui_manager.h"
23#include "chrome/browser/ui/browser.h"
24#include "chrome/browser/ui/browser_tabstrip.h"
25#include "chrome/browser/ui/tabs/tab_strip_model.h"
26#include "chrome/common/pref_names.h"
27#include "chrome/common/url_constants.h"
28#include "chrome/test/base/in_process_browser_test.h"
29#include "chrome/test/base/test_switches.h"
30#include "chrome/test/base/ui_test_utils.h"
31#include "content/public/browser/interstitial_page.h"
32#include "content/public/browser/navigation_controller.h"
33#include "content/public/browser/notification_types.h"
34#include "content/public/browser/render_view_host.h"
35#include "content/public/browser/web_contents.h"
36#include "content/public/browser/web_contents_view.h"
37#include "content/public/test/test_browser_thread.h"
38#include "content/public/test/test_utils.h"
39
40using content::BrowserThread;
41using content::InterstitialPage;
42using content::NavigationController;
43using content::WebContents;
44
45namespace {
46
47const char kEmptyPage[] = "files/empty.html";
48const char kMalwarePage[] = "files/safe_browsing/malware.html";
49const char kMalwareIframe[] = "files/safe_browsing/malware_iframe.html";
50
51class InterstitialObserver : public content::WebContentsObserver {
52 public:
53  InterstitialObserver(content::WebContents* web_contents,
54                       const base::Closure& attach_callback,
55                       const base::Closure& detach_callback)
56      : WebContentsObserver(web_contents),
57        attach_callback_(attach_callback),
58        detach_callback_(detach_callback) {
59  }
60
61  virtual void DidAttachInterstitialPage() OVERRIDE {
62    attach_callback_.Run();
63  }
64
65  virtual void DidDetachInterstitialPage() OVERRIDE {
66    detach_callback_.Run();
67  }
68
69 private:
70  base::Closure attach_callback_;
71  base::Closure detach_callback_;
72
73  DISALLOW_COPY_AND_ASSIGN(InterstitialObserver);
74};
75
76// A SafeBrowsingDatabaseManager class that allows us to inject the malicious
77// URLs.
78class FakeSafeBrowsingDatabaseManager :  public SafeBrowsingDatabaseManager {
79 public:
80  explicit FakeSafeBrowsingDatabaseManager(SafeBrowsingService* service)
81      : SafeBrowsingDatabaseManager(service) { }
82
83  // Called on the IO thread to check if the given url is safe or not.  If we
84  // can synchronously determine that the url is safe, CheckUrl returns true.
85  // Otherwise it returns false, and "client" is called asynchronously with the
86  // result when it is ready.
87  // Overrides SafeBrowsingDatabaseManager::CheckBrowseUrl.
88  virtual bool CheckBrowseUrl(const GURL& gurl, Client* client) OVERRIDE {
89    if (badurls[gurl.spec()] == SB_THREAT_TYPE_SAFE)
90      return true;
91
92    BrowserThread::PostTask(
93        BrowserThread::IO, FROM_HERE,
94        base::Bind(&FakeSafeBrowsingDatabaseManager::OnCheckBrowseURLDone,
95                   this, gurl, client));
96    return false;
97  }
98
99  void OnCheckBrowseURLDone(const GURL& gurl, Client* client) {
100    SafeBrowsingDatabaseManager::SafeBrowsingCheck sb_check(
101        std::vector<GURL>(1, gurl),
102        std::vector<SBFullHash>(),
103        client,
104        safe_browsing_util::MALWARE);
105    sb_check.url_results[0] = badurls[gurl.spec()];
106    client->OnSafeBrowsingResult(sb_check);
107  }
108
109  void SetURLThreatType(const GURL& url, SBThreatType threat_type) {
110    badurls[url.spec()] = threat_type;
111  }
112
113 private:
114  virtual ~FakeSafeBrowsingDatabaseManager() {}
115
116  base::hash_map<std::string, SBThreatType> badurls;
117  DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingDatabaseManager);
118};
119
120// A SafeBrowingUIManager class that allows intercepting malware details.
121class FakeSafeBrowsingUIManager :  public SafeBrowsingUIManager {
122 public:
123  explicit FakeSafeBrowsingUIManager(SafeBrowsingService* service) :
124      SafeBrowsingUIManager(service) { }
125
126  // Overrides SafeBrowsingUIManager
127  virtual void SendSerializedMalwareDetails(
128      const std::string& serialized) OVERRIDE {
129    reports_.push_back(serialized);
130    // Notify the UI thread that we got a report.
131    BrowserThread::PostTask(
132        BrowserThread::UI, FROM_HERE,
133        base::Bind(&FakeSafeBrowsingUIManager::OnMalwareDetailsDone, this));
134  }
135
136  void OnMalwareDetailsDone() {
137    EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
138    base::MessageLoopForUI::current()->Quit();
139  }
140
141  std::string GetReport() {
142    EXPECT_TRUE(reports_.size() == 1);
143    return reports_[0];
144  }
145
146 protected:
147  virtual ~FakeSafeBrowsingUIManager() { }
148
149 private:
150  std::vector<std::string> reports_;
151
152  DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingUIManager);
153};
154
155class FakeSafeBrowsingService : public SafeBrowsingService {
156 public:
157  FakeSafeBrowsingService() { }
158
159  // Returned pointer has the same lifespan as the database_manager_ refcounted
160  // object.
161  FakeSafeBrowsingDatabaseManager* fake_database_manager() {
162    return fake_database_manager_;
163  }
164  // Returned pointer has the same lifespan as the ui_manager_ refcounted
165  // object.
166  FakeSafeBrowsingUIManager* fake_ui_manager() {
167    return fake_ui_manager_;
168  }
169
170 protected:
171  virtual ~FakeSafeBrowsingService() { }
172
173  virtual SafeBrowsingDatabaseManager* CreateDatabaseManager() OVERRIDE {
174    fake_database_manager_ = new FakeSafeBrowsingDatabaseManager(this);
175    return fake_database_manager_;
176  }
177
178  virtual SafeBrowsingUIManager* CreateUIManager() OVERRIDE {
179    fake_ui_manager_ = new FakeSafeBrowsingUIManager(this);
180    return fake_ui_manager_;
181  }
182
183 private:
184  FakeSafeBrowsingDatabaseManager* fake_database_manager_;
185  FakeSafeBrowsingUIManager* fake_ui_manager_;
186
187  DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingService);
188};
189
190// Factory that creates FakeSafeBrowsingService instances.
191class TestSafeBrowsingServiceFactory : public SafeBrowsingServiceFactory {
192 public:
193  TestSafeBrowsingServiceFactory() :
194      most_recent_service_(NULL) { }
195  virtual ~TestSafeBrowsingServiceFactory() { }
196
197  virtual SafeBrowsingService* CreateSafeBrowsingService() OVERRIDE {
198    most_recent_service_ =  new FakeSafeBrowsingService();
199    return most_recent_service_;
200  }
201
202  FakeSafeBrowsingService* most_recent_service() const {
203    return most_recent_service_;
204  }
205
206 private:
207  FakeSafeBrowsingService* most_recent_service_;
208};
209
210// A MalwareDetails class lets us intercept calls from the renderer.
211class FakeMalwareDetails : public MalwareDetails {
212 public:
213  FakeMalwareDetails(
214      SafeBrowsingUIManager* delegate,
215      WebContents* web_contents,
216      const SafeBrowsingUIManager::UnsafeResource& unsafe_resource)
217      : MalwareDetails(delegate, web_contents, unsafe_resource),
218        got_dom_(false),
219        waiting_(false) { }
220
221  virtual void AddDOMDetails(
222      const std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node>& params)
223          OVERRIDE {
224    EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
225    MalwareDetails::AddDOMDetails(params);
226
227    // Notify the UI thread that we got the dom details.
228    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
229                            base::Bind(&FakeMalwareDetails::OnDOMDetailsDone,
230                                       this));
231  }
232
233  void WaitForDOM() {
234    if (got_dom_) {
235      LOG(INFO) << "Already got the dom details.";
236      return;
237    }
238    // This condition might not trigger normally, but if you add a
239    // sleep(1) in malware_dom_details it triggers :).
240    waiting_ = true;
241    LOG(INFO) << "Waiting for dom details.";
242    content::RunMessageLoop();
243    EXPECT_TRUE(got_dom_);
244  }
245
246 private:
247  virtual ~FakeMalwareDetails() {}
248
249  void OnDOMDetailsDone() {
250    got_dom_ = true;
251    if (waiting_) {
252      base::MessageLoopForUI::current()->Quit();
253    }
254  }
255
256  // Some logic to figure out if we should wait for the dom details or not.
257  // These variables should only be accessed in the UI thread.
258  bool got_dom_;
259  bool waiting_;
260};
261
262class TestMalwareDetailsFactory : public MalwareDetailsFactory {
263 public:
264  TestMalwareDetailsFactory() { }
265  virtual ~TestMalwareDetailsFactory() { }
266
267  virtual MalwareDetails* CreateMalwareDetails(
268      SafeBrowsingUIManager* delegate,
269      WebContents* web_contents,
270      const SafeBrowsingUIManager::UnsafeResource& unsafe_resource) OVERRIDE {
271    details_ = new FakeMalwareDetails(delegate, web_contents,
272                                      unsafe_resource);
273    return details_;
274  }
275
276  FakeMalwareDetails* get_details() {
277    return details_;
278  }
279
280 private:
281  FakeMalwareDetails* details_;
282};
283
284// A SafeBrowingBlockingPage class that lets us wait until it's hidden.
285class TestSafeBrowsingBlockingPage : public SafeBrowsingBlockingPageV2 {
286 public:
287  TestSafeBrowsingBlockingPage(SafeBrowsingUIManager* manager,
288                               WebContents* web_contents,
289                               const UnsafeResourceList& unsafe_resources)
290      : SafeBrowsingBlockingPageV2(manager, web_contents, unsafe_resources),
291        wait_for_delete_(false) {
292    // Don't wait the whole 3 seconds for the browser test.
293    malware_details_proceed_delay_ms_ = 100;
294  }
295
296  virtual ~TestSafeBrowsingBlockingPage() {
297    if (!wait_for_delete_)
298      return;
299
300    // Notify that we are gone
301    base::MessageLoopForUI::current()->Quit();
302    wait_for_delete_ = false;
303  }
304
305  void WaitForDelete() {
306    wait_for_delete_ = true;
307    content::RunMessageLoop();
308  }
309
310 private:
311  bool wait_for_delete_;
312};
313
314class TestSafeBrowsingBlockingPageFactory
315    : public SafeBrowsingBlockingPageFactory {
316 public:
317  TestSafeBrowsingBlockingPageFactory() { }
318  virtual ~TestSafeBrowsingBlockingPageFactory() { }
319
320  virtual SafeBrowsingBlockingPage* CreateSafeBrowsingPage(
321      SafeBrowsingUIManager* delegate,
322      WebContents* web_contents,
323      const SafeBrowsingBlockingPage::UnsafeResourceList& unsafe_resources)
324          OVERRIDE {
325    return new TestSafeBrowsingBlockingPage(delegate, web_contents,
326                                            unsafe_resources);
327  }
328};
329
330}  // namespace
331
332// Tests the safe browsing blocking page in a browser.
333class SafeBrowsingBlockingPageTest : public InProcessBrowserTest {
334 public:
335  enum Visibility {
336    VISIBILITY_ERROR = -1,
337    HIDDEN = 0,
338    VISIBLE = 1,
339  };
340
341  SafeBrowsingBlockingPageTest() {
342  }
343
344  virtual void SetUp() OVERRIDE {
345    SafeBrowsingService::RegisterFactory(&factory_);
346    SafeBrowsingBlockingPage::RegisterFactory(&blocking_page_factory_);
347    MalwareDetails::RegisterFactory(&details_factory_);
348    InProcessBrowserTest::SetUp();
349  }
350
351  virtual void TearDown() OVERRIDE {
352    InProcessBrowserTest::TearDown();
353    SafeBrowsingBlockingPage::RegisterFactory(NULL);
354    SafeBrowsingService::RegisterFactory(NULL);
355    MalwareDetails::RegisterFactory(NULL);
356  }
357
358  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
359    ASSERT_TRUE(test_server()->Start());
360  }
361
362  void SetURLThreatType(const GURL& url, SBThreatType threat_type) {
363    FakeSafeBrowsingService* service =
364        static_cast<FakeSafeBrowsingService*>(
365            g_browser_process->safe_browsing_service());
366
367    ASSERT_TRUE(service);
368    service->fake_database_manager()->SetURLThreatType(url, threat_type);
369  }
370
371  // Adds a safebrowsing result of type |threat_type| to the fake safebrowsing
372  // service, navigates to that page, and returns the url.
373  GURL SetupWarningAndNavigate(SBThreatType threat_type) {
374    GURL url = test_server()->GetURL(kEmptyPage);
375    SetURLThreatType(url, threat_type);
376
377    ui_test_utils::NavigateToURL(browser(), url);
378    EXPECT_TRUE(WaitForReady());
379    return url;
380  }
381
382  // Adds a safebrowsing malware result to the fake safebrowsing service,
383  // navigates to a page with an iframe containing the malware site, and
384  // returns the url of the parent page.
385  GURL SetupMalwareIframeWarningAndNavigate() {
386    GURL url = test_server()->GetURL(kMalwarePage);
387    GURL iframe_url = test_server()->GetURL(kMalwareIframe);
388    SetURLThreatType(iframe_url, SB_THREAT_TYPE_URL_MALWARE);
389
390    ui_test_utils::NavigateToURL(browser(), url);
391    EXPECT_TRUE(WaitForReady());
392    return url;
393  }
394
395  void SendCommand(const std::string& command) {
396    WebContents* contents =
397        browser()->tab_strip_model()->GetActiveWebContents();
398    // We use InterstitialPage::GetInterstitialPage(tab) instead of
399    // tab->GetInterstitialPage() because the tab doesn't have a pointer
400    // to its interstital page until it gets a command from the renderer
401    // that it has indeed displayed it -- and this sometimes happens after
402    // NavigateToURL returns.
403    SafeBrowsingBlockingPage* interstitial_page =
404        static_cast<SafeBrowsingBlockingPage*>(
405            InterstitialPage::GetInterstitialPage(contents)->
406                GetDelegateForTesting());
407    ASSERT_TRUE(interstitial_page);
408    interstitial_page->CommandReceived(command);
409  }
410
411  void DontProceedThroughInterstitial() {
412    WebContents* contents =
413        browser()->tab_strip_model()->GetActiveWebContents();
414    InterstitialPage* interstitial_page = InterstitialPage::GetInterstitialPage(
415        contents);
416    ASSERT_TRUE(interstitial_page);
417    interstitial_page->DontProceed();
418  }
419
420  void ProceedThroughInterstitial() {
421    WebContents* contents =
422        browser()->tab_strip_model()->GetActiveWebContents();
423    InterstitialPage* interstitial_page = InterstitialPage::GetInterstitialPage(
424        contents);
425    ASSERT_TRUE(interstitial_page);
426    interstitial_page->Proceed();
427  }
428
429  void AssertNoInterstitial(bool wait_for_delete) {
430    WebContents* contents =
431        browser()->tab_strip_model()->GetActiveWebContents();
432
433    if (contents->ShowingInterstitialPage() && wait_for_delete) {
434      // We'll get notified when the interstitial is deleted.
435      TestSafeBrowsingBlockingPage* page =
436          static_cast<TestSafeBrowsingBlockingPage*>(
437              contents->GetInterstitialPage()->GetDelegateForTesting());
438      page->WaitForDelete();
439    }
440
441    // Can't use InterstitialPage::GetInterstitialPage() because that
442    // gets updated after the TestSafeBrowsingBlockingPage destructor
443    ASSERT_FALSE(contents->ShowingInterstitialPage());
444  }
445
446  bool YesInterstitial() {
447    WebContents* contents =
448        browser()->tab_strip_model()->GetActiveWebContents();
449    InterstitialPage* interstitial_page = InterstitialPage::GetInterstitialPage(
450        contents);
451    return interstitial_page != NULL;
452  }
453
454  void WaitForInterstitial() {
455    WebContents* contents =
456        browser()->tab_strip_model()->GetActiveWebContents();
457    scoped_refptr<content::MessageLoopRunner> loop_runner(
458        new content::MessageLoopRunner);
459    InterstitialObserver observer(contents,
460                                  loop_runner->QuitClosure(),
461                                  base::Closure());
462    if (!InterstitialPage::GetInterstitialPage(contents))
463      loop_runner->Run();
464  }
465
466  void AssertReportSent() {
467    // When a report is scheduled in the IO thread we should get notified.
468    content::RunMessageLoop();
469
470    std::string serialized = factory_.most_recent_service()->
471        fake_ui_manager()->GetReport();
472
473    safe_browsing::ClientMalwareReportRequest report;
474    ASSERT_TRUE(report.ParseFromString(serialized));
475
476    // Verify the report is complete.
477    EXPECT_TRUE(report.complete());
478  }
479
480  void MalwareRedirectCancelAndProceed(const std::string open_function) {
481    GURL load_url = test_server()->GetURL(
482        "files/safe_browsing/interstitial_cancel.html");
483    GURL malware_url("http://localhost/files/safe_browsing/malware.html");
484    SetURLThreatType(malware_url, SB_THREAT_TYPE_URL_MALWARE);
485
486    // Load the test page.
487    ui_test_utils::NavigateToURL(browser(), load_url);
488    // Trigger the safe browsing interstitial page via a redirect in
489    // "openWin()".
490    ui_test_utils::NavigateToURLWithDisposition(
491        browser(),
492        GURL("javascript:" + open_function + "()"),
493        CURRENT_TAB,
494        ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
495    WaitForInterstitial();
496    // Cancel the redirect request while interstitial page is open.
497    browser()->tab_strip_model()->ActivateTabAt(0, true);
498    ui_test_utils::NavigateToURLWithDisposition(
499        browser(),
500        GURL("javascript:stopWin()"),
501        CURRENT_TAB,
502        ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
503    browser()->tab_strip_model()->ActivateTabAt(1, true);
504    // Simulate the user clicking "proceed", there should be no crash.  Since
505    // clicking proceed may do nothing (see comment in MalwareRedirectCanceled
506    // below, and crbug.com/76460), we use SendCommand to trigger the callback
507    // directly rather than using ClickAndWaitForDetach since there might not
508    // be a notification to wait for.
509    SendCommand("\"proceed\"");
510  }
511
512  content::RenderViewHost* GetRenderViewHost() {
513    InterstitialPage* interstitial = InterstitialPage::GetInterstitialPage(
514        browser()->tab_strip_model()->GetActiveWebContents());
515    if (!interstitial)
516      return NULL;
517    return interstitial->GetRenderViewHostForTesting();
518  }
519
520  bool WaitForReady() {
521    content::RenderViewHost* rvh = GetRenderViewHost();
522    if (!rvh)
523      return false;
524    // Wait until all <script> tags have executed, including jstemplate.
525    // TODO(joaodasilva): it would be nice to avoid the busy loop, though in
526    // practice it spins at most once or twice.
527    std::string ready_state;
528    do {
529      scoped_ptr<base::Value> value = content::ExecuteScriptAndGetValue(
530          rvh, "document.readyState");
531      if (!value.get() || !value->GetAsString(&ready_state))
532        return false;
533    } while (ready_state != "complete");
534    return true;
535  }
536
537  Visibility GetVisibility(const std::string& node_id) {
538    content::RenderViewHost* rvh = GetRenderViewHost();
539    if (!rvh)
540      return VISIBILITY_ERROR;
541    scoped_ptr<base::Value> value = content::ExecuteScriptAndGetValue(
542        rvh,
543        "var node = document.getElementById('" + node_id + "');\n"
544        "if (node)\n"
545        "   node.offsetWidth > 0 && node.offsetHeight > 0;"
546        "else\n"
547        "  'node not found';\n");
548    if (!value.get())
549      return VISIBILITY_ERROR;
550    bool result = false;
551    if (!value->GetAsBoolean(&result))
552      return VISIBILITY_ERROR;
553    return result ? VISIBLE : HIDDEN;
554  }
555
556  bool Click(const std::string& node_id) {
557    content::RenderViewHost* rvh = GetRenderViewHost();
558    if (!rvh)
559      return false;
560    // We don't use ExecuteScriptAndGetValue for this one, since clicking
561    // the button/link may navigate away before the injected javascript can
562    // reply, hanging the test.
563    rvh->ExecuteJavascriptInWebFrame(
564        string16(),
565        ASCIIToUTF16("document.getElementById('" + node_id + "').click();\n"));
566    return true;
567  }
568
569  bool ClickAndWaitForDetach(const std::string& node_id) {
570    // We wait for interstitial_detached rather than nav_entry_committed, as
571    // going back from a main-frame malware interstitial page will not cause a
572    // nav entry committed event.
573    scoped_refptr<content::MessageLoopRunner> loop_runner(
574        new content::MessageLoopRunner);
575    InterstitialObserver observer(
576        browser()->tab_strip_model()->GetActiveWebContents(),
577        base::Closure(),
578        loop_runner->QuitClosure());
579    if (!Click(node_id))
580      return false;
581    loop_runner->Run();
582    return true;
583  }
584
585 protected:
586  TestMalwareDetailsFactory details_factory_;
587
588 private:
589  TestSafeBrowsingServiceFactory factory_;
590  TestSafeBrowsingBlockingPageFactory blocking_page_factory_;
591
592  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPageTest);
593};
594
595// TODO(linux_aura) http://crbug.com/163931
596// TODO(win_aura) http://crbug.com/154081
597#if defined(USE_AURA) && !defined(OS_CHROMEOS)
598#define MAYBE_MalwareRedirectInIFrameCanceled DISABLED_MalwareRedirectInIFrameCanceled
599#else
600#define MAYBE_MalwareRedirectInIFrameCanceled MalwareRedirectInIFrameCanceled
601#endif
602IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest,
603                       MAYBE_MalwareRedirectInIFrameCanceled) {
604  // 1. Test the case that redirect is a subresource.
605  MalwareRedirectCancelAndProceed("openWinIFrame");
606  // If the redirect was from subresource but canceled, "proceed" will continue
607  // with the rest of resources.
608  AssertNoInterstitial(true);
609}
610
611IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest,
612                       MalwareRedirectCanceled) {
613  // 2. Test the case that redirect is the only resource.
614  MalwareRedirectCancelAndProceed("openWin");
615  // Clicking proceed won't do anything if the main request is cancelled
616  // already.  See crbug.com/76460.
617  EXPECT_TRUE(YesInterstitial());
618}
619
620IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MalwareDontProceed) {
621#if defined(OS_WIN) && defined(USE_ASH)
622  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
623  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
624    return;
625#endif
626
627  SetupWarningAndNavigate(SB_THREAT_TYPE_URL_MALWARE);
628
629  EXPECT_EQ(VISIBLE, GetVisibility("malware-icon"));
630  EXPECT_EQ(HIDDEN, GetVisibility("subresource-icon"));
631  EXPECT_EQ(HIDDEN, GetVisibility("phishing-icon"));
632  EXPECT_EQ(VISIBLE, GetVisibility("check-report"));
633  EXPECT_EQ(HIDDEN, GetVisibility("show-diagnostic-link"));
634  EXPECT_EQ(HIDDEN, GetVisibility("report-error-link"));
635  EXPECT_EQ(HIDDEN, GetVisibility("proceed"));
636  EXPECT_TRUE(Click("see-more-link"));
637  EXPECT_EQ(VISIBLE, GetVisibility("show-diagnostic-link"));
638  EXPECT_EQ(HIDDEN, GetVisibility("report-error-link"));
639  EXPECT_EQ(VISIBLE, GetVisibility("proceed"));
640
641  EXPECT_TRUE(ClickAndWaitForDetach("back"));
642  AssertNoInterstitial(false);   // Assert the interstitial is gone
643  EXPECT_EQ(
644      GURL(content::kAboutBlankURL),  // Back to "about:blank"
645      browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
646}
647
648IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MalwareProceed) {
649  GURL url = SetupWarningAndNavigate(SB_THREAT_TYPE_URL_MALWARE);
650
651  EXPECT_TRUE(ClickAndWaitForDetach("proceed"));
652  AssertNoInterstitial(true);  // Assert the interstitial is gone.
653  EXPECT_EQ(url,
654            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
655}
656
657IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest,
658                       MalwareLearnMore) {
659  SetupWarningAndNavigate(SB_THREAT_TYPE_URL_MALWARE);
660
661  EXPECT_TRUE(ClickAndWaitForDetach("learn-more-link"));
662  AssertNoInterstitial(false);  // Assert the interstitial is gone
663
664  // We are in the help page.
665  EXPECT_EQ(
666      "/goodtoknow/online-safety/malware/",
667       browser()->tab_strip_model()->GetActiveWebContents()->GetURL().path());
668}
669
670IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest,
671                       MalwareIframeDontProceed) {
672#if defined(OS_WIN) && defined(USE_ASH)
673  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
674  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
675    return;
676#endif
677
678  SetupMalwareIframeWarningAndNavigate();
679
680  EXPECT_EQ(HIDDEN, GetVisibility("malware-icon"));
681  EXPECT_EQ(VISIBLE, GetVisibility("subresource-icon"));
682  EXPECT_EQ(HIDDEN, GetVisibility("phishing-icon"));
683  EXPECT_EQ(VISIBLE, GetVisibility("check-report"));
684  EXPECT_EQ(HIDDEN, GetVisibility("show-diagnostic-link"));
685  EXPECT_EQ(HIDDEN, GetVisibility("report-error-link"));
686  EXPECT_EQ(HIDDEN, GetVisibility("proceed"));
687  EXPECT_TRUE(Click("see-more-link"));
688  EXPECT_EQ(VISIBLE, GetVisibility("show-diagnostic-link"));
689  EXPECT_EQ(HIDDEN, GetVisibility("report-error-link"));
690  EXPECT_EQ(VISIBLE, GetVisibility("proceed"));
691
692  EXPECT_TRUE(ClickAndWaitForDetach("back"));
693  AssertNoInterstitial(false);  // Assert the interstitial is gone
694
695  EXPECT_EQ(
696      GURL(content::kAboutBlankURL),  // Back to "about:blank"
697      browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
698}
699
700IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MalwareIframeProceed) {
701  GURL url = SetupMalwareIframeWarningAndNavigate();
702
703  EXPECT_TRUE(ClickAndWaitForDetach("proceed"));
704  AssertNoInterstitial(true);  // Assert the interstitial is gone
705
706  EXPECT_EQ(url,
707            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
708}
709
710IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest,
711                       MalwareIframeReportDetails) {
712  GURL url = SetupMalwareIframeWarningAndNavigate();
713
714  // If the DOM details from renderer did not already return, wait for them.
715  details_factory_.get_details()->WaitForDOM();
716
717  EXPECT_TRUE(Click("check-report"));
718
719  EXPECT_TRUE(ClickAndWaitForDetach("proceed"));
720  AssertNoInterstitial(true);  // Assert the interstitial is gone
721
722  EXPECT_TRUE(browser()->profile()->GetPrefs()->GetBoolean(
723      prefs::kSafeBrowsingReportingEnabled));
724
725  EXPECT_EQ(url,
726            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
727  AssertReportSent();
728}
729
730// Verifies that the "proceed anyway" link isn't available when it is disabled
731// by the corresponding policy. Also verifies that sending the "proceed"
732// command anyway doesn't advance to the malware site.
733IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, ProceedDisabled) {
734#if defined(OS_WIN) && defined(USE_ASH)
735  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
736  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
737    return;
738#endif
739
740  // Simulate a policy disabling the "proceed anyway" link.
741  browser()->profile()->GetPrefs()->SetBoolean(
742      prefs::kSafeBrowsingProceedAnywayDisabled, true);
743
744  SetupWarningAndNavigate(SB_THREAT_TYPE_URL_MALWARE);
745
746  EXPECT_EQ(VISIBLE, GetVisibility("check-report"));
747  EXPECT_EQ(HIDDEN, GetVisibility("show-diagnostic-link"));
748  EXPECT_EQ(HIDDEN, GetVisibility("proceed"));
749  EXPECT_EQ(HIDDEN, GetVisibility("proceed-span"));
750  EXPECT_TRUE(Click("see-more-link"));
751  EXPECT_EQ(VISIBLE, GetVisibility("show-diagnostic-link"));
752  EXPECT_EQ(HIDDEN, GetVisibility("proceed"));
753  EXPECT_EQ(HIDDEN, GetVisibility("proceed-span"));
754
755  // The "proceed" command should go back instead, if proceeding is disabled.
756  EXPECT_TRUE(ClickAndWaitForDetach("proceed"));
757  AssertNoInterstitial(true);
758  EXPECT_EQ(
759      GURL(content::kAboutBlankURL),  // Back to "about:blank"
760      browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
761}
762
763// Verifies that the reporting checkbox is hidden on non-HTTP pages.
764// TODO(mattm): Should also verify that no report is sent, but there isn't a
765// good way to do that in the current design.
766IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, ReportingDisabled) {
767#if defined(OS_WIN) && defined(USE_ASH)
768  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
769  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
770    return;
771#endif
772
773  browser()->profile()->GetPrefs()->SetBoolean(
774      prefs::kSafeBrowsingReportingEnabled, true);
775
776  net::SpawnedTestServer https_server(
777      net::SpawnedTestServer::TYPE_HTTPS, net::SpawnedTestServer::kLocalhost,
778      base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
779  ASSERT_TRUE(https_server.Start());
780  GURL url = https_server.GetURL(kEmptyPage);
781  SetURLThreatType(url, SB_THREAT_TYPE_URL_MALWARE);
782  ui_test_utils::NavigateToURL(browser(), url);
783  ASSERT_TRUE(WaitForReady());
784
785  EXPECT_EQ(HIDDEN, GetVisibility("check-report"));
786  EXPECT_EQ(HIDDEN, GetVisibility("show-diagnostic-link"));
787  EXPECT_EQ(HIDDEN, GetVisibility("proceed"));
788  EXPECT_TRUE(Click("see-more-link"));
789  EXPECT_EQ(VISIBLE, GetVisibility("show-diagnostic-link"));
790  EXPECT_EQ(VISIBLE, GetVisibility("proceed"));
791
792  EXPECT_TRUE(ClickAndWaitForDetach("back"));
793  AssertNoInterstitial(false);   // Assert the interstitial is gone
794  EXPECT_EQ(
795      GURL(content::kAboutBlankURL),  // Back to "about:blank"
796      browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
797}
798
799IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, PhishingDontProceed) {
800#if defined(OS_WIN) && defined(USE_ASH)
801  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
802  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
803    return;
804#endif
805
806  SetupWarningAndNavigate(SB_THREAT_TYPE_URL_PHISHING);
807
808  EXPECT_EQ(HIDDEN, GetVisibility("malware-icon"));
809  EXPECT_EQ(HIDDEN, GetVisibility("subresource-icon"));
810  EXPECT_EQ(VISIBLE, GetVisibility("phishing-icon"));
811  EXPECT_EQ(HIDDEN, GetVisibility("check-report"));
812  EXPECT_EQ(HIDDEN, GetVisibility("show-diagnostic-link"));
813  EXPECT_EQ(HIDDEN, GetVisibility("report-error-link"));
814  EXPECT_EQ(HIDDEN, GetVisibility("proceed"));
815  EXPECT_TRUE(Click("see-more-link"));
816  EXPECT_EQ(HIDDEN, GetVisibility("show-diagnostic-link"));
817  EXPECT_EQ(VISIBLE, GetVisibility("report-error-link"));
818  EXPECT_EQ(VISIBLE, GetVisibility("proceed"));
819
820  EXPECT_TRUE(ClickAndWaitForDetach("back"));
821  AssertNoInterstitial(false);  // Assert the interstitial is gone
822  EXPECT_EQ(
823      GURL(content::kAboutBlankURL),  // We are back to "about:blank".
824      browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
825}
826
827// http://crbug.com/247763
828#if defined(OS_WIN)
829#define MAYBE_PhishingProceed DISABLED_PhishingProceed
830#else
831#define MAYBE_PhishingProceed PhishingProceed
832#endif
833
834IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MAYBE_PhishingProceed) {
835  GURL url = SetupWarningAndNavigate(SB_THREAT_TYPE_URL_PHISHING);
836
837  EXPECT_TRUE(ClickAndWaitForDetach("proceed"));
838  AssertNoInterstitial(true);  // Assert the interstitial is gone
839  EXPECT_EQ(url,
840            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
841}
842
843IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, PhishingReportError) {
844  SetupWarningAndNavigate(SB_THREAT_TYPE_URL_PHISHING);
845
846  EXPECT_TRUE(ClickAndWaitForDetach("report-error-link"));
847  AssertNoInterstitial(false);  // Assert the interstitial is gone
848
849  // We are in the error reporting page.
850  EXPECT_EQ(
851      "/safebrowsing/report_error/",
852      browser()->tab_strip_model()->GetActiveWebContents()->GetURL().path());
853}
854
855// See crbug.com/248447
856#if defined(OS_WIN)
857#define MAYBE_PhishingLearnMore DISABLED_PhishingLearnMore
858#else
859#define MAYBE_PhishingLearnMore PhishingLearnMore
860#endif
861
862IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MAYBE_PhishingLearnMore) {
863  SetupWarningAndNavigate(SB_THREAT_TYPE_URL_PHISHING);
864
865  EXPECT_TRUE(ClickAndWaitForDetach("learn-more-link"));
866  AssertNoInterstitial(false);  // Assert the interstitial is gone
867
868  // We are in the help page.
869  EXPECT_EQ(
870      "/goodtoknow/online-safety/phishing/",
871       browser()->tab_strip_model()->GetActiveWebContents()->GetURL().path());
872}
873