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#include "base/strings/stringprintf.h"
6#include "base/strings/utf_string_conversions.h"
7#include "chrome/browser/extensions/api/permissions/permissions_api.h"
8#include "chrome/browser/extensions/extension_apitest.h"
9#include "chrome/browser/extensions/extension_service.h"
10#include "chrome/browser/ui/browser.h"
11#include "chrome/browser/ui/tabs/tab_strip_model.h"
12#include "chrome/common/chrome_switches.h"
13#include "chrome/test/base/ui_test_utils.h"
14#include "content/public/browser/web_contents.h"
15#include "content/public/test/browser_test_utils.h"
16#include "extensions/browser/notification_types.h"
17#include "extensions/common/extension.h"
18#include "extensions/test/result_catcher.h"
19#include "net/dns/mock_host_resolver.h"
20#include "net/test/embedded_test_server/embedded_test_server.h"
21#include "url/gurl.h"
22
23namespace extensions {
24
25namespace {
26
27// A fake webstore domain.
28const char kWebstoreDomain[] = "cws.com";
29
30// Check whether or not style was injected, with |expected_injection| indicating
31// the expected result. Also ensure that no CSS was added to the
32// document.styleSheets array.
33testing::AssertionResult CheckStyleInjection(Browser* browser,
34                                             const GURL& url,
35                                             bool expected_injection) {
36  ui_test_utils::NavigateToURL(browser, url);
37
38  bool css_injected = false;
39  if (!content::ExecuteScriptAndExtractBool(
40          browser->tab_strip_model()->GetActiveWebContents(),
41          "window.domAutomationController.send("
42          "    document.defaultView.getComputedStyle(document.body, null)."
43          "        getPropertyValue('display') == 'none');",
44          &css_injected)) {
45    return testing::AssertionFailure()
46        << "Failed to execute script and extract bool for injection status.";
47  }
48
49  if (css_injected != expected_injection) {
50    std::string message;
51    if (css_injected)
52      message = "CSS injected when no injection was expected.";
53    else
54      message = "CSS not injected when injection was expected.";
55    return testing::AssertionFailure() << message;
56  }
57
58  bool css_doesnt_add_to_list = false;
59  if (!content::ExecuteScriptAndExtractBool(
60          browser->tab_strip_model()->GetActiveWebContents(),
61          "window.domAutomationController.send("
62          "    document.styleSheets.length == 0);",
63          &css_doesnt_add_to_list)) {
64    return testing::AssertionFailure()
65        << "Failed to execute script and extract bool for stylesheets length.";
66  }
67  if (!css_doesnt_add_to_list) {
68    return testing::AssertionFailure()
69        << "CSS injection added to number of stylesheets.";
70  }
71
72  return testing::AssertionSuccess();
73}
74
75}  // namespace
76
77IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptAllFrames) {
78  ASSERT_TRUE(StartEmbeddedTestServer());
79  ASSERT_TRUE(RunExtensionTest("content_scripts/all_frames")) << message_;
80}
81
82IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptAboutBlankIframes) {
83  ASSERT_TRUE(StartEmbeddedTestServer());
84  ASSERT_TRUE(
85      RunExtensionTest("content_scripts/about_blank_iframes")) << message_;
86}
87
88IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptAboutBlankAndSrcdoc) {
89  // The optional "*://*/*" permission is requested after verifying that
90  // content script insertion solely depends on content_scripts[*].matches.
91  // The permission is needed for chrome.tabs.executeScript tests.
92  PermissionsRequestFunction::SetAutoConfirmForTests(true);
93  PermissionsRequestFunction::SetIgnoreUserGestureForTests(true);
94
95  ASSERT_TRUE(StartEmbeddedTestServer());
96  ASSERT_TRUE(RunExtensionTest("content_scripts/about_blank_srcdoc"))
97      << message_;
98}
99
100IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptExtensionIframe) {
101  ASSERT_TRUE(StartEmbeddedTestServer());
102  ASSERT_TRUE(RunExtensionTest("content_scripts/extension_iframe")) << message_;
103}
104
105IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptExtensionProcess) {
106  ASSERT_TRUE(StartEmbeddedTestServer());
107  ASSERT_TRUE(
108      RunExtensionTest("content_scripts/extension_process")) << message_;
109}
110
111IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptFragmentNavigation) {
112  ASSERT_TRUE(StartEmbeddedTestServer());
113  const char* extension_name = "content_scripts/fragment";
114  ASSERT_TRUE(RunExtensionTest(extension_name)) << message_;
115}
116
117// Times out on Linux: http://crbug.com/163097
118#if defined(OS_LINUX)
119#define MAYBE_ContentScriptIsolatedWorlds DISABLED_ContentScriptIsolatedWorlds
120#else
121#define MAYBE_ContentScriptIsolatedWorlds ContentScriptIsolatedWorlds
122#endif
123IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_ContentScriptIsolatedWorlds) {
124  // This extension runs various bits of script and tests that they all run in
125  // the same isolated world.
126  ASSERT_TRUE(StartEmbeddedTestServer());
127  ASSERT_TRUE(RunExtensionTest("content_scripts/isolated_world1")) << message_;
128
129  // Now load a different extension, inject into same page, verify worlds aren't
130  // shared.
131  ASSERT_TRUE(RunExtensionTest("content_scripts/isolated_world2")) << message_;
132}
133
134IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptIgnoreHostPermissions) {
135  host_resolver()->AddRule("a.com", "127.0.0.1");
136  host_resolver()->AddRule("b.com", "127.0.0.1");
137  ASSERT_TRUE(StartEmbeddedTestServer());
138  ASSERT_TRUE(RunExtensionTest(
139      "content_scripts/dont_match_host_permissions")) << message_;
140}
141
142// crbug.com/39249 -- content scripts js should not run on view source.
143IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptViewSource) {
144  ASSERT_TRUE(StartEmbeddedTestServer());
145  ASSERT_TRUE(RunExtensionTest("content_scripts/view_source")) << message_;
146}
147
148// crbug.com/126257 -- content scripts should not get injected into other
149// extensions.
150IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptOtherExtensions) {
151  host_resolver()->AddRule("a.com", "127.0.0.1");
152  ASSERT_TRUE(StartEmbeddedTestServer());
153  // First, load extension that sets up content script.
154  ASSERT_TRUE(RunExtensionTest("content_scripts/other_extensions/injector"))
155      << message_;
156  // Then load targeted extension to make sure its content isn't changed.
157  ASSERT_TRUE(RunExtensionTest("content_scripts/other_extensions/victim"))
158      << message_;
159}
160
161class ContentScriptCssInjectionTest : public ExtensionApiTest {
162 protected:
163  // TODO(rdevlin.cronin): Make a testing switch that looks like FeatureSwitch,
164  // but takes in an optional value so that we don't have to do this.
165  virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
166    ExtensionApiTest::SetUpCommandLine(command_line);
167    // We change the Webstore URL to be http://cws.com. We need to do this so
168    // we can check that css injection is not allowed on the webstore (which
169    // could lead to spoofing). Unfortunately, host_resolver seems to have
170    // problems with redirecting "chrome.google.com" to the test server, so we
171    // can't use the real Webstore's URL. If this changes, we could clean this
172    // up.
173    command_line->AppendSwitchASCII(
174        switches::kAppsGalleryURL,
175        base::StringPrintf("http://%s", kWebstoreDomain));
176  }
177};
178
179IN_PROC_BROWSER_TEST_F(ContentScriptCssInjectionTest,
180                       ContentScriptInjectsStyles) {
181  ASSERT_TRUE(StartEmbeddedTestServer());
182  host_resolver()->AddRule(kWebstoreDomain, "127.0.0.1");
183
184  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("content_scripts")
185                                          .AppendASCII("css_injection")));
186
187  // CSS injection should be allowed on an aribitrary web page.
188  GURL url =
189      embedded_test_server()->GetURL("/extensions/test_file_with_body.html");
190  EXPECT_TRUE(CheckStyleInjection(browser(), url, true));
191
192  // The loaded extension has an exclude match for "extensions/test_file.html",
193  // so no CSS should be injected.
194  url = embedded_test_server()->GetURL("/extensions/test_file.html");
195  EXPECT_TRUE(CheckStyleInjection(browser(), url, false));
196
197  // We disallow all injection on the webstore.
198  GURL::Replacements replacements;
199  std::string host(kWebstoreDomain);
200  replacements.SetHostStr(host);
201  url = embedded_test_server()->GetURL("/extensions/test_file_with_body.html")
202            .ReplaceComponents(replacements);
203  EXPECT_TRUE(CheckStyleInjection(browser(), url, false));
204}
205
206// crbug.com/120762
207IN_PROC_BROWSER_TEST_F(
208    ExtensionApiTest,
209    DISABLED_ContentScriptStylesInjectedIntoExistingRenderers) {
210  ASSERT_TRUE(StartEmbeddedTestServer());
211
212  content::WindowedNotificationObserver signal(
213      extensions::NOTIFICATION_USER_SCRIPTS_UPDATED,
214      content::Source<Profile>(browser()->profile()));
215
216  // Start with a renderer already open at a URL.
217  GURL url(test_server()->GetURL("file/extensions/test_file.html"));
218  ui_test_utils::NavigateToURL(browser(), url);
219
220  LoadExtension(
221      test_data_dir_.AppendASCII("content_scripts/existing_renderers"));
222
223  signal.Wait();
224
225  // And check that its styles were affected by the styles that just got loaded.
226  bool styles_injected;
227  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
228      browser()->tab_strip_model()->GetActiveWebContents(),
229      "window.domAutomationController.send("
230      "    document.defaultView.getComputedStyle(document.body, null)."
231      "        getPropertyValue('background-color') == 'rgb(255, 0, 0)')",
232      &styles_injected));
233  ASSERT_TRUE(styles_injected);
234}
235
236IN_PROC_BROWSER_TEST_F(ExtensionApiTest,
237                       ContentScriptCSSLocalization) {
238  ASSERT_TRUE(StartEmbeddedTestServer());
239  ASSERT_TRUE(RunExtensionTest("content_scripts/css_l10n")) << message_;
240}
241
242IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptExtensionAPIs) {
243  ASSERT_TRUE(StartEmbeddedTestServer());
244
245  const extensions::Extension* extension = LoadExtension(
246      test_data_dir_.AppendASCII("content_scripts/extension_api"));
247
248  ResultCatcher catcher;
249  ui_test_utils::NavigateToURL(
250      browser(),
251      embedded_test_server()->GetURL(
252          "/extensions/api_test/content_scripts/extension_api/functions.html"));
253  EXPECT_TRUE(catcher.GetNextResult());
254
255  // Navigate to a page that will cause a content script to run that starts
256  // listening for an extension event.
257  ui_test_utils::NavigateToURL(
258      browser(),
259      embedded_test_server()->GetURL(
260          "/extensions/api_test/content_scripts/extension_api/events.html"));
261
262  // Navigate to an extension page that will fire the event events.js is
263  // listening for.
264  ui_test_utils::NavigateToURLWithDisposition(
265      browser(), extension->GetResourceURL("fire_event.html"),
266      NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_NONE);
267  EXPECT_TRUE(catcher.GetNextResult());
268}
269
270// Flaky on Windows. http://crbug.com/248418
271#if defined(OS_WIN)
272#define MAYBE_ContentScriptPermissionsApi DISABLED_ContentScriptPermissionsApi
273#else
274#define MAYBE_ContentScriptPermissionsApi ContentScriptPermissionsApi
275#endif
276IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_ContentScriptPermissionsApi) {
277  extensions::PermissionsRequestFunction::SetIgnoreUserGestureForTests(true);
278  extensions::PermissionsRequestFunction::SetAutoConfirmForTests(true);
279  host_resolver()->AddRule("*.com", "127.0.0.1");
280  ASSERT_TRUE(StartEmbeddedTestServer());
281  ASSERT_TRUE(RunExtensionTest("content_scripts/permissions")) << message_;
282}
283
284IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptBypassPageCSP) {
285  ASSERT_TRUE(StartEmbeddedTestServer());
286  ASSERT_TRUE(RunExtensionTest("content_scripts/bypass_page_csp")) << message_;
287}
288
289}  // namespace extensions
290