Home | History | Annotate | Download | only in management
      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