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
22class 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.
85IN_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
103IN_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
114IN_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.
128IN_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.
141IN_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.
153IN_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.
165IN_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.
195class 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.
260IN_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
326IN_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.
399IN_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