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

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

Issue 293003008: Make ActiveScriptController use Active Tab-style permissions (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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include <map>
6
7 #include "base/values.h"
8 #include "chrome/browser/extensions/active_script_controller.h"
9 #include "chrome/browser/extensions/active_tab_permission_granter.h"
10 #include "chrome/browser/extensions/tab_helper.h"
11 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
12 #include "chrome/test/base/testing_profile.h"
13 #include "content/public/browser/navigation_controller.h"
14 #include "content/public/browser/navigation_entry.h"
15 #include "content/public/browser/web_contents.h"
16 #include "extensions/browser/extension_registry.h"
17 #include "extensions/common/extension.h"
18 #include "extensions/common/extension_builder.h"
19 #include "extensions/common/feature_switch.h"
20 #include "extensions/common/manifest.h"
21 #include "extensions/common/value_builder.h"
22
23 namespace extensions {
24
25 namespace {
26
27 const char kAllHostsPermission[] = "*://*/*";
28
29 } // namespace
30
31 // Unittests for the ActiveScriptController mostly test the internal logic
32 // of the controller itself (when to allow/deny extension script injection).
33 // Testing real injection is allowed/denied as expected (i.e., that the
34 // ActiveScriptController correctly interfaces in the system) is done in the
35 // ActiveScriptControllerBrowserTests.
36 class ActiveScriptControllerUnitTest : public ChromeRenderViewHostTestHarness {
37 protected:
38 ActiveScriptControllerUnitTest();
39 virtual ~ActiveScriptControllerUnitTest();
40
41 // Creates an extension with all hosts permission and adds it to the registry.
42 const Extension* AddExtension();
43
44 // Returns the current page id.
45 int GetPageId();
46
47 // Returns a closure to use as a script execution for a given extension.
48 base::Closure GetExecutionCallbackForExtension(
49 const std::string& extension_id);
50
51 // Returns the number of times a given extension has had a script execute.
52 size_t GetExecutionCountForExtension(const std::string& extension_id) const;
53
54 ActiveScriptController* controller() { return active_script_controller_; }
55
56 private:
57 // Increment the number of executions for the given |extension_id|.
58 void IncrementExecutionCount(const std::string& extension_id);
59
60 virtual void SetUp() OVERRIDE;
61
62 // Since ActiveScriptController's behavior is behind a flag, override the
63 // feature switch.
64 FeatureSwitch::ScopedOverride feature_override_;
65
66 // The associated ActiveScriptController.
67 ActiveScriptController* active_script_controller_;
68
69 // The map of observed executions, keyed by extension id.
70 std::map<std::string, int> extension_executions_;
71 };
72
73 ActiveScriptControllerUnitTest::ActiveScriptControllerUnitTest()
74 : feature_override_(FeatureSwitch::scripts_require_action(),
75 FeatureSwitch::OVERRIDE_ENABLED),
76 active_script_controller_(NULL) {
77 }
78
79 ActiveScriptControllerUnitTest::~ActiveScriptControllerUnitTest() {
80 }
81
82 const Extension* ActiveScriptControllerUnitTest::AddExtension() {
83 static const char kId[] = "all_hosts_extension";
84 scoped_refptr<const Extension> extension =
85 ExtensionBuilder()
86 .SetManifest(
87 DictionaryBuilder()
88 .Set("name", "all_hosts_extension")
89 .Set("description", "an extension")
90 .Set("manifest_version", 2)
91 .Set("version", "1.0.0")
92 .Set("permissions", ListBuilder().Append(kAllHostsPermission))
93 .Build())
not at google - send to devlin 2014/05/21 20:10:20 don't need the Build()
Devlin 2014/05/21 23:16:07 Done.
94 .SetLocation(Manifest::INTERNAL)
95 .SetID(kId)
96 .Build();
97
98 ExtensionRegistry* registry = ExtensionRegistry::Get(profile());
99 registry->AddEnabled(extension);
100
101 // Make sure the extension is correctly added. If not, return NULL.
not at google - send to devlin 2014/05/21 20:10:20 how can this possibly fail..? ExtensionRegistry ha
Devlin 2014/05/21 23:16:07 Fair. :)
102 if (!registry->enabled_extensions().GetByID(kId))
103 return NULL;
104
105 return extension;
106 }
107
108 int ActiveScriptControllerUnitTest::GetPageId() {
109 content::NavigationEntry* navigation_entry =
110 web_contents()->GetController().GetVisibleEntry();
111 DCHECK(navigation_entry); // This should never be NULL.
112 return navigation_entry->GetPageID();
113 }
114
115 base::Closure ActiveScriptControllerUnitTest::GetExecutionCallbackForExtension(
116 const std::string& extension_id) {
117 // We use base unretained here, but if this ever gets executed outside of
118 // this test's lifetime, we have a major problem anyway.
119 return base::Bind(&ActiveScriptControllerUnitTest::IncrementExecutionCount,
120 base::Unretained(this),
121 extension_id);
122 }
123
124 size_t ActiveScriptControllerUnitTest::GetExecutionCountForExtension(
125 const std::string& extension_id) const {
126 std::map<std::string, int>::const_iterator iter =
127 extension_executions_.find(extension_id);
128 if (iter != extension_executions_.end())
129 return iter->second;
130 return 0u;
131 }
132
133 void ActiveScriptControllerUnitTest::IncrementExecutionCount(
134 const std::string& extension_id) {
135 std::map<std::string, int>::iterator iter =
136 extension_executions_.find(extension_id);
137 if (iter != extension_executions_.end())
138 iter->second += 1;
139 else
140 extension_executions_[extension_id] = 1u;
not at google - send to devlin 2014/05/21 20:10:20 numbers are initialised to 0, so you just need "++
Devlin 2014/05/21 23:16:07 Done.
141 }
142
143 void ActiveScriptControllerUnitTest::SetUp() {
144 ChromeRenderViewHostTestHarness::SetUp();
145
146 TabHelper::CreateForWebContents(web_contents());
147 TabHelper* tab_helper = TabHelper::FromWebContents(web_contents());
148 // None of these should ever be NULL.
149 DCHECK(tab_helper);
150 DCHECK(tab_helper->location_bar_controller());
151 active_script_controller_ =
152 tab_helper->location_bar_controller()->active_script_controller();
153 DCHECK(active_script_controller_);
154 }
155
156 // Test that extensions with all_hosts require permission to execute, and, once
157 // that permission is granted, do execute.
158 TEST_F(ActiveScriptControllerUnitTest, RequestPermissionAndExecute) {
159 const Extension* extension = AddExtension();
160 ASSERT_TRUE(extension);
161
162 NavigateAndCommit(GURL("https://www.google.com"));
163
164 // Ensure that there aren't any executions pending.
165 ASSERT_EQ(0u, GetExecutionCountForExtension(extension->id()));
166 ExtensionAction* action = controller()->GetActionForExtension(extension);
167 ASSERT_FALSE(action);
not at google - send to devlin 2014/05/21 20:10:20 holding onto |action| here looks odd. just ASSERT_
Devlin 2014/05/21 23:16:07 Yeah, noticed that after I had uploaded. Original
168
169 // Since the extension requests all_hosts, we should require user consent.
170 EXPECT_TRUE(
171 controller()->RequiresUserConsentForScriptInjection(extension));
172
173 // Request an injection. There should be an action visible, but no executions.
174 controller()->RequestScriptInjection(
175 extension,
176 GetPageId(),
177 GetExecutionCallbackForExtension(extension->id()));
178 action = controller()->GetActionForExtension(extension);
179 EXPECT_TRUE(action);
180 EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
181
182 // Click to accept the extension executing.
183 controller()->OnClicked(extension);
184
185 // The extension should execute, and the action should go away.
186 EXPECT_EQ(1u, GetExecutionCountForExtension(extension->id()));
187 action = controller()->GetActionForExtension(extension);
188 EXPECT_FALSE(action);
189
190 // Since we already executed on the given page, we shouldn't need permission
191 // for a second time.
192 EXPECT_FALSE(
193 controller()->RequiresUserConsentForScriptInjection(extension));
194
195 // Navigating again should clear those permissions, and we should again
196 // require user consent.
197 NavigateAndCommit(GURL("https://www.google.com"));
198 EXPECT_TRUE(
199 controller()->RequiresUserConsentForScriptInjection(extension));
200 }
201
202 // Test that injections that are not executed by the time the user navigates are
203 // ignored and never execute.
204 TEST_F(ActiveScriptControllerUnitTest, PendingInjectionsRemovedAtNavigation) {
205 const Extension* extension = AddExtension();
206 ASSERT_TRUE(extension);
207
208 NavigateAndCommit(GURL("https://www.google.com"));
209
210 ASSERT_EQ(0u, GetExecutionCountForExtension(extension->id()));
211
212 // Request an injection. There should be an action visible, but no executions.
213 controller()->RequestScriptInjection(
214 extension,
215 GetPageId(),
216 GetExecutionCallbackForExtension(extension->id()));
217 ExtensionAction* action = controller()->GetActionForExtension(extension);
218 EXPECT_TRUE(action);
219 EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
220
221 // Navigate away. This should remove the pending injection, and we should not
222 // execute anything.
223 NavigateAndCommit(GURL("https://www.google.com"));
not at google - send to devlin 2014/05/21 20:10:20 you could also Reload() if that's any easier. wou
Devlin 2014/05/21 23:16:07 Done.
224 action = controller()->GetActionForExtension(extension);
225 EXPECT_FALSE(action);
226 EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
227
228 // Request and accept a new injection.
229 controller()->RequestScriptInjection(
230 extension,
231 GetPageId(),
232 GetExecutionCallbackForExtension(extension->id()));
233 controller()->OnClicked(extension);
234
235 // The extension should only have executed once, even though a grand total
236 // of two executions were requested.
237 EXPECT_EQ(1u, GetExecutionCountForExtension(extension->id()));
238 action = controller()->GetActionForExtension(extension);
239 EXPECT_FALSE(action);
240 }
241
242 // Test that queueing multiple pending injections, and then accepting, triggers
243 // them all.
244 TEST_F(ActiveScriptControllerUnitTest, MultiplePendingInjection) {
245 const Extension* extension = AddExtension();
246 ASSERT_TRUE(extension);
247 NavigateAndCommit(GURL("https://www.google.com"));
248
249 ASSERT_EQ(0u, GetExecutionCountForExtension(extension->id()));
250
251 const size_t kNumInjections = 3u;
252 // Queue multiple pending injections.
253 for (size_t i = 0u; i < kNumInjections; ++i) {
254 controller()->RequestScriptInjection(
255 extension,
256 GetPageId(),
257 GetExecutionCallbackForExtension(extension->id()));
258 }
259 EXPECT_EQ(0u, GetExecutionCountForExtension(extension->id()));
260
261 controller()->OnClicked(extension);
262
263 // All pending injections should have executed.
264 EXPECT_EQ(3u, GetExecutionCountForExtension(extension->id()));
not at google - send to devlin 2014/05/21 20:10:20 kNumInjections?
Devlin 2014/05/21 23:16:07 heh, whoops. Done.
265 ExtensionAction* action = controller()->GetActionForExtension(extension);
266 EXPECT_FALSE(action);
267 }
268
269 TEST_F(ActiveScriptControllerUnitTest, ActiveScriptsUseActiveTabPermissions) {
270 const Extension* extension = AddExtension();
271 NavigateAndCommit(GURL("https://www.google.com"));
272
273 ActiveTabPermissionGranter* active_tab_permission_granter =
274 TabHelper::FromWebContents(web_contents())
275 ->active_tab_permission_granter();
276 ASSERT_TRUE(active_tab_permission_granter);
277 // Grant the extension active tab permissions. This normally happens, e.g.,
278 // if the user clicks on a browser action.
279 active_tab_permission_granter->GrantIfRequested(extension);
280
281 // Since we have active tab permissions, we shouldn't need user consent
282 // anymore.
283 EXPECT_FALSE(
284 controller()->RequiresUserConsentForScriptInjection(extension));
285
286 // TODO(rdevlin.cronin): We should also implement/test that granting active
287 // tab permissions automatically runs any pending injections.
288 }
289
290 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698