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

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

Issue 286003004: Block tabs.executeScript() from executing until user grants permission (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 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/macros.h" 5 #include "base/macros.h"
6 #include "chrome/browser/extensions/active_script_controller.h" 6 #include "chrome/browser/extensions/active_script_controller.h"
7 #include "chrome/browser/extensions/extension_action.h" 7 #include "chrome/browser/extensions/extension_action.h"
8 #include "chrome/browser/extensions/extension_browsertest.h" 8 #include "chrome/browser/extensions/extension_browsertest.h"
9 #include "chrome/browser/extensions/extension_test_message_listener.h" 9 #include "chrome/browser/extensions/extension_test_message_listener.h"
10 #include "chrome/browser/extensions/location_bar_controller.h" 10 #include "chrome/browser/extensions/location_bar_controller.h"
11 #include "chrome/browser/extensions/tab_helper.h" 11 #include "chrome/browser/extensions/tab_helper.h"
12 #include "chrome/browser/ui/browser.h" 12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/tabs/tab_strip_model.h" 13 #include "chrome/browser/ui/tabs/tab_strip_model.h"
14 #include "chrome/test/base/ui_test_utils.h" 14 #include "chrome/test/base/ui_test_utils.h"
15 #include "extensions/common/feature_switch.h" 15 #include "extensions/common/feature_switch.h"
16 #include "net/test/embedded_test_server/embedded_test_server.h" 16 #include "net/test/embedded_test_server/embedded_test_server.h"
17 #include "testing/gtest/include/gtest/gtest.h" 17 #include "testing/gtest/include/gtest/gtest.h"
18 18
19 namespace extensions { 19 namespace extensions {
20 20
21 namespace {
22
23 const char kInjectAttempted[] = "inject attempted";
24 const char kInjectSucceeded[] = "inject succeeded";
25
26 enum InjectionType {
27 CONTENT_SCRIPT,
28 EXECUTE_SCRIPT
29 };
30
31 enum RequiresConsent {
32 REQUIRES_CONSENT,
33 DOES_NOT_REQUIRE_CONSENT
34 };
35
36 } // namespace
37
21 class ActiveScriptControllerBrowserTest : public ExtensionBrowserTest { 38 class ActiveScriptControllerBrowserTest : public ExtensionBrowserTest {
22 public: 39 public:
23 ActiveScriptControllerBrowserTest() 40 ActiveScriptControllerBrowserTest()
24 : feature_override_(FeatureSwitch::scripts_require_action(), 41 : feature_override_(FeatureSwitch::scripts_require_action(),
25 FeatureSwitch::OVERRIDE_ENABLED) {} 42 FeatureSwitch::OVERRIDE_ENABLED) {}
26 private: 43 private:
27 FeatureSwitch::ScopedOverride feature_override_; 44 FeatureSwitch::ScopedOverride feature_override_;
28 }; 45 };
29 46
30 class ActiveScriptTester { 47 class ActiveScriptTester {
31 public: 48 public:
32 ActiveScriptTester(const std::string& name, 49 ActiveScriptTester(const std::string& name,
33 const Extension* extension, 50 const Extension* extension,
34 bool expect_has_action); 51 Browser* browser,
52 RequiresConsent requires_consent,
53 InjectionType type);
35 ~ActiveScriptTester(); 54 ~ActiveScriptTester();
36 55
37 testing::AssertionResult Verify(Browser* browser); 56 testing::AssertionResult Verify();
38 57
39 private: 58 private:
59 // Returns the location bar controller, or NULL if one does not exist.
60 LocationBarController* GetLocationBarController();
61
62 // Returns the active script controller, or NULL if one does not exist.
63 ActiveScriptController* GetActiveScriptController();
64
65 // Get the ExtensionAction for this extension, or NULL if one does not exist.
66 ExtensionAction* GetAction();
67
40 // The name of the extension, and also the message it sends. 68 // The name of the extension, and also the message it sends.
41 std::string name_; 69 std::string name_;
42 70
43 // The extension associated with this tester. 71 // The extension associated with this tester.
44 const Extension* extension_; 72 const Extension* extension_;
45 73
46 // Whether or not we expect the extension to have an action for script 74 // The browser the tester is running in.
47 // injection. 75 Browser* browser_;
48 bool expect_has_action_; 76
77 // Whether or not the extension has permission to run the script without
78 // asking the user.
79 RequiresConsent requires_consent_;
80
81 // The type of injection this tester uses.
82 InjectionType type_;
49 83
50 // All of these extensions should inject a script (either through content 84 // All of these extensions should inject a script (either through content
51 // scripts or through chrome.tabs.executeScript()) that sends a message with 85 // scripts or through chrome.tabs.executeScript()) that sends a message with
52 // their names (for verification). 86 // the |kInjectSucceeded| message.
53 // Be prepared to wait for each extension to inject the script. 87 linked_ptr<ExtensionTestMessageListener> inject_attempt_listener_;
54 linked_ptr<ExtensionTestMessageListener> listener_; 88
89 // After trying to inject the script, extensions sending the script via
90 // chrome.tabs.executeScript() send a |kInjectAttempted| message.
91 linked_ptr<ExtensionTestMessageListener> inject_success_listener_;
55 }; 92 };
56 93
57 ActiveScriptTester::ActiveScriptTester(const std::string& name, 94 ActiveScriptTester::ActiveScriptTester(const std::string& name,
58 const Extension* extension, 95 const Extension* extension,
59 bool expect_has_action) 96 Browser* browser,
97 RequiresConsent requires_consent,
98 InjectionType type)
60 : name_(name), 99 : name_(name),
61 extension_(extension), 100 extension_(extension),
62 expect_has_action_(expect_has_action), 101 browser_(browser),
63 listener_( 102 requires_consent_(requires_consent),
64 new ExtensionTestMessageListener(name, false /* won't reply */)) { 103 type_(type),
104 inject_attempt_listener_(
105 new ExtensionTestMessageListener(kInjectAttempted,
106 false /* won't reply */)),
107 inject_success_listener_(
108 new ExtensionTestMessageListener(kInjectSucceeded,
109 false /* won't reply */)) {
110 inject_attempt_listener_->set_extension_id(extension->id());
111 inject_success_listener_->set_extension_id(extension->id());
65 } 112 }
66 113
67 ActiveScriptTester::~ActiveScriptTester() { 114 ActiveScriptTester::~ActiveScriptTester() {
68 } 115 }
69 116
70 testing::AssertionResult ActiveScriptTester::Verify(Browser* browser) { 117 testing::AssertionResult ActiveScriptTester::Verify() {
71 if (!extension_) 118 if (!extension_)
72 return testing::AssertionFailure() << "Could not load extension: " << name_; 119 return testing::AssertionFailure() << "Could not load extension: " << name_;
73 120
74 listener_->WaitUntilSatisfied(); 121 // If it's not a content script, the Extension lets us know when it has
75 content::WebContents* web_contents = 122 // attempted to inject the script.
76 browser ? browser->tab_strip_model()->GetActiveWebContents() : NULL; 123 // This means there is a potential for a race condition with content scripts;
77 124 // however, since they are all injected at document_start, this shouldn't be
78 if (!web_contents) 125 // a problem. If these tests start failing, though, that might be it.
79 return testing::AssertionFailure() << "Could not find web contents."; 126 if (type_ == EXECUTE_SCRIPT)
80 127 inject_attempt_listener_->WaitUntilSatisfied();
81 TabHelper* tab_helper = TabHelper::FromWebContents(web_contents); 128
82 if (!tab_helper) 129 // Make sure all running tasks are complete.
83 return testing::AssertionFailure() << "Could not find tab helper."; 130 content::RunAllPendingInMessageLoop();
131
132 LocationBarController* location_bar_controller = GetLocationBarController();
133 if (!location_bar_controller) {
134 return testing::AssertionFailure()
135 << "Could not find location bar controller";
136 }
84 137
85 ActiveScriptController* controller = 138 ActiveScriptController* controller =
86 tab_helper->location_bar_controller()->active_script_controller(); 139 location_bar_controller->active_script_controller();
87 if (!controller) 140 if (!controller)
88 return testing::AssertionFailure() << "Could not find controller."; 141 return testing::AssertionFailure() << "Could not find controller.";
89 142
90 bool has_action = controller->GetActionForExtension(extension_) != NULL; 143 ExtensionAction* action = GetAction();
91 if (expect_has_action_ != has_action) { 144 bool has_action = action != NULL;
145
146 // An extension should have an action displayed iff it requires user consent.
147 if ((requires_consent_ == REQUIRES_CONSENT && !has_action) ||
148 (requires_consent_ == DOES_NOT_REQUIRE_CONSENT && has_action)) {
92 return testing::AssertionFailure() 149 return testing::AssertionFailure()
93 << "Improper action status: expected " << expect_has_action_ 150 << "Improper action status for " << name_ << ": expected "
94 << ", found " << has_action; 151 << (requires_consent_ == REQUIRES_CONSENT) << ", found " << has_action;
152 }
153
154 // If the extension has permission, we should be able to simply wait for it
155 // to execute.
156 if (requires_consent_ == DOES_NOT_REQUIRE_CONSENT) {
157 inject_success_listener_->WaitUntilSatisfied();
158 return testing::AssertionSuccess();
159 }
160
161 // Otherwise, we don't have permission, and have to grant it. Ensure the
162 // script has *not* already executed.
163 // Currently, it's okay for content scripts to execute, because we don't
164 // block them.
165 // TODO(rdevlin.cronin): Fix this.
166 if (inject_success_listener_->was_satisfied() && type_ != CONTENT_SCRIPT) {
167 return testing::AssertionFailure() <<
168 name_ << "'s script ran without permission.";
169 }
170
171 // If we reach this point, we should always have an action.
172 DCHECK(action);
173
174 // Grant permission by clicking on the extension action.
175 location_bar_controller->OnClicked(action);
176
177 // Now, the extension should be able to inject the script.
178 inject_success_listener_->WaitUntilSatisfied();
179
180 // The Action should have disappeared.
181 has_action = GetAction() != NULL;
182 if (has_action) {
183 return testing::AssertionFailure()
184 << "Extension " << name_ << " has lingering action.";
95 } 185 }
96 186
97 return testing::AssertionSuccess(); 187 return testing::AssertionSuccess();
98 } 188 }
99 189
190 LocationBarController* ActiveScriptTester::GetLocationBarController() {
191 content::WebContents* web_contents =
192 browser_ ? browser_->tab_strip_model()->GetActiveWebContents() : NULL;
193
194 if (!web_contents)
195 return NULL;
196
197 TabHelper* tab_helper = TabHelper::FromWebContents(web_contents);
198 return tab_helper ? tab_helper->location_bar_controller() : NULL;
199 }
200
201 ActiveScriptController* ActiveScriptTester::GetActiveScriptController() {
202 LocationBarController* location_bar_controller = GetLocationBarController();
203 return location_bar_controller ?
204 location_bar_controller->active_script_controller() : NULL;
205 }
206
207 ExtensionAction* ActiveScriptTester::GetAction() {
208 ActiveScriptController* controller = GetActiveScriptController();
209 return controller ? controller->GetActionForExtension(extension_) : NULL;
210 }
211
100 IN_PROC_BROWSER_TEST_F(ActiveScriptControllerBrowserTest, 212 IN_PROC_BROWSER_TEST_F(ActiveScriptControllerBrowserTest,
101 ActiveScriptsAreDisplayed) { 213 ActiveScriptsAreDisplayed) {
102 base::FilePath active_script_path = 214 base::FilePath active_script_path =
103 test_data_dir_.AppendASCII("active_script"); 215 test_data_dir_.AppendASCII("active_script");
104 216
105 const char* kExtensionNames[] = { 217 const char* kExtensionNames[] = {
218 "inject_scripts_all_hosts",
219 "inject_scripts_explicit_hosts",
106 "content_scripts_all_hosts", 220 "content_scripts_all_hosts",
107 "inject_scripts_all_hosts",
108 "content_scripts_explicit_hosts" 221 "content_scripts_explicit_hosts"
109 }; 222 };
110 223
111 // First, we load up three extensions: 224 // First, we load up three extensions:
225 // - An extension that injects scripts into all hosts,
226 // - An extension that injects scripts into explicit hosts,
112 // - An extension with a content script that runs on all hosts, 227 // - An extension with a content script that runs on all hosts,
113 // - An extension that injects scripts into all hosts,
114 // - An extension with a content script that runs on explicit hosts. 228 // - An extension with a content script that runs on explicit hosts.
229 // The extensions that operate on explicit hosts have permission; the ones
230 // that request all hosts require user consent.
115 ActiveScriptTester testers[] = { 231 ActiveScriptTester testers[] = {
116 ActiveScriptTester( 232 ActiveScriptTester(
117 kExtensionNames[0], 233 kExtensionNames[0],
118 LoadExtension(active_script_path.AppendASCII(kExtensionNames[0])), 234 LoadExtension(active_script_path.AppendASCII(kExtensionNames[0])),
119 true /* expect action */), 235 browser(),
236 REQUIRES_CONSENT,
237 EXECUTE_SCRIPT),
120 ActiveScriptTester( 238 ActiveScriptTester(
121 kExtensionNames[1], 239 kExtensionNames[1],
122 LoadExtension(active_script_path.AppendASCII(kExtensionNames[1])), 240 LoadExtension(active_script_path.AppendASCII(kExtensionNames[1])),
123 true /* expect action */), 241 browser(),
242 DOES_NOT_REQUIRE_CONSENT,
243 EXECUTE_SCRIPT),
124 ActiveScriptTester( 244 ActiveScriptTester(
125 kExtensionNames[2], 245 kExtensionNames[2],
126 LoadExtension(active_script_path.AppendASCII(kExtensionNames[2])), 246 LoadExtension(active_script_path.AppendASCII(kExtensionNames[2])),
127 false /* expect action */) 247 browser(),
248 REQUIRES_CONSENT,
249 CONTENT_SCRIPT),
250 ActiveScriptTester(
251 kExtensionNames[3],
252 LoadExtension(active_script_path.AppendASCII(kExtensionNames[3])),
253 browser(),
254 DOES_NOT_REQUIRE_CONSENT,
255 CONTENT_SCRIPT),
128 }; 256 };
129 257
130 // Navigate to an URL (which matches the explicit host specified in the 258 // Navigate to an URL (which matches the explicit host specified in the
131 // extension content_scripts_explicit_hosts). All three extensions should 259 // extension content_scripts_explicit_hosts). All three extensions should
132 // inject the script. 260 // inject the script.
133 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 261 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
134 ui_test_utils::NavigateToURL( 262 ui_test_utils::NavigateToURL(
135 browser(), embedded_test_server()->GetURL("/extensions/test_file.html")); 263 browser(), embedded_test_server()->GetURL("/extensions/test_file.html"));
136 264
137 for (size_t i = 0u; i < arraysize(testers); ++i) 265 for (size_t i = 0u; i < arraysize(testers); ++i)
138 ASSERT_TRUE(testers[i].Verify(browser())) << kExtensionNames[i]; 266 EXPECT_TRUE(testers[i].Verify()) << kExtensionNames[i];
139 } 267 }
140 268
141 } // namespace extensions 269 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698