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: 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. 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 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 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 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 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 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 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 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 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 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 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 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