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/files/file_path.h"
6 #include "base/files/scoped_temp_dir.h"
7 #include "base/memory/scoped_refptr.h"
8 #include "base/strings/pattern.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/test/metrics/histogram_tester.h"
12 #include "build/build_config.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/install_verifier.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/tabs/tab_strip_model.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/api/management/management_api.h"
25 #include "extensions/browser/api/management/management_api_constants.h"
26 #include "extensions/browser/extension_dialog_auto_confirm.h"
27 #include "extensions/browser/extension_host.h"
28 #include "extensions/browser/extension_prefs.h"
29 #include "extensions/browser/extension_registry.h"
30 #include "extensions/browser/notification_types.h"
31 #include "extensions/common/extension_builder.h"
32 #include "extensions/test/extension_test_message_listener.h"
33
34 #if defined(OS_CHROMEOS)
35 #include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
36 #endif
37
38 namespace keys = extension_management_api_constants;
39 namespace test_utils = extension_function_test_utils;
40
41 namespace extensions {
42
43 class ExtensionManagementApiBrowserTest : public ExtensionBrowserTest {
44 protected:
CrashEnabledExtension(const std::string & extension_id)45 bool CrashEnabledExtension(const std::string& extension_id) {
46 ExtensionHost* background_host =
47 ProcessManager::Get(browser()->profile())
48 ->GetBackgroundHostForExtension(extension_id);
49 if (!background_host)
50 return false;
51 content::CrashTab(background_host->host_contents());
52 return true;
53 }
54
55 private:
56 ScopedInstallVerifierBypassForTest install_verifier_bypass_;
57 };
58
59 // We test this here instead of in an ExtensionApiTest because normal extensions
60 // are not allowed to call the install function.
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,InstallEvent)61 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest, InstallEvent) {
62 ExtensionTestMessageListener listener1("ready", false);
63 ASSERT_TRUE(LoadExtension(
64 test_data_dir_.AppendASCII("management/install_event")));
65 ASSERT_TRUE(listener1.WaitUntilSatisfied());
66
67 ExtensionTestMessageListener listener2("got_event", false);
68 ASSERT_TRUE(LoadExtension(
69 test_data_dir_.AppendASCII("api_test/management/enabled_extension")));
70 ASSERT_TRUE(listener2.WaitUntilSatisfied());
71 }
72
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,LaunchApp)73 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest, LaunchApp) {
74 ExtensionTestMessageListener listener1("app_launched", false);
75 ExtensionTestMessageListener listener2("got_expected_error", false);
76 ASSERT_TRUE(LoadExtension(
77 test_data_dir_.AppendASCII("management/simple_extension")));
78 ASSERT_TRUE(LoadExtension(
79 test_data_dir_.AppendASCII("management/packaged_app")));
80 ASSERT_TRUE(LoadExtension(
81 test_data_dir_.AppendASCII("management/launch_app")));
82 ASSERT_TRUE(listener1.WaitUntilSatisfied());
83 ASSERT_TRUE(listener2.WaitUntilSatisfied());
84 }
85
86 #if defined(OS_CHROMEOS)
87
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,NoDemoModeAppLaunchSourceReported)88 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
89 NoDemoModeAppLaunchSourceReported) {
90 EXPECT_FALSE(chromeos::DemoSession::IsDeviceInDemoMode());
91
92 base::HistogramTester histogram_tester;
93 // Should see 0 apps launched from the API in the histogram at first.
94 histogram_tester.ExpectTotalCount("DemoMode.AppLaunchSource", 0);
95
96 ExtensionTestMessageListener app_launched_listener("app_launched", false);
97 ASSERT_TRUE(
98 LoadExtension(test_data_dir_.AppendASCII("management/packaged_app")));
99 ASSERT_TRUE(
100 LoadExtension(test_data_dir_.AppendASCII("management/launch_app")));
101 ASSERT_TRUE(app_launched_listener.WaitUntilSatisfied());
102
103 // Should still see 0 apps launched from the API in the histogram.
104 histogram_tester.ExpectTotalCount("DemoMode.AppLaunchSource", 0);
105 }
106
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,DemoModeAppLaunchSourceReported)107 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
108 DemoModeAppLaunchSourceReported) {
109 chromeos::DemoSession::SetDemoConfigForTesting(
110 chromeos::DemoSession::DemoModeConfig::kOnline);
111 EXPECT_TRUE(chromeos::DemoSession::IsDeviceInDemoMode());
112
113 base::HistogramTester histogram_tester;
114 // Should see 0 apps launched from the Launcher in the histogram at first.
115 histogram_tester.ExpectTotalCount("DemoMode.AppLaunchSource", 0);
116
117 ExtensionTestMessageListener app_launched_listener("app_launched", false);
118 ASSERT_TRUE(
119 LoadExtension(test_data_dir_.AppendASCII("management/packaged_app")));
120 ASSERT_TRUE(
121 LoadExtension(test_data_dir_.AppendASCII("management/launch_app")));
122 ASSERT_TRUE(app_launched_listener.WaitUntilSatisfied());
123
124 // Should see 1 app launched from the highlights app in the histogram.
125 histogram_tester.ExpectUniqueSample(
126 "DemoMode.AppLaunchSource",
127 chromeos::DemoSession::AppLaunchSource::kExtensionApi, 1);
128 }
129
130 #endif
131
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,LaunchAppFromBackground)132 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
133 LaunchAppFromBackground) {
134 ExtensionTestMessageListener listener1("success", false);
135 ASSERT_TRUE(LoadExtension(
136 test_data_dir_.AppendASCII("management/packaged_app")));
137 ASSERT_TRUE(LoadExtension(
138 test_data_dir_.AppendASCII("management/launch_app_from_background")));
139 ASSERT_TRUE(listener1.WaitUntilSatisfied());
140 }
141
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,SelfUninstall)142 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
143 SelfUninstall) {
144 ExtensionTestMessageListener listener1("success", false);
145 ASSERT_TRUE(LoadExtension(
146 test_data_dir_.AppendASCII("management/self_uninstall_helper")));
147 ASSERT_TRUE(LoadExtension(
148 test_data_dir_.AppendASCII("management/self_uninstall")));
149 ASSERT_TRUE(listener1.WaitUntilSatisfied());
150 }
151
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,SelfUninstallNoPermissions)152 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
153 SelfUninstallNoPermissions) {
154 ExtensionTestMessageListener listener1("success", false);
155 ASSERT_TRUE(LoadExtension(
156 test_data_dir_.AppendASCII("management/self_uninstall_helper")));
157 ASSERT_TRUE(LoadExtension(
158 test_data_dir_.AppendASCII("management/self_uninstall_noperm")));
159 ASSERT_TRUE(listener1.WaitUntilSatisfied());
160 }
161
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,GetSelfNoPermissions)162 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
163 GetSelfNoPermissions) {
164 ExtensionTestMessageListener listener1("success", false);
165 ASSERT_TRUE(LoadExtension(
166 test_data_dir_.AppendASCII("management/get_self")));
167 ASSERT_TRUE(listener1.WaitUntilSatisfied());
168 }
169
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,CreateAppShortcutConfirmDialog)170 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
171 CreateAppShortcutConfirmDialog) {
172 const Extension* app = InstallExtension(
173 test_data_dir_.AppendASCII("api_test/management/packaged_app"), 1);
174 ASSERT_TRUE(app);
175
176 const std::string app_id = app->id();
177
178 scoped_refptr<ManagementCreateAppShortcutFunction> create_shortcut_function(
179 new ManagementCreateAppShortcutFunction());
180 create_shortcut_function->set_user_gesture(true);
181 ManagementCreateAppShortcutFunction::SetAutoConfirmForTest(true);
182 test_utils::RunFunctionAndReturnSingleResult(
183 create_shortcut_function.get(),
184 base::StringPrintf("[\"%s\"]", app_id.c_str()), browser());
185
186 create_shortcut_function = new ManagementCreateAppShortcutFunction();
187 create_shortcut_function->set_user_gesture(true);
188 ManagementCreateAppShortcutFunction::SetAutoConfirmForTest(false);
189 EXPECT_TRUE(base::MatchPattern(
190 test_utils::RunFunctionAndReturnError(
191 create_shortcut_function.get(),
192 base::StringPrintf("[\"%s\"]", app_id.c_str()), browser()),
193 keys::kCreateShortcutCanceledError));
194 }
195
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,GetAllIncludesTerminated)196 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
197 GetAllIncludesTerminated) {
198 // Load an extension with a background page, so that we know it has a process
199 // running.
200 ExtensionTestMessageListener listener("ready", false);
201 const Extension* extension = LoadExtension(
202 test_data_dir_.AppendASCII("management/install_event"));
203 ASSERT_TRUE(extension);
204 ASSERT_TRUE(listener.WaitUntilSatisfied());
205
206 // The management API should list this extension.
207 scoped_refptr<ManagementGetAllFunction> function =
208 new ManagementGetAllFunction();
209 std::unique_ptr<base::Value> result(
210 test_utils::RunFunctionAndReturnSingleResult(function.get(), "[]",
211 browser()));
212 base::ListValue* list;
213 ASSERT_TRUE(result->GetAsList(&list));
214 EXPECT_EQ(1U, list->GetSize());
215
216 // And it should continue to do so even after it crashes.
217 ASSERT_TRUE(CrashEnabledExtension(extension->id()));
218
219 function = new ManagementGetAllFunction();
220 result.reset(test_utils::RunFunctionAndReturnSingleResult(function.get(),
221 "[]", browser()));
222 ASSERT_TRUE(result->GetAsList(&list));
223 EXPECT_EQ(1U, list->GetSize());
224 }
225
226 class ExtensionManagementApiEscalationTest :
227 public ExtensionManagementApiBrowserTest {
228 protected:
229 // The id of the permissions escalation test extension we use.
230 static const char kId[];
231
SetUpOnMainThread()232 void SetUpOnMainThread() override {
233 ExtensionManagementApiBrowserTest::SetUpOnMainThread();
234 EXPECT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
235 base::FilePath pem_path = test_data_dir_.
236 AppendASCII("permissions_increase").AppendASCII("permissions.pem");
237 base::FilePath path_v1 = PackExtensionWithOptions(
238 test_data_dir_.AppendASCII("permissions_increase").AppendASCII("v1"),
239 scoped_temp_dir_.GetPath().AppendASCII("permissions1.crx"), pem_path,
240 base::FilePath());
241 base::FilePath path_v2 = PackExtensionWithOptions(
242 test_data_dir_.AppendASCII("permissions_increase").AppendASCII("v2"),
243 scoped_temp_dir_.GetPath().AppendASCII("permissions2.crx"), pem_path,
244 base::FilePath());
245
246 // Install low-permission version of the extension.
247 ASSERT_TRUE(InstallExtension(path_v1, 1));
248 EXPECT_TRUE(extension_registry()->enabled_extensions().GetByID(kId));
249
250 // Update to a high-permission version - it should get disabled.
251 EXPECT_FALSE(UpdateExtension(kId, path_v2, -1));
252 EXPECT_FALSE(extension_registry()->enabled_extensions().GetByID(kId));
253 EXPECT_TRUE(extension_registry()->disabled_extensions().GetByID(kId));
254 EXPECT_TRUE(ExtensionPrefs::Get(browser()->profile())
255 ->DidExtensionEscalatePermissions(kId));
256 }
257
SetEnabled(bool enabled,bool user_gesture,const std::string & expected_error,scoped_refptr<const Extension> extension)258 void SetEnabled(bool enabled,
259 bool user_gesture,
260 const std::string& expected_error,
261 scoped_refptr<const Extension> extension) {
262 scoped_refptr<ManagementSetEnabledFunction> function(
263 new ManagementSetEnabledFunction);
264 function->set_extension(extension);
265 const char* const enabled_string = enabled ? "true" : "false";
266 if (user_gesture)
267 function->set_user_gesture(true);
268 function->SetRenderFrameHost(browser()->tab_strip_model()->
269 GetActiveWebContents()->GetMainFrame());
270 bool response = test_utils::RunFunction(
271 function.get(), base::StringPrintf("[\"%s\", %s]", kId, enabled_string),
272 browser(), api_test_utils::NONE);
273 if (expected_error.empty()) {
274 EXPECT_EQ(true, response);
275 } else {
276 EXPECT_TRUE(response == false);
277 EXPECT_EQ(expected_error, function->GetError());
278 }
279 }
280
281
282 private:
283 base::ScopedTempDir scoped_temp_dir_;
284 };
285
286 const char ExtensionManagementApiEscalationTest::kId[] =
287 "pgdpcfcocojkjfbgpiianjngphoopgmo";
288
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiEscalationTest,DisabledReason)289 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiEscalationTest,
290 DisabledReason) {
291 scoped_refptr<ManagementGetFunction> function =
292 new ManagementGetFunction();
293 std::unique_ptr<base::Value> result(
294 test_utils::RunFunctionAndReturnSingleResult(
295 function.get(), base::StringPrintf("[\"%s\"]", kId), browser()));
296 ASSERT_TRUE(result.get() != NULL);
297 ASSERT_TRUE(result->is_dict());
298 base::DictionaryValue* dict =
299 static_cast<base::DictionaryValue*>(result.get());
300 std::string reason;
301 EXPECT_TRUE(dict->GetStringASCII(keys::kDisabledReasonKey, &reason));
302 EXPECT_EQ(reason, std::string(keys::kDisabledReasonPermissionsIncrease));
303 }
304
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiEscalationTest,SetEnabled)305 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiEscalationTest,
306 SetEnabled) {
307 scoped_refptr<const Extension> source_extension =
308 ExtensionBuilder("test").Build();
309
310 // Expect an error about no gesture.
311 SetEnabled(true, false, keys::kGestureNeededForEscalationError,
312 source_extension);
313
314 {
315 // Expect an error that user cancelled the dialog.
316 ScopedTestDialogAutoConfirm auto_confirm(
317 ScopedTestDialogAutoConfirm::CANCEL);
318 SetEnabled(true, true, keys::kUserDidNotReEnableError, source_extension);
319 }
320
321 {
322 // This should succeed when user accepts dialog. We must wait for the
323 // process to connect *and* for the channel to finish initializing before
324 // trying to crash it. (NOTIFICATION_RENDERER_PROCESS_CREATED does not wait
325 // for the latter and can cause KillProcess to fail on Windows.)
326 content::WindowedNotificationObserver observer(
327 extensions::NOTIFICATION_EXTENSION_HOST_CREATED,
328 content::NotificationService::AllSources());
329 ScopedTestDialogAutoConfirm auto_confirm(
330 ScopedTestDialogAutoConfirm::ACCEPT);
331 SetEnabled(true, true, std::string(), source_extension);
332 observer.Wait();
333 }
334
335 {
336 // Crash the extension. Mock a reload by disabling and then enabling. The
337 // extension should be reloaded and enabled.
338 ScopedTestDialogAutoConfirm auto_confirm(
339 ScopedTestDialogAutoConfirm::ACCEPT);
340 ASSERT_TRUE(CrashEnabledExtension(kId));
341 // Register the target extension with extension service.
342 scoped_refptr<const Extension> target_extension =
343 ExtensionBuilder("TargetExtension").SetID(kId).Build();
344 extension_service()->AddExtension(target_extension.get());
345 SetEnabled(false, true, std::string(), source_extension);
346 SetEnabled(true, true, std::string(), source_extension);
347 EXPECT_TRUE(extension_registry()->enabled_extensions().GetByID(kId));
348 }
349 }
350
351 } // namespace extensions
352