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