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

Side by Side Diff: chrome/browser/extensions/active_script_controller_browsertest.cc

Issue 313453002: Resubmit: Block content scripts from executing until user grants permission (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Latest master Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/files/file_path.h" 5 #include "base/files/file_path.h"
6 #include "base/macros.h" 6 #include "base/macros.h"
7 #include "base/strings/stringprintf.h" 7 #include "base/strings/stringprintf.h"
8 #include "chrome/browser/extensions/active_script_controller.h" 8 #include "chrome/browser/extensions/active_script_controller.h"
9 #include "chrome/browser/extensions/extension_action.h" 9 #include "chrome/browser/extensions/extension_action.h"
10 #include "chrome/browser/extensions/extension_browsertest.h" 10 #include "chrome/browser/extensions/extension_browsertest.h"
11 #include "chrome/browser/extensions/extension_test_message_listener.h" 11 #include "chrome/browser/extensions/extension_test_message_listener.h"
12 #include "chrome/browser/extensions/location_bar_controller.h" 12 #include "chrome/browser/extensions/location_bar_controller.h"
13 #include "chrome/browser/extensions/tab_helper.h" 13 #include "chrome/browser/extensions/tab_helper.h"
14 #include "chrome/browser/extensions/test_extension_dir.h" 14 #include "chrome/browser/extensions/test_extension_dir.h"
15 #include "chrome/browser/ui/browser.h" 15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/tabs/tab_strip_model.h" 16 #include "chrome/browser/ui/tabs/tab_strip_model.h"
17 #include "chrome/test/base/ui_test_utils.h" 17 #include "chrome/test/base/ui_test_utils.h"
18 #include "content/public/test/browser_test_utils.h"
18 #include "extensions/common/feature_switch.h" 19 #include "extensions/common/feature_switch.h"
20 #include "extensions/common/switches.h"
19 #include "net/test/embedded_test_server/embedded_test_server.h" 21 #include "net/test/embedded_test_server/embedded_test_server.h"
20 #include "testing/gtest/include/gtest/gtest.h" 22 #include "testing/gtest/include/gtest/gtest.h"
21 23
22 namespace extensions { 24 namespace extensions {
23 25
24 namespace { 26 namespace {
25 27
26 const char kAllHostsScheme[] = "*://*/*"; 28 const char kAllHostsScheme[] = "*://*/*";
27 const char kExplicitHostsScheme[] = "http://127.0.0.1/*"; 29 const char kExplicitHostsScheme[] = "http://127.0.0.1/*";
28 const char kBackgroundScript[] = 30 const char kBackgroundScript[] =
(...skipping 25 matching lines...) Expand all
54 56
55 enum RequiresConsent { 57 enum RequiresConsent {
56 REQUIRES_CONSENT, 58 REQUIRES_CONSENT,
57 DOES_NOT_REQUIRE_CONSENT 59 DOES_NOT_REQUIRE_CONSENT
58 }; 60 };
59 61
60 } // namespace 62 } // namespace
61 63
62 class ActiveScriptControllerBrowserTest : public ExtensionBrowserTest { 64 class ActiveScriptControllerBrowserTest : public ExtensionBrowserTest {
63 public: 65 public:
64 ActiveScriptControllerBrowserTest() 66 ActiveScriptControllerBrowserTest() {}
65 : feature_override_(FeatureSwitch::scripts_require_action(),
66 FeatureSwitch::OVERRIDE_ENABLED) {}
67 67
68 virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE;
68 virtual void CleanUpOnMainThread() OVERRIDE; 69 virtual void CleanUpOnMainThread() OVERRIDE;
69 70
70 // Returns an extension with the given |host_type| and |injection_type|. If 71 // Returns an extension with the given |host_type| and |injection_type|. If
71 // one already exists, the existing extension will be returned. Othewrwise, 72 // one already exists, the existing extension will be returned. Othewrwise,
72 // one will be created. 73 // one will be created.
73 // This could potentially return NULL if LoadExtension() fails. 74 // This could potentially return NULL if LoadExtension() fails.
74 const Extension* GetOrCreateExtension(HostType host_type, 75 const Extension* CreateExtension(HostType host_type,
75 InjectionType injection_type); 76 InjectionType injection_type);
76 77
77 private: 78 private:
78 FeatureSwitch::ScopedOverride feature_override_;
79 ScopedVector<TestExtensionDir> test_extension_dirs_; 79 ScopedVector<TestExtensionDir> test_extension_dirs_;
80 std::vector<const Extension*> extensions_; 80 std::vector<const Extension*> extensions_;
81 }; 81 };
82 82
83 void ActiveScriptControllerBrowserTest::SetUpCommandLine(
84 base::CommandLine* command_line) {
85 ExtensionBrowserTest::SetUpCommandLine(command_line);
86 // We append the actual switch to the commandline because it needs to be
87 // passed over to the renderer, which a FeatureSwitch::ScopedOverride will
88 // not do.
89 command_line->AppendSwitch(switches::kEnableScriptsRequireAction);
90 }
91
83 void ActiveScriptControllerBrowserTest::CleanUpOnMainThread() { 92 void ActiveScriptControllerBrowserTest::CleanUpOnMainThread() {
84 test_extension_dirs_.clear(); 93 test_extension_dirs_.clear();
85 } 94 }
86 95
87 const Extension* ActiveScriptControllerBrowserTest::GetOrCreateExtension( 96 const Extension* ActiveScriptControllerBrowserTest::CreateExtension(
88 HostType host_type, InjectionType injection_type) { 97 HostType host_type, InjectionType injection_type) {
89 std::string name = 98 std::string name =
90 base::StringPrintf( 99 base::StringPrintf(
91 "%s %s", 100 "%s %s",
92 injection_type == CONTENT_SCRIPT ? 101 injection_type == CONTENT_SCRIPT ?
93 "content_script" : "execute_script", 102 "content_script" : "execute_script",
94 host_type == ALL_HOSTS ? "all_hosts" : "explicit_hosts"); 103 host_type == ALL_HOSTS ? "all_hosts" : "explicit_hosts");
95 104
96 for (std::vector<const Extension*>::const_iterator iter = extensions_.begin();
97 iter != extensions_.end();
98 ++iter) {
99 if ((*iter)->name() == name)
100 return *iter;
101 }
102
103 const char* permission_scheme = 105 const char* permission_scheme =
104 host_type == ALL_HOSTS ? kAllHostsScheme : kExplicitHostsScheme; 106 host_type == ALL_HOSTS ? kAllHostsScheme : kExplicitHostsScheme;
105 107
106 std::string permissions = base::StringPrintf( 108 std::string permissions = base::StringPrintf(
107 "\"permissions\": [\"tabs\", \"%s\"]", permission_scheme); 109 "\"permissions\": [\"tabs\", \"%s\"]", permission_scheme);
108 110
109 std::string scripts; 111 std::string scripts;
110 std::string script_source; 112 std::string script_source;
111 if (injection_type == CONTENT_SCRIPT) { 113 if (injection_type == CONTENT_SCRIPT) {
112 scripts = base::StringPrintf( 114 scripts = base::StringPrintf(
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 261
260 // If the extension has permission, we should be able to simply wait for it 262 // If the extension has permission, we should be able to simply wait for it
261 // to execute. 263 // to execute.
262 if (requires_consent_ == DOES_NOT_REQUIRE_CONSENT) { 264 if (requires_consent_ == DOES_NOT_REQUIRE_CONSENT) {
263 inject_success_listener_->WaitUntilSatisfied(); 265 inject_success_listener_->WaitUntilSatisfied();
264 return testing::AssertionSuccess(); 266 return testing::AssertionSuccess();
265 } 267 }
266 268
267 // Otherwise, we don't have permission, and have to grant it. Ensure the 269 // Otherwise, we don't have permission, and have to grant it. Ensure the
268 // script has *not* already executed. 270 // script has *not* already executed.
269 // Currently, it's okay for content scripts to execute, because we don't 271 if (inject_success_listener_->was_satisfied()) {
270 // block them.
271 // TODO(rdevlin.cronin): Fix this.
272 if (inject_success_listener_->was_satisfied() && type_ != CONTENT_SCRIPT) {
273 return testing::AssertionFailure() << 272 return testing::AssertionFailure() <<
274 name_ << "'s script ran without permission."; 273 name_ << "'s script ran without permission.";
275 } 274 }
276 275
277 // If we reach this point, we should always have an action. 276 // If we reach this point, we should always have an action.
278 DCHECK(action); 277 DCHECK(action);
279 278
280 // Grant permission by clicking on the extension action. 279 // Grant permission by clicking on the extension action.
281 location_bar_controller->OnClicked(action); 280 location_bar_controller->OnClicked(action);
282 281
(...skipping 26 matching lines...) Expand all
309 return location_bar_controller ? 308 return location_bar_controller ?
310 location_bar_controller->active_script_controller() : NULL; 309 location_bar_controller->active_script_controller() : NULL;
311 } 310 }
312 311
313 ExtensionAction* ActiveScriptTester::GetAction() { 312 ExtensionAction* ActiveScriptTester::GetAction() {
314 ActiveScriptController* controller = GetActiveScriptController(); 313 ActiveScriptController* controller = GetActiveScriptController();
315 return controller ? controller->GetActionForExtension(extension_) : NULL; 314 return controller ? controller->GetActionForExtension(extension_) : NULL;
316 } 315 }
317 316
318 IN_PROC_BROWSER_TEST_F(ActiveScriptControllerBrowserTest, 317 IN_PROC_BROWSER_TEST_F(ActiveScriptControllerBrowserTest,
319 ActiveScriptsAreDisplayed) { 318 ActiveScriptsAreDisplayedAndDelayExecution) {
320 base::FilePath active_script_path = 319 base::FilePath active_script_path =
321 test_data_dir_.AppendASCII("active_script"); 320 test_data_dir_.AppendASCII("active_script");
322 321
323 const char* kExtensionNames[] = { 322 const char* kExtensionNames[] = {
324 "inject_scripts_all_hosts", 323 "inject_scripts_all_hosts",
325 "inject_scripts_explicit_hosts", 324 "inject_scripts_explicit_hosts",
326 "content_scripts_all_hosts", 325 "content_scripts_all_hosts",
327 "content_scripts_explicit_hosts" 326 "content_scripts_explicit_hosts"
328 }; 327 };
329 328
330 // First, we load up three extensions: 329 // First, we load up three extensions:
331 // - An extension that injects scripts into all hosts, 330 // - An extension that injects scripts into all hosts,
332 // - An extension that injects scripts into explicit hosts, 331 // - An extension that injects scripts into explicit hosts,
333 // - An extension with a content script that runs on all hosts, 332 // - An extension with a content script that runs on all hosts,
334 // - An extension with a content script that runs on explicit hosts. 333 // - An extension with a content script that runs on explicit hosts.
335 // The extensions that operate on explicit hosts have permission; the ones 334 // The extensions that operate on explicit hosts have permission; the ones
336 // that request all hosts require user consent. 335 // that request all hosts require user consent.
337 ActiveScriptTester testers[] = { 336 ActiveScriptTester testers[] = {
338 ActiveScriptTester( 337 ActiveScriptTester(
339 kExtensionNames[0], 338 kExtensionNames[0],
340 GetOrCreateExtension(ALL_HOSTS, EXECUTE_SCRIPT), 339 CreateExtension(ALL_HOSTS, EXECUTE_SCRIPT),
341 browser(), 340 browser(),
342 REQUIRES_CONSENT, 341 REQUIRES_CONSENT,
343 EXECUTE_SCRIPT), 342 EXECUTE_SCRIPT),
344 ActiveScriptTester( 343 ActiveScriptTester(
345 kExtensionNames[1], 344 kExtensionNames[1],
346 GetOrCreateExtension(EXPLICIT_HOSTS, EXECUTE_SCRIPT), 345 CreateExtension(EXPLICIT_HOSTS, EXECUTE_SCRIPT),
347 browser(), 346 browser(),
348 DOES_NOT_REQUIRE_CONSENT, 347 DOES_NOT_REQUIRE_CONSENT,
349 EXECUTE_SCRIPT), 348 EXECUTE_SCRIPT),
350 ActiveScriptTester( 349 ActiveScriptTester(
351 kExtensionNames[2], 350 kExtensionNames[2],
352 GetOrCreateExtension(ALL_HOSTS, CONTENT_SCRIPT), 351 CreateExtension(ALL_HOSTS, CONTENT_SCRIPT),
353 browser(), 352 browser(),
354 REQUIRES_CONSENT, 353 REQUIRES_CONSENT,
355 CONTENT_SCRIPT), 354 CONTENT_SCRIPT),
356 ActiveScriptTester( 355 ActiveScriptTester(
357 kExtensionNames[3], 356 kExtensionNames[3],
358 GetOrCreateExtension(EXPLICIT_HOSTS, CONTENT_SCRIPT), 357 CreateExtension(EXPLICIT_HOSTS, CONTENT_SCRIPT),
359 browser(), 358 browser(),
360 DOES_NOT_REQUIRE_CONSENT, 359 DOES_NOT_REQUIRE_CONSENT,
361 CONTENT_SCRIPT), 360 CONTENT_SCRIPT),
362 }; 361 };
363 362
364 // Navigate to an URL (which matches the explicit host specified in the 363 // Navigate to an URL (which matches the explicit host specified in the
365 // extension content_scripts_explicit_hosts). All three extensions should 364 // extension content_scripts_explicit_hosts). All four extensions should
366 // inject the script. 365 // inject the script.
367 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 366 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
368 ui_test_utils::NavigateToURL( 367 ui_test_utils::NavigateToURL(
369 browser(), embedded_test_server()->GetURL("/extensions/test_file.html")); 368 browser(), embedded_test_server()->GetURL("/extensions/test_file.html"));
370 369
371 for (size_t i = 0u; i < arraysize(testers); ++i) 370 for (size_t i = 0u; i < arraysize(testers); ++i)
372 EXPECT_TRUE(testers[i].Verify()) << kExtensionNames[i]; 371 EXPECT_TRUE(testers[i].Verify()) << kExtensionNames[i];
373 } 372 }
374 373
374 // Test that removing an extension with pending injections a) removes the
375 // pending injections for that extension, and b) does not affect pending
376 // injections for other extensions.
377 IN_PROC_BROWSER_TEST_F(ActiveScriptControllerBrowserTest,
378 RemoveExtensionWithPendingInjections) {
379 // Load up two extensions, each with content scripts.
380 const Extension* extension1 = CreateExtension(ALL_HOSTS, CONTENT_SCRIPT);
381 ASSERT_TRUE(extension1);
382 const Extension* extension2 = CreateExtension(ALL_HOSTS, CONTENT_SCRIPT);
383 ASSERT_TRUE(extension2);
384
385 ASSERT_NE(extension1->id(), extension2->id());
386
387 content::WebContents* web_contents =
388 browser()->tab_strip_model()->GetActiveWebContents();
389 ASSERT_TRUE(web_contents);
390 ActiveScriptController* active_script_controller =
391 ActiveScriptController::GetForWebContents(web_contents);
392 ASSERT_TRUE(active_script_controller);
393
394 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
395 ui_test_utils::NavigateToURL(
396 browser(), embedded_test_server()->GetURL("/extensions/test_file.html"));
397
398 // Both extensions should have pending requests.
399 EXPECT_TRUE(active_script_controller->GetActionForExtension(extension1));
400 EXPECT_TRUE(active_script_controller->GetActionForExtension(extension2));
401
402 // Unload one of the extensions.
403 UnloadExtension(extension2->id());
404
405 // This is slight hack to achieve a RunPendingInRenderer() method. Since IPCs
406 // are sent synchronously, the renderer will be notified of the extension
407 // being unloaded before the script is executed, and, since ExecuteScript() is
408 // synchronous, the renderer is guaranteed to be done updating scripts.
409 EXPECT_TRUE(content::ExecuteScript(web_contents, "1 == 1;"));
410
411 // We should have pending requests for extension1, but not the removed
412 // extension2.
413 EXPECT_TRUE(active_script_controller->GetActionForExtension(extension1));
414 EXPECT_FALSE(active_script_controller->GetActionForExtension(extension2));
415
416 // We should still be able to run the request for extension1.
417 ExtensionTestMessageListener inject_success_listener(
418 new ExtensionTestMessageListener(kInjectSucceeded,
419 false /* won't reply */));
420 inject_success_listener.set_extension_id(extension1->id());
421 active_script_controller->OnClicked(extension1);
422 inject_success_listener.WaitUntilSatisfied();
423 }
424
425 // A version of the test with the flag off, in order to test that everything
426 // still works as expected.
427 class FlagOffActiveScriptControllerBrowserTest
428 : public ActiveScriptControllerBrowserTest {
429 private:
430 // Simply don't append the flag.
431 virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
432 ExtensionBrowserTest::SetUpCommandLine(command_line);
433 }
434 };
435
436 IN_PROC_BROWSER_TEST_F(FlagOffActiveScriptControllerBrowserTest,
437 ScriptsExecuteWhenFlagAbsent) {
438 const char* kExtensionNames[] = {
439 "content_scripts_all_hosts",
440 "inject_scripts_all_hosts",
441 };
442 ActiveScriptTester testers[] = {
443 ActiveScriptTester(
444 kExtensionNames[0],
445 CreateExtension(ALL_HOSTS, CONTENT_SCRIPT),
446 browser(),
447 DOES_NOT_REQUIRE_CONSENT,
448 CONTENT_SCRIPT),
449 ActiveScriptTester(
450 kExtensionNames[1],
451 CreateExtension(ALL_HOSTS, EXECUTE_SCRIPT),
452 browser(),
453 DOES_NOT_REQUIRE_CONSENT,
454 EXECUTE_SCRIPT),
455 };
456
457 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
458 ui_test_utils::NavigateToURL(
459 browser(), embedded_test_server()->GetURL("/extensions/test_file.html"));
460
461 for (size_t i = 0u; i < arraysize(testers); ++i)
462 EXPECT_TRUE(testers[i].Verify()) << kExtensionNames[i];
463 }
464
375 } // namespace extensions 465 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/browser/extensions/active_script_controller.cc ('k') | chrome/browser/extensions/location_bar_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698