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/command_line.h"
6 #include "base/files/file_path.h"
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/stringprintf.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/extensions/api/management/management_api.h"
12 #include "chrome/browser/extensions/api/management/management_api_constants.h"
13 #include "chrome/browser/extensions/extension_browsertest.h"
14 #include "chrome/browser/extensions/extension_function_test_utils.h"
15 #include "chrome/browser/extensions/extension_service.h"
16 #include "chrome/browser/extensions/extension_test_message_listener.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "content/public/browser/notification_service.h"
21 #include "content/public/common/url_constants.h"
22 #include "content/public/test/browser_test_utils.h"
23 #include "content/public/test/test_utils.h"
24 #include "extensions/browser/extension_host.h"
25 #include "extensions/browser/extension_prefs.h"
26 #include "extensions/browser/extension_system.h"
27
28 namespace keys = extension_management_api_constants;
29 namespace util = extension_function_test_utils;
30
31 namespace extensions {
32
33 class ExtensionManagementApiBrowserTest : public ExtensionBrowserTest {
34 protected:
CrashEnabledExtension(const std::string & extension_id)35 bool CrashEnabledExtension(const std::string& extension_id) {
36 ExtensionHost* background_host =
37 ExtensionSystem::Get(browser()->profile())->
38 process_manager()->GetBackgroundHostForExtension(extension_id);
39 if (!background_host)
40 return false;
41 content::CrashTab(background_host->host_contents());
42 return true;
43 }
44 };
45
46 // We test this here instead of in an ExtensionApiTest because normal extensions
47 // are not allowed to call the install function.
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,InstallEvent)48 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest, InstallEvent) {
49 ExtensionTestMessageListener listener1("ready", false);
50 ASSERT_TRUE(LoadExtension(
51 test_data_dir_.AppendASCII("management/install_event")));
52 ASSERT_TRUE(listener1.WaitUntilSatisfied());
53
54 ExtensionTestMessageListener listener2("got_event", false);
55 ASSERT_TRUE(LoadExtension(
56 test_data_dir_.AppendASCII("api_test/management/enabled_extension")));
57 ASSERT_TRUE(listener2.WaitUntilSatisfied());
58 }
59
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,LaunchApp)60 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest, LaunchApp) {
61 ExtensionTestMessageListener listener1("app_launched", false);
62 ExtensionTestMessageListener listener2("got_expected_error", false);
63 ASSERT_TRUE(LoadExtension(
64 test_data_dir_.AppendASCII("management/simple_extension")));
65 ASSERT_TRUE(LoadExtension(
66 test_data_dir_.AppendASCII("management/packaged_app")));
67 ASSERT_TRUE(LoadExtension(
68 test_data_dir_.AppendASCII("management/launch_app")));
69 ASSERT_TRUE(listener1.WaitUntilSatisfied());
70 ASSERT_TRUE(listener2.WaitUntilSatisfied());
71 }
72
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,LaunchAppFromBackground)73 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
74 LaunchAppFromBackground) {
75 ExtensionTestMessageListener listener1("success", false);
76 ASSERT_TRUE(LoadExtension(
77 test_data_dir_.AppendASCII("management/packaged_app")));
78 ASSERT_TRUE(LoadExtension(
79 test_data_dir_.AppendASCII("management/launch_app_from_background")));
80 ASSERT_TRUE(listener1.WaitUntilSatisfied());
81 }
82
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,SelfUninstall)83 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
84 SelfUninstall) {
85 ExtensionTestMessageListener listener1("success", false);
86 ASSERT_TRUE(LoadExtension(
87 test_data_dir_.AppendASCII("management/self_uninstall_helper")));
88 ASSERT_TRUE(LoadExtension(
89 test_data_dir_.AppendASCII("management/self_uninstall")));
90 ASSERT_TRUE(listener1.WaitUntilSatisfied());
91 }
92
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,SelfUninstallNoPermissions)93 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
94 SelfUninstallNoPermissions) {
95 ExtensionTestMessageListener listener1("success", false);
96 ASSERT_TRUE(LoadExtension(
97 test_data_dir_.AppendASCII("management/self_uninstall_helper")));
98 ASSERT_TRUE(LoadExtension(
99 test_data_dir_.AppendASCII("management/self_uninstall_noperm")));
100 ASSERT_TRUE(listener1.WaitUntilSatisfied());
101 }
102
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,UninstallWithConfirmDialog)103 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
104 UninstallWithConfirmDialog) {
105 ExtensionService* service = ExtensionSystem::Get(browser()->profile())->
106 extension_service();
107
108 // Install an extension.
109 const Extension* extension = InstallExtension(
110 test_data_dir_.AppendASCII("api_test/management/enabled_extension"), 1);
111 ASSERT_TRUE(extension);
112
113 const std::string id = extension->id();
114
115 scoped_refptr<Extension> empty_extension(
116 extension_function_test_utils::CreateEmptyExtension());
117 // Uninstall, then cancel via the confirm dialog.
118 scoped_refptr<ManagementUninstallFunction> uninstall_function(
119 new ManagementUninstallFunction());
120 uninstall_function->set_extension(empty_extension);
121 uninstall_function->set_user_gesture(true);
122 ManagementUninstallFunction::SetAutoConfirmForTest(false);
123
124 EXPECT_TRUE(MatchPattern(
125 util::RunFunctionAndReturnError(
126 uninstall_function.get(),
127 base::StringPrintf("[\"%s\", {\"showConfirmDialog\": true}]",
128 id.c_str()),
129 browser()),
130 keys::kUninstallCanceledError));
131
132 // Make sure the extension wasn't uninstalled.
133 EXPECT_TRUE(service->GetExtensionById(id, false) != NULL);
134
135 // Uninstall, then accept via the confirm dialog.
136 uninstall_function = new ManagementUninstallFunction();
137 uninstall_function->set_extension(empty_extension);
138 ManagementUninstallFunction::SetAutoConfirmForTest(true);
139 uninstall_function->set_user_gesture(true);
140 util::RunFunctionAndReturnSingleResult(
141 uninstall_function.get(),
142 base::StringPrintf("[\"%s\", {\"showConfirmDialog\": true}]", id.c_str()),
143 browser());
144
145 // Make sure the extension was uninstalled.
146 EXPECT_TRUE(service->GetExtensionById(id, false) == NULL);
147 }
148
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,CreateAppShortcutConfirmDialog)149 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
150 CreateAppShortcutConfirmDialog) {
151 const Extension* app = InstallExtension(
152 test_data_dir_.AppendASCII("api_test/management/packaged_app"), 1);
153 ASSERT_TRUE(app);
154
155 const std::string app_id = app->id();
156
157 scoped_refptr<ManagementCreateAppShortcutFunction> create_shortcut_function(
158 new ManagementCreateAppShortcutFunction());
159 create_shortcut_function->set_user_gesture(true);
160 ManagementCreateAppShortcutFunction::SetAutoConfirmForTest(true);
161 util::RunFunctionAndReturnSingleResult(
162 create_shortcut_function.get(),
163 base::StringPrintf("[\"%s\"]", app_id.c_str()),
164 browser());
165
166 create_shortcut_function = new ManagementCreateAppShortcutFunction();
167 create_shortcut_function->set_user_gesture(true);
168 ManagementCreateAppShortcutFunction::SetAutoConfirmForTest(false);
169 EXPECT_TRUE(MatchPattern(
170 util::RunFunctionAndReturnError(
171 create_shortcut_function.get(),
172 base::StringPrintf("[\"%s\"]", app_id.c_str()),
173 browser()),
174 keys::kCreateShortcutCanceledError));
175 }
176
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,GetAllIncludesTerminated)177 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
178 GetAllIncludesTerminated) {
179 // Load an extension with a background page, so that we know it has a process
180 // running.
181 ExtensionTestMessageListener listener("ready", false);
182 const Extension* extension = LoadExtension(
183 test_data_dir_.AppendASCII("management/install_event"));
184 ASSERT_TRUE(extension);
185 ASSERT_TRUE(listener.WaitUntilSatisfied());
186
187 // The management API should list this extension.
188 scoped_refptr<ManagementGetAllFunction> function =
189 new ManagementGetAllFunction();
190 scoped_ptr<base::Value> result(util::RunFunctionAndReturnSingleResult(
191 function.get(), "[]", browser()));
192 base::ListValue* list;
193 ASSERT_TRUE(result->GetAsList(&list));
194 EXPECT_EQ(1U, list->GetSize());
195
196 // And it should continue to do so even after it crashes.
197 ASSERT_TRUE(CrashEnabledExtension(extension->id()));
198
199 function = new ManagementGetAllFunction();
200 result.reset(util::RunFunctionAndReturnSingleResult(
201 function.get(), "[]", browser()));
202 ASSERT_TRUE(result->GetAsList(&list));
203 EXPECT_EQ(1U, list->GetSize());
204 }
205
206 class ExtensionManagementApiEscalationTest :
207 public ExtensionManagementApiBrowserTest {
208 protected:
209 // The id of the permissions escalation test extension we use.
210 static const char kId[];
211
SetUpOnMainThread()212 virtual void SetUpOnMainThread() OVERRIDE {
213 EXPECT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
214 base::FilePath pem_path = test_data_dir_.
215 AppendASCII("permissions_increase").AppendASCII("permissions.pem");
216 base::FilePath path_v1 = PackExtensionWithOptions(
217 test_data_dir_.AppendASCII("permissions_increase").AppendASCII("v1"),
218 scoped_temp_dir_.path().AppendASCII("permissions1.crx"),
219 pem_path,
220 base::FilePath());
221 base::FilePath path_v2 = PackExtensionWithOptions(
222 test_data_dir_.AppendASCII("permissions_increase").AppendASCII("v2"),
223 scoped_temp_dir_.path().AppendASCII("permissions2.crx"),
224 pem_path,
225 base::FilePath());
226
227 ExtensionService* service = ExtensionSystem::Get(browser()->profile())->
228 extension_service();
229
230 // Install low-permission version of the extension.
231 ASSERT_TRUE(InstallExtension(path_v1, 1));
232 EXPECT_TRUE(service->GetExtensionById(kId, false) != NULL);
233
234 // Update to a high-permission version - it should get disabled.
235 EXPECT_FALSE(UpdateExtension(kId, path_v2, -1));
236 EXPECT_TRUE(service->GetExtensionById(kId, false) == NULL);
237 EXPECT_TRUE(service->GetExtensionById(kId, true) != NULL);
238 EXPECT_TRUE(ExtensionPrefs::Get(browser()->profile())
239 ->DidExtensionEscalatePermissions(kId));
240 }
241
SetEnabled(bool enabled,bool user_gesture,const std::string & expected_error)242 void SetEnabled(bool enabled, bool user_gesture,
243 const std::string& expected_error) {
244 scoped_refptr<ManagementSetEnabledFunction> function(
245 new ManagementSetEnabledFunction);
246 const char* enabled_string = enabled ? "true" : "false";
247 if (user_gesture)
248 function->set_user_gesture(true);
249 bool response = util::RunFunction(
250 function.get(),
251 base::StringPrintf("[\"%s\", %s]", kId, enabled_string),
252 browser(),
253 util::NONE);
254 if (expected_error.empty()) {
255 EXPECT_EQ(true, response);
256 } else {
257 EXPECT_TRUE(response == false);
258 EXPECT_EQ(expected_error, function->GetError());
259 }
260 }
261
262
263 private:
264 base::ScopedTempDir scoped_temp_dir_;
265 };
266
267 const char ExtensionManagementApiEscalationTest::kId[] =
268 "pgdpcfcocojkjfbgpiianjngphoopgmo";
269
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiEscalationTest,DisabledReason)270 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiEscalationTest,
271 DisabledReason) {
272 scoped_refptr<ManagementGetFunction> function =
273 new ManagementGetFunction();
274 scoped_ptr<base::Value> result(util::RunFunctionAndReturnSingleResult(
275 function.get(),
276 base::StringPrintf("[\"%s\"]", kId),
277 browser()));
278 ASSERT_TRUE(result.get() != NULL);
279 ASSERT_TRUE(result->IsType(base::Value::TYPE_DICTIONARY));
280 base::DictionaryValue* dict =
281 static_cast<base::DictionaryValue*>(result.get());
282 std::string reason;
283 EXPECT_TRUE(dict->GetStringASCII(keys::kDisabledReasonKey, &reason));
284 EXPECT_EQ(reason, std::string(keys::kDisabledReasonPermissionsIncrease));
285 }
286
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiEscalationTest,SetEnabled)287 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiEscalationTest,
288 SetEnabled) {
289 // Expect an error about no gesture.
290 SetEnabled(true, false, keys::kGestureNeededForEscalationError);
291
292 // Expect an error that user cancelled the dialog.
293 CommandLine::ForCurrentProcess()->AppendSwitchASCII(
294 switches::kAppsGalleryInstallAutoConfirmForTests, "cancel");
295 SetEnabled(true, true, keys::kUserDidNotReEnableError);
296
297 // This should succeed when user accepts dialog. We must wait for the process
298 // to connect *and* for the channel to finish initializing before trying to
299 // crash it. (NOTIFICATION_RENDERER_PROCESS_CREATED does not wait for the
300 // latter and can cause KillProcess to fail on Windows.)
301 content::WindowedNotificationObserver observer(
302 chrome::NOTIFICATION_EXTENSION_HOST_CREATED,
303 content::NotificationService::AllSources());
304 CommandLine::ForCurrentProcess()->AppendSwitchASCII(
305 switches::kAppsGalleryInstallAutoConfirmForTests, "accept");
306 SetEnabled(true, true, std::string());
307 observer.Wait();
308
309 // Crash the extension. Mock a reload by disabling and then enabling. The
310 // extension should be reloaded and enabled.
311 ASSERT_TRUE(CrashEnabledExtension(kId));
312 SetEnabled(false, true, std::string());
313 SetEnabled(true, true, std::string());
314 const Extension* extension = ExtensionSystem::Get(browser()->profile())
315 ->extension_service()->GetExtensionById(kId, false);
316 EXPECT_TRUE(extension);
317 }
318
319 } // namespace extensions
320