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