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