Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2011 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/memory/ref_counted.h"
      6 #include "base/stl_util-inl.h"
      7 #include "chrome/browser/extensions/autoupdate_interceptor.h"
      8 #include "chrome/browser/extensions/extension_browsertest.h"
      9 #include "chrome/browser/extensions/extension_host.h"
     10 #include "chrome/browser/extensions/extension_service.h"
     11 #include "chrome/browser/extensions/extension_test_message_listener.h"
     12 #include "chrome/browser/extensions/extension_updater.h"
     13 #include "chrome/browser/prefs/pref_service.h"
     14 #include "chrome/browser/prefs/scoped_user_pref_update.h"
     15 #include "chrome/browser/profiles/profile.h"
     16 #include "chrome/browser/ui/browser.h"
     17 #include "chrome/common/pref_names.h"
     18 #include "chrome/common/url_constants.h"
     19 #include "chrome/test/ui_test_utils.h"
     20 #include "content/browser/renderer_host/render_view_host.h"
     21 
     22 class ExtensionManagementTest : public ExtensionBrowserTest {
     23  protected:
     24   // Helper method that returns whether the extension is at the given version.
     25   // This calls version(), which must be defined in the extension's bg page,
     26   // as well as asking the extension itself.
     27   //
     28   // Note that 'version' here means something different than the version field
     29   // in the extension's manifest. We use the version as reported by the
     30   // background page to test how overinstalling crx files with the same
     31   // manifest version works.
     32   bool IsExtensionAtVersion(const Extension* extension,
     33                             const std::string& expected_version) {
     34     // Test that the extension's version from the manifest and reported by the
     35     // background page is correct.  This is to ensure that the processes are in
     36     // sync with the Extension.
     37     ExtensionProcessManager* manager = browser()->profile()->
     38         GetExtensionProcessManager();
     39     ExtensionHost* ext_host = manager->GetBackgroundHostForExtension(extension);
     40     EXPECT_TRUE(ext_host);
     41     if (!ext_host)
     42       return false;
     43 
     44     std::string version_from_bg;
     45     bool exec = ui_test_utils::ExecuteJavaScriptAndExtractString(
     46         ext_host->render_view_host(), L"", L"version()", &version_from_bg);
     47     EXPECT_TRUE(exec);
     48     if (!exec)
     49       return false;
     50 
     51     if (version_from_bg != expected_version ||
     52         extension->VersionString() != expected_version)
     53       return false;
     54     return true;
     55   }
     56 
     57   // Helper method that installs a low permission extension then updates
     58   // to the second version requiring increased permissions. Returns whether
     59   // the operation was completed successfully.
     60   bool InstallAndUpdateIncreasingPermissionsExtension() {
     61     ExtensionService* service = browser()->profile()->GetExtensionService();
     62     size_t size_before = service->extensions()->size();
     63 
     64     // Install the initial version, which should happen just fine.
     65     if (!InstallExtension(
     66         test_data_dir_.AppendASCII("permissions-low-v1.crx"), 1))
     67       return false;
     68 
     69     // Upgrade to a version that wants more permissions. We should disable the
     70     // extension and prompt the user to reenable.
     71     if (service->extensions()->size() != size_before + 1)
     72       return false;
     73     if (!UpdateExtension(
     74         service->extensions()->at(size_before)->id(),
     75         test_data_dir_.AppendASCII("permissions-high-v2.crx"), -1))
     76       return false;
     77     EXPECT_EQ(size_before, service->extensions()->size());
     78     if (service->disabled_extensions()->size() != 1u)
     79       return false;
     80     return true;
     81   }
     82 };
     83 
     84 // Tests that installing the same version overwrites.
     85 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallSameVersion) {
     86   ExtensionService* service = browser()->profile()->GetExtensionService();
     87   const size_t size_before = service->extensions()->size();
     88   ASSERT_TRUE(InstallExtension(
     89       test_data_dir_.AppendASCII("install/install.crx"), 1));
     90   FilePath old_path = service->extensions()->back()->path();
     91 
     92   // Install an extension with the same version. The previous install should be
     93   // overwritten.
     94   ASSERT_TRUE(InstallExtension(
     95       test_data_dir_.AppendASCII("install/install_same_version.crx"), 0));
     96   FilePath new_path = service->extensions()->back()->path();
     97 
     98   EXPECT_FALSE(IsExtensionAtVersion(service->extensions()->at(size_before),
     99                                     "1.0"));
    100   EXPECT_NE(old_path.value(), new_path.value());
    101 }
    102 
    103 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallOlderVersion) {
    104   ExtensionService* service = browser()->profile()->GetExtensionService();
    105   const size_t size_before = service->extensions()->size();
    106   ASSERT_TRUE(InstallExtension(
    107       test_data_dir_.AppendASCII("install/install.crx"), 1));
    108   ASSERT_TRUE(InstallExtension(
    109       test_data_dir_.AppendASCII("install/install_older_version.crx"), 0));
    110   EXPECT_TRUE(IsExtensionAtVersion(service->extensions()->at(size_before),
    111                                    "1.0"));
    112 }
    113 
    114 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallThenCancel) {
    115   ExtensionService* service = browser()->profile()->GetExtensionService();
    116   const size_t size_before = service->extensions()->size();
    117   ASSERT_TRUE(InstallExtension(
    118       test_data_dir_.AppendASCII("install/install.crx"), 1));
    119 
    120   // Cancel this install.
    121   StartInstallButCancel(test_data_dir_.AppendASCII("install/install_v2.crx"));
    122   EXPECT_TRUE(IsExtensionAtVersion(service->extensions()->at(size_before),
    123                                    "1.0"));
    124 }
    125 
    126 // Tests that installing and uninstalling extensions don't crash with an
    127 // incognito window open.
    128 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, Incognito) {
    129   // Open an incognito window to the extensions management page.  We just
    130   // want to make sure that we don't crash while playing with extensions when
    131   // this guy is around.
    132   ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
    133                                      GURL(chrome::kChromeUIExtensionsURL));
    134 
    135   ASSERT_TRUE(InstallExtension(test_data_dir_.AppendASCII("good.crx"), 1));
    136   UninstallExtension("ldnnhddmnhbkjipkidpdiheffobcpfmf");
    137 }
    138 
    139 // Tests the process of updating an extension to one that requires higher
    140 // permissions.
    141 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, UpdatePermissions) {
    142   ExtensionService* service = browser()->profile()->GetExtensionService();
    143   ASSERT_TRUE(InstallAndUpdateIncreasingPermissionsExtension());
    144   const size_t size_before = service->extensions()->size();
    145 
    146   // Now try reenabling it.
    147   service->EnableExtension(service->disabled_extensions()->at(0)->id());
    148   EXPECT_EQ(size_before + 1, service->extensions()->size());
    149   EXPECT_EQ(0u, service->disabled_extensions()->size());
    150 }
    151 
    152 // Tests that we can uninstall a disabled extension.
    153 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, UninstallDisabled) {
    154   ExtensionService* service = browser()->profile()->GetExtensionService();
    155   ASSERT_TRUE(InstallAndUpdateIncreasingPermissionsExtension());
    156   const size_t size_before = service->extensions()->size();
    157 
    158   // Now try uninstalling it.
    159   UninstallExtension(service->disabled_extensions()->at(0)->id());
    160   EXPECT_EQ(size_before, service->extensions()->size());
    161   EXPECT_EQ(0u, service->disabled_extensions()->size());
    162 }
    163 
    164 // Tests that disabling and re-enabling an extension works.
    165 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, DisableEnable) {
    166   ExtensionProcessManager* manager = browser()->profile()->
    167       GetExtensionProcessManager();
    168   ExtensionService* service = browser()->profile()->GetExtensionService();
    169   const size_t size_before = service->extensions()->size();
    170 
    171   // Load an extension, expect the background page to be available.
    172   ASSERT_TRUE(LoadExtension(
    173       test_data_dir_.AppendASCII("good").AppendASCII("Extensions")
    174                     .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa")
    175                     .AppendASCII("1.0")));
    176   ASSERT_EQ(size_before + 1, service->extensions()->size());
    177   EXPECT_EQ(0u, service->disabled_extensions()->size());
    178   const Extension* extension = service->extensions()->at(size_before);
    179   EXPECT_TRUE(manager->GetBackgroundHostForExtension(extension));
    180 
    181   // After disabling, the background page should go away.
    182   service->DisableExtension("bjafgdebaacbbbecmhlhpofkepfkgcpa");
    183   EXPECT_EQ(size_before, service->extensions()->size());
    184   EXPECT_EQ(1u, service->disabled_extensions()->size());
    185   EXPECT_FALSE(manager->GetBackgroundHostForExtension(extension));
    186 
    187   // And bring it back.
    188   service->EnableExtension("bjafgdebaacbbbecmhlhpofkepfkgcpa");
    189   EXPECT_EQ(size_before + 1, service->extensions()->size());
    190   EXPECT_EQ(0u, service->disabled_extensions()->size());
    191   EXPECT_TRUE(manager->GetBackgroundHostForExtension(extension));
    192 }
    193 
    194 // Used for testing notifications sent during extension updates.
    195 class NotificationListener : public NotificationObserver {
    196  public:
    197   NotificationListener() : started_(false), finished_(false) {
    198     NotificationType::Type types[] = {
    199       NotificationType::EXTENSION_UPDATING_STARTED,
    200       NotificationType::EXTENSION_UPDATING_FINISHED,
    201       NotificationType::EXTENSION_UPDATE_FOUND
    202     };
    203     for (size_t i = 0; i < arraysize(types); i++) {
    204       registrar_.Add(this, types[i], NotificationService::AllSources());
    205     }
    206   }
    207   ~NotificationListener() {}
    208 
    209   bool started() { return started_; }
    210 
    211   bool finished() { return finished_; }
    212 
    213   const std::set<std::string>& updates() { return updates_; }
    214 
    215   void Reset() {
    216     started_ = false;
    217     finished_ = false;
    218     updates_.clear();
    219   }
    220 
    221   // Implements NotificationObserver interface.
    222   virtual void Observe(NotificationType type,
    223                        const NotificationSource& source,
    224                        const NotificationDetails& details) {
    225     switch (type.value) {
    226       case NotificationType::EXTENSION_UPDATING_STARTED: {
    227         DCHECK(!started_);
    228         started_ = true;
    229         break;
    230       }
    231       case NotificationType::EXTENSION_UPDATING_FINISHED: {
    232         DCHECK(!finished_);
    233         finished_ = true;
    234         break;
    235       }
    236       case NotificationType::EXTENSION_UPDATE_FOUND: {
    237         const std::string* id = Details<const std::string>(details).ptr();
    238         updates_.insert(*id);
    239         break;
    240       }
    241       default:
    242         NOTREACHED();
    243     }
    244   }
    245 
    246  private:
    247   NotificationRegistrar registrar_;
    248 
    249   // Did we see EXTENSION_UPDATING_STARTED?
    250   bool started_;
    251 
    252   // Did we see EXTENSION_UPDATING_FINISHED?
    253   bool finished_;
    254 
    255   // The set of extension id's we've seen via EXTENSION_UPDATE_FOUND.
    256   std::set<std::string> updates_;
    257 };
    258 
    259 // Tests extension autoupdate.
    260 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, AutoUpdate) {
    261   NotificationListener notification_listener;
    262   FilePath basedir = test_data_dir_.AppendASCII("autoupdate");
    263   // Note: This interceptor gets requests on the IO thread.
    264   scoped_refptr<AutoUpdateInterceptor> interceptor(new AutoUpdateInterceptor());
    265   URLFetcher::enable_interception_for_tests(true);
    266 
    267   interceptor->SetResponseOnIOThread("http://localhost/autoupdate/manifest",
    268                                      basedir.AppendASCII("manifest_v2.xml"));
    269   interceptor->SetResponseOnIOThread("http://localhost/autoupdate/v2.crx",
    270                                      basedir.AppendASCII("v2.crx"));
    271 
    272   // Install version 1 of the extension.
    273   ExtensionTestMessageListener listener1("v1 installed", false);
    274   ExtensionService* service = browser()->profile()->GetExtensionService();
    275   const size_t size_before = service->extensions()->size();
    276   ASSERT_TRUE(service->disabled_extensions()->empty());
    277   ASSERT_TRUE(InstallExtension(basedir.AppendASCII("v1.crx"), 1));
    278   listener1.WaitUntilSatisfied();
    279   const ExtensionList* extensions = service->extensions();
    280   ASSERT_EQ(size_before + 1, extensions->size());
    281   ASSERT_EQ("ogjcoiohnmldgjemafoockdghcjciccf",
    282             extensions->at(size_before)->id());
    283   ASSERT_EQ("1.0", extensions->at(size_before)->VersionString());
    284 
    285   // We don't want autoupdate blacklist checks.
    286   service->updater()->set_blacklist_checks_enabled(false);
    287 
    288   // Run autoupdate and make sure version 2 of the extension was installed.
    289   ExtensionTestMessageListener listener2("v2 installed", false);
    290   service->updater()->CheckNow();
    291   ASSERT_TRUE(WaitForExtensionInstall());
    292   listener2.WaitUntilSatisfied();
    293   extensions = service->extensions();
    294   ASSERT_EQ(size_before + 1, extensions->size());
    295   ASSERT_EQ("ogjcoiohnmldgjemafoockdghcjciccf",
    296             extensions->at(size_before)->id());
    297   ASSERT_EQ("2.0", extensions->at(size_before)->VersionString());
    298   ASSERT_TRUE(notification_listener.started());
    299   ASSERT_TRUE(notification_listener.finished());
    300   ASSERT_TRUE(ContainsKey(notification_listener.updates(),
    301                           "ogjcoiohnmldgjemafoockdghcjciccf"));
    302   notification_listener.Reset();
    303 
    304   // Now try doing an update to version 3, which has been incorrectly
    305   // signed. This should fail.
    306   interceptor->SetResponseOnIOThread("http://localhost/autoupdate/manifest",
    307                                      basedir.AppendASCII("manifest_v3.xml"));
    308   interceptor->SetResponseOnIOThread("http://localhost/autoupdate/v3.crx",
    309                                      basedir.AppendASCII("v3.crx"));
    310 
    311   service->updater()->CheckNow();
    312   ASSERT_TRUE(WaitForExtensionInstallError());
    313   ASSERT_TRUE(notification_listener.started());
    314   ASSERT_TRUE(notification_listener.finished());
    315   ASSERT_TRUE(ContainsKey(notification_listener.updates(),
    316                           "ogjcoiohnmldgjemafoockdghcjciccf"));
    317 
    318   // Make sure the extension state is the same as before.
    319   extensions = service->extensions();
    320   ASSERT_EQ(size_before + 1, extensions->size());
    321   ASSERT_EQ("ogjcoiohnmldgjemafoockdghcjciccf",
    322             extensions->at(size_before)->id());
    323   ASSERT_EQ("2.0", extensions->at(size_before)->VersionString());
    324 }
    325 
    326 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalUrlUpdate) {
    327   ExtensionService* service = browser()->profile()->GetExtensionService();
    328   const char* kExtensionId = "ogjcoiohnmldgjemafoockdghcjciccf";
    329   // We don't want autoupdate blacklist checks.
    330   service->updater()->set_blacklist_checks_enabled(false);
    331 
    332   FilePath basedir = test_data_dir_.AppendASCII("autoupdate");
    333 
    334   // Note: This interceptor gets requests on the IO thread.
    335   scoped_refptr<AutoUpdateInterceptor> interceptor(new AutoUpdateInterceptor());
    336   URLFetcher::enable_interception_for_tests(true);
    337 
    338   interceptor->SetResponseOnIOThread("http://localhost/autoupdate/manifest",
    339                                      basedir.AppendASCII("manifest_v2.xml"));
    340   interceptor->SetResponseOnIOThread("http://localhost/autoupdate/v2.crx",
    341                                      basedir.AppendASCII("v2.crx"));
    342 
    343   const size_t size_before = service->extensions()->size();
    344   ASSERT_TRUE(service->disabled_extensions()->empty());
    345 
    346   PendingExtensionManager* pending_extension_manager =
    347       service->pending_extension_manager();
    348 
    349   // The code that reads external_extensions.json uses this method to inform
    350   // the ExtensionService of an extension to download.  Using the real code
    351   // is race-prone, because instantating the ExtensionService starts a read
    352   // of external_extensions.json before this test function starts.
    353 
    354   pending_extension_manager->AddFromExternalUpdateUrl(
    355       kExtensionId, GURL("http://localhost/autoupdate/manifest"),
    356       Extension::EXTERNAL_PREF_DOWNLOAD);
    357 
    358   // Run autoupdate and make sure version 2 of the extension was installed.
    359   service->updater()->CheckNow();
    360   ASSERT_TRUE(WaitForExtensionInstall());
    361   const ExtensionList* extensions = service->extensions();
    362   ASSERT_EQ(size_before + 1, extensions->size());
    363   ASSERT_EQ(kExtensionId, extensions->at(size_before)->id());
    364   ASSERT_EQ("2.0", extensions->at(size_before)->VersionString());
    365 
    366   // Uninstalling the extension should set a pref that keeps the extension from
    367   // being installed again the next time external_extensions.json is read.
    368 
    369   UninstallExtension(kExtensionId);
    370 
    371   ExtensionPrefs* extension_prefs = service->extension_prefs();
    372   EXPECT_TRUE(extension_prefs->IsExternalExtensionUninstalled(kExtensionId))
    373       << "Uninstalling should set kill bit on externaly installed extension.";
    374 
    375   // Try to install the extension again from an external source. It should fail
    376   // because of the killbit.
    377   pending_extension_manager->AddFromExternalUpdateUrl(
    378       kExtensionId, GURL("http://localhost/autoupdate/manifest"),
    379       Extension::EXTERNAL_PREF_DOWNLOAD);
    380   EXPECT_FALSE(pending_extension_manager->IsIdPending(kExtensionId))
    381       << "External reinstall of a killed extension shouldn't work.";
    382   EXPECT_TRUE(extension_prefs->IsExternalExtensionUninstalled(kExtensionId))
    383       << "External reinstall of a killed extension should leave it killed.";
    384 
    385   // Installing from non-external source.
    386   ASSERT_TRUE(InstallExtension(basedir.AppendASCII("v2.crx"), 1));
    387 
    388   EXPECT_FALSE(extension_prefs->IsExternalExtensionUninstalled(kExtensionId))
    389       << "Reinstalling should clear the kill bit.";
    390 
    391   // Uninstalling from a non-external source should not set the kill bit.
    392   UninstallExtension(kExtensionId);
    393 
    394   EXPECT_FALSE(extension_prefs->IsExternalExtensionUninstalled(kExtensionId))
    395       << "Uninstalling non-external extension should not set kill bit.";
    396 }
    397 
    398 // See http://crbug.com/57378 for flakiness details.
    399 IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalPolicyRefresh) {
    400   ExtensionService* service = browser()->profile()->GetExtensionService();
    401   const char* kExtensionId = "ogjcoiohnmldgjemafoockdghcjciccf";
    402   // We don't want autoupdate blacklist checks.
    403   service->updater()->set_blacklist_checks_enabled(false);
    404 
    405   FilePath basedir = test_data_dir_.AppendASCII("autoupdate");
    406 
    407   // Note: This interceptor gets requests on the IO thread.
    408   scoped_refptr<AutoUpdateInterceptor> interceptor(new AutoUpdateInterceptor());
    409   URLFetcher::enable_interception_for_tests(true);
    410 
    411   interceptor->SetResponseOnIOThread("http://localhost/autoupdate/manifest",
    412                                      basedir.AppendASCII("manifest_v2.xml"));
    413   interceptor->SetResponseOnIOThread("http://localhost/autoupdate/v2.crx",
    414                                      basedir.AppendASCII("v2.crx"));
    415 
    416   const size_t size_before = service->extensions()->size();
    417   ASSERT_TRUE(service->disabled_extensions()->empty());
    418 
    419   PrefService* prefs = browser()->profile()->GetPrefs();
    420   {
    421     // Set the policy as a user preference and fire notification observers.
    422     ListPrefUpdate pref_update(prefs, prefs::kExtensionInstallForceList);
    423     ListValue* forcelist = pref_update.Get();
    424     ASSERT_TRUE(forcelist->empty());
    425     forcelist->Append(Value::CreateStringValue(
    426         std::string(kExtensionId) +
    427         ";http://localhost/autoupdate/manifest"));
    428   }
    429 
    430   // Check if the extension got installed.
    431   ASSERT_TRUE(WaitForExtensionInstall());
    432   const ExtensionList* extensions = service->extensions();
    433   ASSERT_EQ(size_before + 1, extensions->size());
    434   ASSERT_EQ(kExtensionId, extensions->at(size_before)->id());
    435   EXPECT_EQ("2.0", extensions->at(size_before)->VersionString());
    436   EXPECT_EQ(Extension::EXTERNAL_POLICY_DOWNLOAD,
    437             extensions->at(size_before)->location());
    438 
    439   // Try to disable and unstall the extension which should fail.
    440   service->DisableExtension(kExtensionId);
    441   EXPECT_EQ(size_before + 1, service->extensions()->size());
    442   EXPECT_EQ(0u, service->disabled_extensions()->size());
    443   UninstallExtension(kExtensionId);
    444   EXPECT_EQ(size_before + 1, service->extensions()->size());
    445   EXPECT_EQ(0u, service->disabled_extensions()->size());
    446 
    447   // Now try to disable it through the management api.
    448   ExtensionTestMessageListener listener1("ready", false);
    449   ASSERT_TRUE(LoadExtension(
    450       test_data_dir_.AppendASCII("management/uninstall_extension")));
    451   ASSERT_TRUE(listener1.WaitUntilSatisfied());
    452   EXPECT_EQ(size_before + 2, service->extensions()->size());
    453   EXPECT_EQ(0u, service->disabled_extensions()->size());
    454 
    455   // Check that emptying the list triggers uninstall.
    456   {
    457     prefs->ClearPref(prefs::kExtensionInstallForceList);
    458   }
    459   EXPECT_EQ(size_before + 1, extensions->size());
    460   ExtensionList::const_iterator i;
    461   for (i = extensions->begin(); i != extensions->end(); ++i)
    462     EXPECT_NE(kExtensionId, (*i)->id());
    463 }
    464