Home | History | Annotate | Download | only in extensions
      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/run_loop.h"
      8 #include "base/threading/sequenced_worker_pool.h"
      9 #include "chrome/app/chrome_command_ids.h"
     10 #include "chrome/browser/extensions/extension_browsertest.h"
     11 #include "chrome/browser/extensions/extension_service.h"
     12 #include "chrome/browser/extensions/extension_sync_service.h"
     13 #include "chrome/browser/extensions/updater/extension_updater.h"
     14 #include "chrome/browser/profiles/profile.h"
     15 #include "chrome/browser/ui/browser.h"
     16 #include "chrome/browser/ui/global_error/global_error.h"
     17 #include "chrome/browser/ui/global_error/global_error_service.h"
     18 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
     19 #include "chrome/common/chrome_switches.h"
     20 #include "content/public/browser/browser_thread.h"
     21 #include "content/public/test/test_utils.h"
     22 #include "content/test/net/url_request_prepackaged_interceptor.h"
     23 #include "extensions/browser/extension_prefs.h"
     24 #include "extensions/browser/extension_registry.h"
     25 #include "extensions/common/extension.h"
     26 #include "net/url_request/url_fetcher.h"
     27 #include "sync/protocol/extension_specifics.pb.h"
     28 #include "sync/protocol/sync.pb.h"
     29 
     30 using extensions::Extension;
     31 using extensions::ExtensionRegistry;
     32 using extensions::ExtensionPrefs;
     33 
     34 class ExtensionDisabledGlobalErrorTest : public ExtensionBrowserTest {
     35  protected:
     36   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     37     ExtensionBrowserTest::SetUpCommandLine(command_line);
     38     command_line->AppendSwitchASCII(switches::kAppsGalleryUpdateURL,
     39                                     "http://localhost/autoupdate/updates.xml");
     40   }
     41 
     42   virtual void SetUpOnMainThread() OVERRIDE {
     43     EXPECT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
     44     service_ = browser()->profile()->GetExtensionService();
     45     registry_ = ExtensionRegistry::Get(browser()->profile());
     46     base::FilePath pem_path = test_data_dir_.
     47         AppendASCII("permissions_increase").AppendASCII("permissions.pem");
     48     path_v1_ = PackExtensionWithOptions(
     49         test_data_dir_.AppendASCII("permissions_increase").AppendASCII("v1"),
     50         scoped_temp_dir_.path().AppendASCII("permissions1.crx"),
     51         pem_path,
     52         base::FilePath());
     53     path_v2_ = PackExtensionWithOptions(
     54         test_data_dir_.AppendASCII("permissions_increase").AppendASCII("v2"),
     55         scoped_temp_dir_.path().AppendASCII("permissions2.crx"),
     56         pem_path,
     57         base::FilePath());
     58     path_v3_ = PackExtensionWithOptions(
     59         test_data_dir_.AppendASCII("permissions_increase").AppendASCII("v3"),
     60         scoped_temp_dir_.path().AppendASCII("permissions3.crx"),
     61         pem_path,
     62         base::FilePath());
     63   }
     64 
     65   // Returns the ExtensionDisabledGlobalError, if present.
     66   // Caution: currently only supports one error at a time.
     67   GlobalError* GetExtensionDisabledGlobalError() {
     68     return GlobalErrorServiceFactory::GetForProfile(browser()->profile())->
     69         GetGlobalErrorByMenuItemCommandID(IDC_EXTENSION_DISABLED_FIRST);
     70   }
     71 
     72   // Install the initial version, which should happen just fine.
     73   const Extension* InstallIncreasingPermissionExtensionV1() {
     74     size_t size_before = registry_->enabled_extensions().size();
     75     const Extension* extension = InstallExtension(path_v1_, 1);
     76     if (!extension)
     77       return NULL;
     78     if (registry_->enabled_extensions().size() != size_before + 1)
     79       return NULL;
     80     return extension;
     81   }
     82 
     83   // Upgrade to a version that wants more permissions. We should disable the
     84   // extension and prompt the user to reenable.
     85   const Extension* UpdateIncreasingPermissionExtension(
     86       const Extension* extension,
     87       const base::FilePath& crx_path,
     88       int expected_change) {
     89     size_t size_before = registry_->enabled_extensions().size();
     90     if (UpdateExtension(extension->id(), crx_path, expected_change))
     91       return NULL;
     92     content::BrowserThread::GetBlockingPool()->FlushForTesting();
     93     base::RunLoop().RunUntilIdle();
     94     EXPECT_EQ(size_before + expected_change,
     95               registry_->enabled_extensions().size());
     96     if (registry_->disabled_extensions().size() != 1u)
     97       return NULL;
     98 
     99     return registry_->disabled_extensions().begin()->get();
    100   }
    101 
    102   // Helper function to install an extension and upgrade it to a version
    103   // requiring additional permissions. Returns the new disabled Extension.
    104   const Extension* InstallAndUpdateIncreasingPermissionsExtension() {
    105     const Extension* extension = InstallIncreasingPermissionExtensionV1();
    106     extension = UpdateIncreasingPermissionExtension(extension, path_v2_, -1);
    107     return extension;
    108   }
    109 
    110   ExtensionService* service_;
    111   ExtensionRegistry* registry_;
    112   base::ScopedTempDir scoped_temp_dir_;
    113   base::FilePath path_v1_;
    114   base::FilePath path_v2_;
    115   base::FilePath path_v3_;
    116 };
    117 
    118 // Tests the process of updating an extension to one that requires higher
    119 // permissions, and accepting the permissions.
    120 IN_PROC_BROWSER_TEST_F(ExtensionDisabledGlobalErrorTest, AcceptPermissions) {
    121   const Extension* extension = InstallAndUpdateIncreasingPermissionsExtension();
    122   ASSERT_TRUE(extension);
    123   ASSERT_TRUE(GetExtensionDisabledGlobalError());
    124   const size_t size_before = registry_->enabled_extensions().size();
    125 
    126   service_->GrantPermissionsAndEnableExtension(extension);
    127   EXPECT_EQ(size_before + 1, registry_->enabled_extensions().size());
    128   EXPECT_EQ(0u, registry_->disabled_extensions().size());
    129   ASSERT_FALSE(GetExtensionDisabledGlobalError());
    130 }
    131 
    132 // Tests uninstalling an extension that was disabled due to higher permissions.
    133 IN_PROC_BROWSER_TEST_F(ExtensionDisabledGlobalErrorTest, Uninstall) {
    134   const Extension* extension = InstallAndUpdateIncreasingPermissionsExtension();
    135   ASSERT_TRUE(extension);
    136   ASSERT_TRUE(GetExtensionDisabledGlobalError());
    137   const size_t size_before = registry_->enabled_extensions().size();
    138 
    139   UninstallExtension(extension->id());
    140   EXPECT_EQ(size_before, registry_->enabled_extensions().size());
    141   EXPECT_EQ(0u, registry_->disabled_extensions().size());
    142   ASSERT_FALSE(GetExtensionDisabledGlobalError());
    143 }
    144 
    145 // Tests that no error appears if the user disabled the extension.
    146 IN_PROC_BROWSER_TEST_F(ExtensionDisabledGlobalErrorTest, UserDisabled) {
    147   const Extension* extension = InstallIncreasingPermissionExtensionV1();
    148   DisableExtension(extension->id());
    149   extension = UpdateIncreasingPermissionExtension(extension, path_v2_, 0);
    150   ASSERT_FALSE(GetExtensionDisabledGlobalError());
    151 }
    152 
    153 // Test that no error appears if the disable reason is unknown
    154 // (but probably was by the user).
    155 IN_PROC_BROWSER_TEST_F(ExtensionDisabledGlobalErrorTest,
    156                        UnknownReasonSamePermissions) {
    157   const Extension* extension = InstallIncreasingPermissionExtensionV1();
    158   DisableExtension(extension->id());
    159   // Clear disable reason to simulate legacy disables.
    160   ExtensionPrefs::Get(browser()->profile())
    161       ->ClearDisableReasons(extension->id());
    162   // Upgrade to version 2. Infer from version 1 having the same permissions
    163   // granted by the user that it was disabled by the user.
    164   extension = UpdateIncreasingPermissionExtension(extension, path_v2_, 0);
    165   ASSERT_TRUE(extension);
    166   ASSERT_FALSE(GetExtensionDisabledGlobalError());
    167 }
    168 
    169 // Test that an error appears if the disable reason is unknown
    170 // (but probably was for increased permissions).
    171 IN_PROC_BROWSER_TEST_F(ExtensionDisabledGlobalErrorTest,
    172                        UnknownReasonHigherPermissions) {
    173   const Extension* extension = InstallAndUpdateIncreasingPermissionsExtension();
    174   // Clear disable reason to simulate legacy disables.
    175   ExtensionPrefs::Get(service_->profile())
    176       ->ClearDisableReasons(extension->id());
    177   // We now have version 2 but only accepted permissions for version 1.
    178   GlobalError* error = GetExtensionDisabledGlobalError();
    179   ASSERT_TRUE(error);
    180   // Also, remove the upgrade error for version 2.
    181   GlobalErrorServiceFactory::GetForProfile(browser()->profile())->
    182       RemoveGlobalError(error);
    183   delete error;
    184   // Upgrade to version 3, with even higher permissions. Infer from
    185   // version 2 having higher-than-granted permissions that it was disabled
    186   // for permissions increase.
    187   extension = UpdateIncreasingPermissionExtension(extension, path_v3_, 0);
    188   ASSERT_TRUE(extension);
    189   ASSERT_TRUE(GetExtensionDisabledGlobalError());
    190 }
    191 
    192 // Test that an error appears if the extension gets disabled because a
    193 // version with higher permissions was installed by sync.
    194 IN_PROC_BROWSER_TEST_F(ExtensionDisabledGlobalErrorTest,
    195                        HigherPermissionsFromSync) {
    196   // Get data for extension v2 (disabled) into sync.
    197   const Extension* extension = InstallAndUpdateIncreasingPermissionsExtension();
    198   std::string extension_id = extension->id();
    199   ExtensionSyncService* sync_service = ExtensionSyncService::Get(
    200       browser()->profile());
    201   extensions::ExtensionSyncData sync_data =
    202       sync_service->GetExtensionSyncData(*extension);
    203   UninstallExtension(extension_id);
    204   extension = NULL;
    205 
    206   // Install extension v1.
    207   InstallIncreasingPermissionExtensionV1();
    208 
    209   // Note: This interceptor gets requests on the IO thread.
    210   content::URLLocalHostRequestPrepackagedInterceptor interceptor;
    211   net::URLFetcher::SetEnableInterceptionForTests(true);
    212   interceptor.SetResponseIgnoreQuery(
    213       GURL("http://localhost/autoupdate/updates.xml"),
    214       test_data_dir_.AppendASCII("permissions_increase")
    215                     .AppendASCII("updates.xml"));
    216   interceptor.SetResponseIgnoreQuery(
    217       GURL("http://localhost/autoupdate/v2.crx"),
    218       scoped_temp_dir_.path().AppendASCII("permissions2.crx"));
    219 
    220   extensions::ExtensionUpdater::CheckParams params;
    221   service_->updater()->set_default_check_params(params);
    222 
    223   // Sync is replacing an older version, so it pends.
    224   EXPECT_FALSE(sync_service->ProcessExtensionSyncData(sync_data));
    225 
    226   WaitForExtensionInstall();
    227   content::BrowserThread::GetBlockingPool()->FlushForTesting();
    228   base::RunLoop().RunUntilIdle();
    229 
    230   extension = service_->GetExtensionById(extension_id, true);
    231   ASSERT_TRUE(extension);
    232   EXPECT_EQ("2", extension->VersionString());
    233   EXPECT_EQ(1u, registry_->disabled_extensions().size());
    234   EXPECT_EQ(Extension::DISABLE_PERMISSIONS_INCREASE,
    235             ExtensionPrefs::Get(service_->profile())
    236                 ->GetDisableReasons(extension_id));
    237   EXPECT_TRUE(GetExtensionDisabledGlobalError());
    238 }
    239 
    240 // Test that an error appears if an extension gets installed server side.
    241 IN_PROC_BROWSER_TEST_F(ExtensionDisabledGlobalErrorTest, RemoteInstall) {
    242   static const char* extension_id = "pgdpcfcocojkjfbgpiianjngphoopgmo";
    243   ExtensionSyncService* sync_service =
    244       ExtensionSyncService::Get(browser()->profile());
    245 
    246   // Note: This interceptor gets requests on the IO thread.
    247   content::URLLocalHostRequestPrepackagedInterceptor interceptor;
    248   net::URLFetcher::SetEnableInterceptionForTests(true);
    249   interceptor.SetResponseIgnoreQuery(
    250       GURL("http://localhost/autoupdate/updates.xml"),
    251       test_data_dir_.AppendASCII("permissions_increase")
    252           .AppendASCII("updates.xml"));
    253   interceptor.SetResponseIgnoreQuery(
    254       GURL("http://localhost/autoupdate/v2.crx"),
    255       scoped_temp_dir_.path().AppendASCII("permissions2.crx"));
    256 
    257   extensions::ExtensionUpdater::CheckParams params;
    258   service_->updater()->set_default_check_params(params);
    259 
    260   sync_pb::EntitySpecifics specifics;
    261   specifics.mutable_extension()->set_id(extension_id);
    262   specifics.mutable_extension()->set_enabled(false);
    263   specifics.mutable_extension()->set_remote_install(true);
    264   specifics.mutable_extension()->set_update_url(
    265       "http://localhost/autoupdate/updates.xml");
    266   specifics.mutable_extension()->set_version("2");
    267   syncer::SyncData sync_data =
    268       syncer::SyncData::CreateRemoteData(1234567,
    269                                          specifics,
    270                                          base::Time::Now(),
    271                                          syncer::AttachmentIdList(),
    272                                          syncer::AttachmentServiceProxy());
    273   // Sync is installing a new extension, so it pends.
    274   EXPECT_FALSE(sync_service->ProcessExtensionSyncData(
    275       extensions::ExtensionSyncData(sync_data)));
    276 
    277   WaitForExtensionInstall();
    278   content::BrowserThread::GetBlockingPool()->FlushForTesting();
    279   base::RunLoop().RunUntilIdle();
    280 
    281   const Extension* extension = service_->GetExtensionById(extension_id, true);
    282   ASSERT_TRUE(extension);
    283   EXPECT_EQ("2", extension->VersionString());
    284   EXPECT_EQ(1u, registry_->disabled_extensions().size());
    285   EXPECT_EQ(Extension::DISABLE_REMOTE_INSTALL,
    286             ExtensionPrefs::Get(service_->profile())
    287                 ->GetDisableReasons(extension_id));
    288   EXPECT_TRUE(GetExtensionDisabledGlobalError());
    289 }
    290