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

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 } // namespace
32
21 class ActiveScriptControllerBrowserTest : public ExtensionBrowserTest { 33 class ActiveScriptControllerBrowserTest : public ExtensionBrowserTest {
22 public: 34 public:
23 ActiveScriptControllerBrowserTest() 35 ActiveScriptControllerBrowserTest()
24 : feature_override_(FeatureSwitch::scripts_require_action(), 36 : feature_override_(FeatureSwitch::scripts_require_action(),
25 FeatureSwitch::OVERRIDE_ENABLED) {} 37 FeatureSwitch::OVERRIDE_ENABLED) {}
26 private: 38 private:
27 FeatureSwitch::ScopedOverride feature_override_; 39 FeatureSwitch::ScopedOverride feature_override_;
28 }; 40 };
29 41
30 class ActiveScriptTester { 42 class ActiveScriptTester {
31 public: 43 public:
32 ActiveScriptTester(const std::string& name, 44 ActiveScriptTester(const std::string& name,
33 const Extension* extension, 45 const Extension* extension,
34 bool expect_has_action); 46 bool requires_consent,
47 InjectionType type);
35 ~ActiveScriptTester(); 48 ~ActiveScriptTester();
36 49
37 testing::AssertionResult Verify(Browser* browser); 50 testing::AssertionResult Verify(Browser* browser);
38 51
39 private: 52 private:
40 // The name of the extension, and also the message it sends. 53 // The name of the extension, and also the message it sends.
41 std::string name_; 54 std::string name_;
42 55
43 // The extension associated with this tester. 56 // The extension associated with this tester.
44 const Extension* extension_; 57 const Extension* extension_;
45 58
46 // Whether or not we expect the extension to have an action for script 59 // Whether or not the extension has permission to run the script without
47 // injection. 60 // asking the user.
48 bool expect_has_action_; 61 bool requires_consent_;
62
63 // The type of injection this tester uses.
64 InjectionType type_;
49 65
50 // All of these extensions should inject a script (either through content 66 // All of these extensions should inject a script (either through content
51 // scripts or through chrome.tabs.executeScript()) that sends a message with 67 // scripts or through chrome.tabs.executeScript()) that sends a message with
52 // their names (for verification). 68 // the |kInjectSucceeded| message.
53 // Be prepared to wait for each extension to inject the script. 69 linked_ptr<ExtensionTestMessageListener> inject_attempt_listener_;
54 linked_ptr<ExtensionTestMessageListener> listener_; 70
71 // After trying to inject the script, extensions sending the script via
72 // chrome.tabs.executeScript() send a |kInjectAttempted| message.
73 linked_ptr<ExtensionTestMessageListener> inject_success_listener_;
55 }; 74 };
56 75
57 ActiveScriptTester::ActiveScriptTester(const std::string& name, 76 ActiveScriptTester::ActiveScriptTester(const std::string& name,
58 const Extension* extension, 77 const Extension* extension,
59 bool expect_has_action) 78 bool requires_consent,
79 InjectionType type)
60 : name_(name), 80 : name_(name),
61 extension_(extension), 81 extension_(extension),
62 expect_has_action_(expect_has_action), 82 requires_consent_(requires_consent),
63 listener_( 83 type_(type),
64 new ExtensionTestMessageListener(name, false /* won't reply */)) { 84 inject_attempt_listener_(
85 new ExtensionTestMessageListener(kInjectAttempted,
86 false /* won't reply */)),
87 inject_success_listener_(
88 new ExtensionTestMessageListener(kInjectSucceeded,
89 false /* won't reply */)) {
90 inject_attempt_listener_->set_extension_id(extension->id());
91 inject_success_listener_->set_extension_id(extension->id());
65 } 92 }
66 93
67 ActiveScriptTester::~ActiveScriptTester() { 94 ActiveScriptTester::~ActiveScriptTester() {
68 } 95 }
69 96
70 testing::AssertionResult ActiveScriptTester::Verify(Browser* browser) { 97 testing::AssertionResult ActiveScriptTester::Verify(Browser* browser) {
71 if (!extension_) 98 if (!extension_)
72 return testing::AssertionFailure() << "Could not load extension: " << name_; 99 return testing::AssertionFailure() << "Could not load extension: " << name_;
73 100
74 listener_->WaitUntilSatisfied(); 101 // If it's not a content script, the Extension lets us know when it has
102 // attempted to inject the script.
103 // This means there is a potential for a race condition with content scripts;
104 // however, since they are all injected at document_start, this shouldn't be
not at google - send to devlin 2014/05/15 00:12:36 document_start will be an issue actually. if you r
Devlin 2014/05/15 17:45:59 I think this one deserves a bit more thought. So,
not at google - send to devlin 2014/05/15 18:26:55 I agree, it requires thought, and it's complex eno
105 // a problem. If these tests start failing, though, that might be it.
106 if (type_ == EXECUTE_SCRIPT)
107 inject_attempt_listener_->WaitUntilSatisfied();
108
109 // Make sure all running tasks are complete.
not at google - send to devlin 2014/05/15 00:12:36 what tasks? the active script controller ones?
Devlin 2014/05/15 17:45:59 Yeah. Just making sure that if anything is runnin
110 content::RunAllPendingInMessageLoop();
111
75 content::WebContents* web_contents = 112 content::WebContents* web_contents =
76 browser ? browser->tab_strip_model()->GetActiveWebContents() : NULL; 113 browser ? browser->tab_strip_model()->GetActiveWebContents() : NULL;
77 114
78 if (!web_contents) 115 if (!web_contents)
79 return testing::AssertionFailure() << "Could not find web contents."; 116 return testing::AssertionFailure() << "Could not find web contents.";
80 117
81 TabHelper* tab_helper = TabHelper::FromWebContents(web_contents); 118 TabHelper* tab_helper = TabHelper::FromWebContents(web_contents);
82 if (!tab_helper) 119 if (!tab_helper)
83 return testing::AssertionFailure() << "Could not find tab helper."; 120 return testing::AssertionFailure() << "Could not find tab helper.";
84 121
122 LocationBarController* location_bar_controller =
123 tab_helper->location_bar_controller();
124 if (!location_bar_controller) {
125 return testing::AssertionFailure()
126 << "Could not find location bar controller";
127 }
128
85 ActiveScriptController* controller = 129 ActiveScriptController* controller =
86 tab_helper->location_bar_controller()->active_script_controller(); 130 tab_helper->location_bar_controller()->active_script_controller();
not at google - send to devlin 2014/05/15 00:12:36 s/tab_helper->location_bar_controller()/location_b
Devlin 2014/05/15 17:45:59 Whoops, done.
87 if (!controller) 131 if (!controller)
88 return testing::AssertionFailure() << "Could not find controller."; 132 return testing::AssertionFailure() << "Could not find controller.";
89 133
90 bool has_action = controller->GetActionForExtension(extension_) != NULL; 134 bool has_action = controller->GetActionForExtension(extension_) != NULL;
91 if (expect_has_action_ != has_action) { 135
136 // An extension should have an action displayed iff it requires user consent.
137 if (requires_consent_ != has_action) {
92 return testing::AssertionFailure() 138 return testing::AssertionFailure()
93 << "Improper action status: expected " << expect_has_action_ 139 << "Improper action status for " << name_ << ": expected "
94 << ", found " << has_action; 140 << requires_consent_ << ", found " << has_action;
141 }
142
143 // If the extension has permission, we should be able to simply wait for it
144 // to execute.
145 if (!requires_consent_) {
146 inject_success_listener_->WaitUntilSatisfied();
147 return testing::AssertionSuccess();
148 }
149
150 // Otherwise, we don't have permission, and have to grant it. Ensure the
151 // script has *not* already executed.
152 // Currently, it's okay for content scripts to execute, because we don't
153 // block them.
154 // TODO(rdevlin.cronin): Fix this.
155 if (inject_success_listener_->was_satisfied() && type_ != CONTENT_SCRIPT) {
156 return testing::AssertionFailure() <<
157 name_ << "'s script ran without permission.";
158 }
159
160 ExtensionAction* action = controller->GetActionForExtension(extension_);
161 // We've already verified this exists, so just a sanity check.
162 DCHECK(action);
not at google - send to devlin 2014/05/15 00:12:36 in theory the action could have disappeared, like
Devlin 2014/05/15 17:45:59 Actually... it can't. After line 134 (when we che
163
164 // Grant permission by clicking on the extension action.
165 location_bar_controller->OnClicked(action);
166
167 // Now, the extension should be able to inject the script.
168 inject_success_listener_->WaitUntilSatisfied();
169
170 // The Action should have disappeared.
171 has_action = controller->GetActionForExtension(extension_) != NULL;
not at google - send to devlin 2014/05/15 00:12:36 you do this a couple of times. how about a (privat
Devlin 2014/05/15 17:45:59 Done (though the end result is much longer).
172 if (has_action) {
173 return testing::AssertionFailure()
174 << "Extension " << name_ << " has lingering action.";
95 } 175 }
96 176
97 return testing::AssertionSuccess(); 177 return testing::AssertionSuccess();
98 } 178 }
99 179
100 IN_PROC_BROWSER_TEST_F(ActiveScriptControllerBrowserTest, 180 IN_PROC_BROWSER_TEST_F(ActiveScriptControllerBrowserTest,
101 ActiveScriptsAreDisplayed) { 181 ActiveScriptsAreDisplayed) {
102 base::FilePath active_script_path = 182 base::FilePath active_script_path =
103 test_data_dir_.AppendASCII("active_script"); 183 test_data_dir_.AppendASCII("active_script");
104 184
105 const char* kExtensionNames[] = { 185 const char* kExtensionNames[] = {
186 "inject_scripts_all_hosts",
187 "inject_scripts_explicit_hosts",
106 "content_scripts_all_hosts", 188 "content_scripts_all_hosts",
107 "inject_scripts_all_hosts",
108 "content_scripts_explicit_hosts" 189 "content_scripts_explicit_hosts"
109 }; 190 };
110 191
111 // First, we load up three extensions: 192 // First, we load up three extensions:
193 // - An extension that injects scripts into all hosts,
194 // - An extension that injects scripts into explicit hosts,
112 // - An extension with a content script that runs on all hosts, 195 // - 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. 196 // - An extension with a content script that runs on explicit hosts.
197 // The extensions that operate on explicit hosts have permission; the ones
198 // that request all hosts require user consent.
115 ActiveScriptTester testers[] = { 199 ActiveScriptTester testers[] = {
116 ActiveScriptTester( 200 ActiveScriptTester(
117 kExtensionNames[0], 201 kExtensionNames[0],
118 LoadExtension(active_script_path.AppendASCII(kExtensionNames[0])), 202 LoadExtension(active_script_path.AppendASCII(kExtensionNames[0])),
119 true /* expect action */), 203 true /* needs consent */,
not at google - send to devlin 2014/05/15 00:12:36 how about making this an enum so you don't need to
Devlin 2014/05/15 17:45:59 The reason was because if statements like if (re
204 EXECUTE_SCRIPT),
120 ActiveScriptTester( 205 ActiveScriptTester(
121 kExtensionNames[1], 206 kExtensionNames[1],
122 LoadExtension(active_script_path.AppendASCII(kExtensionNames[1])), 207 LoadExtension(active_script_path.AppendASCII(kExtensionNames[1])),
123 true /* expect action */), 208 false /* does not need consent */,
209 EXECUTE_SCRIPT),
124 ActiveScriptTester( 210 ActiveScriptTester(
125 kExtensionNames[2], 211 kExtensionNames[2],
126 LoadExtension(active_script_path.AppendASCII(kExtensionNames[2])), 212 LoadExtension(active_script_path.AppendASCII(kExtensionNames[2])),
127 false /* expect action */) 213 true /* needs consent */,
214 CONTENT_SCRIPT),
215 ActiveScriptTester(
216 kExtensionNames[3],
217 LoadExtension(active_script_path.AppendASCII(kExtensionNames[3])),
218 false /* does not need consent */,
219 CONTENT_SCRIPT),
128 }; 220 };
129 221
130 // Navigate to an URL (which matches the explicit host specified in the 222 // Navigate to an URL (which matches the explicit host specified in the
131 // extension content_scripts_explicit_hosts). All three extensions should 223 // extension content_scripts_explicit_hosts). All three extensions should
132 // inject the script. 224 // inject the script.
133 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 225 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
134 ui_test_utils::NavigateToURL( 226 ui_test_utils::NavigateToURL(
135 browser(), embedded_test_server()->GetURL("/extensions/test_file.html")); 227 browser(), embedded_test_server()->GetURL("/extensions/test_file.html"));
136 228
137 for (size_t i = 0u; i < arraysize(testers); ++i) 229 for (size_t i = 0u; i < arraysize(testers); ++i)
138 ASSERT_TRUE(testers[i].Verify(browser())) << kExtensionNames[i]; 230 EXPECT_TRUE(testers[i].Verify(browser())) << kExtensionNames[i];
139 } 231 }
140 232
141 } // namespace extensions 233 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698