1 // Copyright 2019 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 "base/files/file_util.h"
6 #include "base/test/simple_test_clock.h"
7 #include "base/threading/thread_restrictions.h"
8 #include "chrome/browser/infobars/infobar_service.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/ssl/known_interception_disclosure_infobar_delegate.h"
11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/test/base/in_process_browser_test.h"
13 #include "chrome/test/base/ui_test_utils.h"
14 #include "components/infobars/core/confirm_infobar_delegate.h"
15 #include "components/infobars/core/infobar.h"
16 #include "content/public/browser/network_service_instance.h"
17 #include "content/public/test/browser_test.h"
18 #include "content/public/test/browser_test_utils.h"
19 #include "net/cert/crl_set.h"
20 #include "net/test/embedded_test_server/embedded_test_server.h"
21 #include "net/test/test_data_directory.h"
22 #include "ui/base/window_open_disposition.h"
23 
24 namespace {
25 
GetInfobarCount(content::WebContents * contents)26 size_t GetInfobarCount(content::WebContents* contents) {
27   InfoBarService* infobar_service = InfoBarService::FromWebContents(contents);
28   if (!infobar_service)
29     return 0;
30   return infobar_service->infobar_count();
31 }
32 
GetInfobar(content::WebContents * contents)33 infobars::InfoBar* GetInfobar(content::WebContents* contents) {
34   InfoBarService* infobar_service = InfoBarService::FromWebContents(contents);
35   DCHECK(infobar_service);
36   return infobar_service->infobar_at(0);
37 }
38 
39 // Follows same logic as clicking the "Continue" button would.
CloseInfobar(content::WebContents * contents)40 void CloseInfobar(content::WebContents* contents) {
41   infobars::InfoBar* infobar = GetInfobar(contents);
42   if (!infobar)
43     return;
44 
45   ConfirmInfoBarDelegate* delegate =
46       static_cast<ConfirmInfoBarDelegate*>(infobar->delegate());
47   delegate->Accept();
48   infobar->RemoveSelf();
49 }
50 
51 }  // namespace
52 
53 class KnownInterceptionDisclosureInfobarTest : public InProcessBrowserTest {
54  public:
KnownInterceptionDisclosureInfobarTest()55   KnownInterceptionDisclosureInfobarTest()
56       : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
57     https_server_.AddDefaultHandlers(GetChromeTestDataDir());
58   }
59 
60   KnownInterceptionDisclosureInfobarTest(
61       const KnownInterceptionDisclosureInfobarTest&) = delete;
62   KnownInterceptionDisclosureInfobarTest& operator=(
63       const KnownInterceptionDisclosureInfobarTest&) = delete;
64 
SetUpOnMainThread()65   void SetUpOnMainThread() override {
66     ASSERT_TRUE(https_server_.Start());
67 
68     // Load a CRLSet that marks the root as a known MITM.
69     std::string crl_set_bytes;
70     {
71       base::ScopedAllowBlockingForTesting allow_blocking;
72       base::ReadFileToString(net::GetTestCertsDirectory().AppendASCII(
73                                  "crlset_known_interception_by_root.raw"),
74                              &crl_set_bytes);
75     }
76     network::mojom::NetworkService* network_service =
77         content::GetNetworkService();
78     DCHECK(network_service);
79     base::RunLoop run_loop;
80     network_service->UpdateCRLSet(
81         base::as_bytes(base::make_span(crl_set_bytes)), run_loop.QuitClosure());
82     run_loop.Run();
83   }
84 
85  protected:
86   net::EmbeddedTestServer https_server_;
87 };
88 
IN_PROC_BROWSER_TEST_F(KnownInterceptionDisclosureInfobarTest,OnlyShowDisclosureOncePerSession)89 IN_PROC_BROWSER_TEST_F(KnownInterceptionDisclosureInfobarTest,
90                        OnlyShowDisclosureOncePerSession) {
91   const GURL kInterceptedUrl(https_server_.GetURL("/ssl/google.html"));
92 
93   TabStripModel* tab_strip_model = browser()->tab_strip_model();
94   content::WebContents* tab1 = tab_strip_model->GetActiveWebContents();
95 
96   auto* clock = new base::SimpleTestClock();
97   clock->SetNow(base::Time::Now());
98   KnownInterceptionDisclosureCooldown::GetInstance()->SetClockForTesting(
99       std::unique_ptr<base::Clock>(clock));
100 
101   // Trigger the disclosure infobar by navigating to a page served by a root
102   // marked as known interception.
103   ui_test_utils::NavigateToURL(browser(), kInterceptedUrl);
104   EXPECT_EQ(1u, GetInfobarCount(tab1));
105 
106   // Test that the infobar is shown on new tabs after it has been triggered
107   // once.
108   ui_test_utils::NavigateToURLWithDisposition(
109       browser(), GURL("about:blank"), WindowOpenDisposition::NEW_FOREGROUND_TAB,
110       ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
111   content::WebContents* tab2 = tab_strip_model->GetActiveWebContents();
112   EXPECT_EQ(1u, GetInfobarCount(tab2));
113 
114   // Close the new tab.
115   tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(),
116                                       TabStripModel::CLOSE_USER_GESTURE);
117 
118   // Reload the first page -- infobar should still show.
119   ui_test_utils::NavigateToURL(browser(), kInterceptedUrl);
120   EXPECT_EQ(1u, GetInfobarCount(tab1));
121 
122   // Dismiss the infobar.
123   CloseInfobar(tab1);
124   EXPECT_EQ(0u, GetInfobarCount(tab1));
125 
126   // Try to trigger again by reloading the page -- infobar should not show.
127   ui_test_utils::NavigateToURL(browser(), kInterceptedUrl);
128   EXPECT_EQ(0u, GetInfobarCount(tab1));
129 
130   // Move clock ahead 8 days.
131   clock->Advance(base::TimeDelta::FromDays(8));
132 
133   // Trigger the infobar again -- infobar should show again.
134   ui_test_utils::NavigateToURL(browser(), kInterceptedUrl);
135   EXPECT_EQ(1u, GetInfobarCount(tab1));
136 }
137 
IN_PROC_BROWSER_TEST_F(KnownInterceptionDisclosureInfobarTest,PRE_CooldownResetsOnBrowserRestartDesktop)138 IN_PROC_BROWSER_TEST_F(KnownInterceptionDisclosureInfobarTest,
139                        PRE_CooldownResetsOnBrowserRestartDesktop) {
140   const GURL kInterceptedUrl(https_server_.GetURL("/ssl/google.html"));
141 
142   // Trigger the disclosure infobar.
143   content::WebContents* tab =
144       browser()->tab_strip_model()->GetActiveWebContents();
145   ui_test_utils::NavigateToURL(browser(), kInterceptedUrl);
146   EXPECT_EQ(1u, GetInfobarCount(tab));
147 
148   // Dismiss the infobar.
149   CloseInfobar(tab);
150   EXPECT_EQ(0u, GetInfobarCount(tab));
151 }
152 
IN_PROC_BROWSER_TEST_F(KnownInterceptionDisclosureInfobarTest,CooldownResetsOnBrowserRestartDesktop)153 IN_PROC_BROWSER_TEST_F(KnownInterceptionDisclosureInfobarTest,
154                        CooldownResetsOnBrowserRestartDesktop) {
155   const GURL kInterceptedUrl(https_server_.GetURL("/ssl/google.html"));
156 
157   // On restart, no infobar should be shown initially.
158   content::WebContents* tab =
159       browser()->tab_strip_model()->GetActiveWebContents();
160   EXPECT_EQ(0u, GetInfobarCount(tab));
161 
162   // Triggering the disclosure infobar again after browser restart should show
163   // the infobar (the cooldown period should no longer apply on Desktop).
164   ui_test_utils::NavigateToURL(browser(), kInterceptedUrl);
165   EXPECT_EQ(1u, GetInfobarCount(tab));
166 }
167