Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / crx_installer_browsertest.cc
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/memory/ref_counted.h"
6 #include "chrome/browser/download/download_crx_util.h"
7 #include "chrome/browser/extensions/browser_action_test_util.h"
8 #include "chrome/browser/extensions/crx_installer.h"
9 #include "chrome/browser/extensions/extension_browsertest.h"
10 #include "chrome/browser/extensions/extension_install_prompt.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/fake_safe_browsing_database_manager.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/browser_window.h"
16 #include "chrome/browser/ui/tabs/tab_strip_model.h"
17 #include "chrome/common/extensions/extension_file_util.h"
18 #include "chrome/test/base/ui_test_utils.h"
19 #include "content/public/browser/download_manager.h"
20 #include "content/public/browser/render_view_host.h"
21 #include "content/public/test/browser_test_utils.h"
22 #include "content/public/test/download_test_observer.h"
23 #include "extensions/browser/extension_system.h"
24 #include "extensions/common/extension.h"
25 #include "extensions/common/feature_switch.h"
26 #include "extensions/common/permissions/permission_set.h"
27 #include "extensions/common/switches.h"
28 #include "grit/generated_resources.h"
29 #include "ui/base/l10n/l10n_util.h"
30
31 #if defined(OS_CHROMEOS)
32 #include "chrome/browser/chromeos/login/fake_user_manager.h"
33 #include "chrome/browser/chromeos/login/user_manager.h"
34 #endif
35
36 class SkBitmap;
37
38 namespace extensions {
39
40 namespace {
41
42 class MockInstallPrompt;
43
44 // This class holds information about things that happen with a
45 // MockInstallPrompt. We create the MockInstallPrompt but need to pass
46 // ownership of it to CrxInstaller, so it isn't safe to hang this data on
47 // MockInstallPrompt itself becuase we can't guarantee it's lifetime.
48 class MockPromptProxy :
49       public base::RefCountedThreadSafe<MockPromptProxy> {
50  public:
51   explicit MockPromptProxy(content::WebContents* web_contents);
52
53   bool did_succeed() const { return !extension_id_.empty(); }
54   const std::string& extension_id() { return extension_id_; }
55   bool confirmation_requested() const { return confirmation_requested_; }
56   const base::string16& error() const { return error_; }
57
58   // To have any effect, this should be called before CreatePrompt.
59   void set_record_oauth2_grant(bool record_oauth2_grant) {
60     record_oauth2_grant_.reset(new bool(record_oauth2_grant));
61   }
62
63   void set_extension_id(const std::string& id) { extension_id_ = id; }
64   void set_confirmation_requested() { confirmation_requested_ = true; }
65   void set_error(const base::string16& error) { error_ = error; }
66
67   scoped_ptr<ExtensionInstallPrompt> CreatePrompt();
68
69  private:
70   friend class base::RefCountedThreadSafe<MockPromptProxy>;
71   virtual ~MockPromptProxy();
72
73   // Data used to create a prompt.
74   content::WebContents* web_contents_;
75   scoped_ptr<bool> record_oauth2_grant_;
76
77   // Data reported back to us by the prompt we created.
78   bool confirmation_requested_;
79   std::string extension_id_;
80   base::string16 error_;
81 };
82
83 class MockInstallPrompt : public ExtensionInstallPrompt {
84  public:
85   MockInstallPrompt(content::WebContents* web_contents,
86                     MockPromptProxy* proxy) :
87       ExtensionInstallPrompt(web_contents),
88       proxy_(proxy) {}
89
90   void set_record_oauth2_grant(bool record) { record_oauth2_grant_ = record; }
91
92   // Overriding some of the ExtensionInstallUI API.
93   virtual void ConfirmInstall(
94       Delegate* delegate,
95       const Extension* extension,
96       const ShowDialogCallback& show_dialog_callback) OVERRIDE {
97     proxy_->set_confirmation_requested();
98     delegate->InstallUIProceed();
99   }
100   virtual void OnInstallSuccess(const Extension* extension,
101                                 SkBitmap* icon) OVERRIDE {
102     proxy_->set_extension_id(extension->id());
103     base::MessageLoopForUI::current()->Quit();
104   }
105   virtual void OnInstallFailure(const CrxInstallerError& error) OVERRIDE {
106     proxy_->set_error(error.message());
107     base::MessageLoopForUI::current()->Quit();
108   }
109
110  private:
111   scoped_refptr<MockPromptProxy> proxy_;
112 };
113
114
115 MockPromptProxy::MockPromptProxy(content::WebContents* web_contents) :
116     web_contents_(web_contents),
117     confirmation_requested_(false) {
118 }
119
120 MockPromptProxy::~MockPromptProxy() {}
121
122 scoped_ptr<ExtensionInstallPrompt> MockPromptProxy::CreatePrompt() {
123   scoped_ptr<MockInstallPrompt> prompt(
124       new MockInstallPrompt(web_contents_, this));
125   if (record_oauth2_grant_.get())
126     prompt->set_record_oauth2_grant(*record_oauth2_grant_.get());
127   return prompt.PassAs<ExtensionInstallPrompt>();
128 }
129
130
131 scoped_refptr<MockPromptProxy> CreateMockPromptProxyForBrowser(
132     Browser* browser) {
133   return new MockPromptProxy(
134       browser->tab_strip_model()->GetActiveWebContents());
135 }
136
137 }  // namespace
138
139 class ExtensionCrxInstallerTest : public ExtensionBrowserTest {
140  public:
141   scoped_ptr<WebstoreInstaller::Approval> GetApproval(
142       const char* manifest_dir,
143       const std::string& id,
144       bool strict_manifest_checks) {
145     scoped_ptr<WebstoreInstaller::Approval> result;
146
147     base::FilePath ext_path = test_data_dir_.AppendASCII(manifest_dir);
148     std::string error;
149     scoped_ptr<base::DictionaryValue> parsed_manifest(
150         extension_file_util::LoadManifest(ext_path, &error));
151     if (!parsed_manifest.get() || !error.empty())
152       return result.Pass();
153
154     return WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
155         browser()->profile(),
156         id,
157         parsed_manifest.Pass(),
158         strict_manifest_checks);
159   }
160
161   void RunCrxInstaller(const WebstoreInstaller::Approval* approval,
162                        scoped_ptr<ExtensionInstallPrompt> prompt,
163                        const base::FilePath& crx_path) {
164     ExtensionService* service = extensions::ExtensionSystem::Get(
165         browser()->profile())->extension_service();
166     scoped_refptr<CrxInstaller> installer(
167         CrxInstaller::Create(service, prompt.Pass(), approval));
168     installer->set_allow_silent_install(true);
169     installer->set_is_gallery_install(true);
170     installer->InstallCrx(crx_path);
171     content::RunMessageLoop();
172   }
173
174   // Installs a crx from |crx_relpath| (a path relative to the extension test
175   // data dir) with expected id |id|.
176   void InstallWithPrompt(const char* ext_relpath,
177                          const std::string& id,
178                          scoped_refptr<MockPromptProxy> mock_install_prompt) {
179     base::FilePath ext_path = test_data_dir_.AppendASCII(ext_relpath);
180
181     scoped_ptr<WebstoreInstaller::Approval> approval;
182     if (!id.empty())
183       approval = GetApproval(ext_relpath, id, true);
184
185     base::FilePath crx_path = PackExtension(ext_path);
186     EXPECT_FALSE(crx_path.empty());
187     RunCrxInstaller(approval.get(), mock_install_prompt->CreatePrompt(),
188                     crx_path);
189
190     EXPECT_TRUE(mock_install_prompt->did_succeed());
191   }
192
193   // Installs an extension and checks that it has scopes granted IFF
194   // |record_oauth2_grant| is true.
195   void CheckHasEmptyScopesAfterInstall(const std::string& ext_relpath,
196                                        bool record_oauth2_grant) {
197     CommandLine::ForCurrentProcess()->AppendSwitch(
198         switches::kEnableExperimentalExtensionApis);
199
200     ExtensionService* service = extensions::ExtensionSystem::Get(
201         browser()->profile())->extension_service();
202
203     scoped_refptr<MockPromptProxy> mock_prompt =
204         CreateMockPromptProxyForBrowser(browser());
205
206     mock_prompt->set_record_oauth2_grant(record_oauth2_grant);
207     InstallWithPrompt("browsertest/scopes", std::string(), mock_prompt);
208
209     scoped_refptr<PermissionSet> permissions =
210         service->extension_prefs()->GetGrantedPermissions(
211             mock_prompt->extension_id());
212     ASSERT_TRUE(permissions.get());
213   }
214 };
215
216 #if defined(OS_CHROMEOS)
217 #define MAYBE_Whitelisting DISABLED_Whitelisting
218 #else
219 #define MAYBE_Whitelisting Whitelisting
220 #endif
221 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, MAYBE_Whitelisting) {
222   std::string id = "hdgllgikmikobbofgnabhfimcfoopgnd";
223   ExtensionService* service = extensions::ExtensionSystem::Get(
224       browser()->profile())->extension_service();
225
226   // Even whitelisted extensions with NPAPI should not prompt.
227   scoped_refptr<MockPromptProxy> mock_prompt =
228       CreateMockPromptProxyForBrowser(browser());
229   InstallWithPrompt("uitest/plugins", id, mock_prompt);
230   EXPECT_FALSE(mock_prompt->confirmation_requested());
231   EXPECT_TRUE(service->GetExtensionById(id, false));
232 }
233
234 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
235                        GalleryInstallGetsExperimental) {
236   // We must modify the command line temporarily in order to pack an extension
237   // that requests the experimental permission.
238   CommandLine* command_line = CommandLine::ForCurrentProcess();
239   CommandLine old_command_line = *command_line;
240   command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
241   base::FilePath crx_path = PackExtension(
242       test_data_dir_.AppendASCII("experimental"));
243   ASSERT_FALSE(crx_path.empty());
244
245   // Now reset the command line so that we are testing specifically whether
246   // installing from webstore enables experimental permissions.
247   *(CommandLine::ForCurrentProcess()) = old_command_line;
248
249   EXPECT_FALSE(InstallExtension(crx_path, 0));
250   EXPECT_TRUE(InstallExtensionFromWebstore(crx_path, 1));
251 }
252
253 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, PlatformAppCrx) {
254   CommandLine::ForCurrentProcess()->AppendSwitch(
255       switches::kEnableExperimentalExtensionApis);
256   EXPECT_TRUE(InstallExtension(
257       test_data_dir_.AppendASCII("minimal_platform_app.crx"), 1));
258 }
259
260 // http://crbug.com/136397
261 #if defined(OS_CHROMEOS)
262 #define MAYBE_PackAndInstallExtension DISABLED_PackAndInstallExtension
263 #else
264 #define MAYBE_PackAndInstallExtension PackAndInstallExtension
265 #endif
266 IN_PROC_BROWSER_TEST_F(
267     ExtensionCrxInstallerTest, MAYBE_PackAndInstallExtension) {
268   if (!FeatureSwitch::easy_off_store_install()->IsEnabled())
269     return;
270
271   const int kNumDownloadsExpected = 1;
272
273   LOG(ERROR) << "PackAndInstallExtension: Packing extension";
274   base::FilePath crx_path = PackExtension(
275       test_data_dir_.AppendASCII("common/background_page"));
276   ASSERT_FALSE(crx_path.empty());
277   std::string crx_path_string(crx_path.value().begin(), crx_path.value().end());
278   GURL url = GURL(std::string("file:///").append(crx_path_string));
279
280   scoped_refptr<MockPromptProxy> mock_prompt =
281       CreateMockPromptProxyForBrowser(browser());
282   download_crx_util::SetMockInstallPromptForTesting(
283       mock_prompt->CreatePrompt());
284
285   LOG(ERROR) << "PackAndInstallExtension: Getting download manager";
286   content::DownloadManager* download_manager =
287       content::BrowserContext::GetDownloadManager(browser()->profile());
288
289   LOG(ERROR) << "PackAndInstallExtension: Setting observer";
290   scoped_ptr<content::DownloadTestObserver> observer(
291       new content::DownloadTestObserverTerminal(
292           download_manager, kNumDownloadsExpected,
293           content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_ACCEPT));
294   LOG(ERROR) << "PackAndInstallExtension: Navigating to URL";
295   ui_test_utils::NavigateToURLWithDisposition(browser(), url, CURRENT_TAB,
296       ui_test_utils::BROWSER_TEST_NONE);
297
298   EXPECT_TRUE(WaitForCrxInstallerDone());
299   LOG(ERROR) << "PackAndInstallExtension: Extension install";
300   EXPECT_TRUE(mock_prompt->confirmation_requested());
301   LOG(ERROR) << "PackAndInstallExtension: Extension install confirmed";
302 }
303
304 // Tests that scopes are only granted if |record_oauth2_grant_| on the prompt is
305 // true.
306 #if defined(OS_WIN)
307 #define MAYBE_GrantScopes DISABLED_GrantScopes
308 #else
309 #define MAYBE_GrantScopes GrantScopes
310 #endif
311 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, MAYBE_GrantScopes) {
312   EXPECT_NO_FATAL_FAILURE(CheckHasEmptyScopesAfterInstall("browsertest/scopes",
313                                                           true));
314 }
315
316 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, DoNotGrantScopes) {
317   EXPECT_NO_FATAL_FAILURE(CheckHasEmptyScopesAfterInstall("browsertest/scopes",
318                                                           false));
319 }
320
321 // Off-store install cannot yet be disabled on Aura.
322 #if defined(USE_AURA)
323 #define MAYBE_AllowOffStore DISABLED_AllowOffStore
324 #else
325 #define MAYBE_AllowOffStore AllowOffStore
326 #endif
327 // Crashy: http://crbug.com/140893
328 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, DISABLED_AllowOffStore) {
329   ExtensionService* service = extensions::ExtensionSystem::Get(
330       browser()->profile())->extension_service();
331   const bool kTestData[] = {false, true};
332
333   for (size_t i = 0; i < arraysize(kTestData); ++i) {
334     scoped_refptr<MockPromptProxy> mock_prompt =
335         CreateMockPromptProxyForBrowser(browser());
336
337     scoped_refptr<CrxInstaller> crx_installer(
338         CrxInstaller::Create(service, mock_prompt->CreatePrompt()));
339     crx_installer->set_install_cause(
340         extension_misc::INSTALL_CAUSE_USER_DOWNLOAD);
341
342     if (kTestData[i]) {
343       crx_installer->set_off_store_install_allow_reason(
344           CrxInstaller::OffStoreInstallAllowedInTest);
345     }
346
347     crx_installer->InstallCrx(test_data_dir_.AppendASCII("good.crx"));
348     EXPECT_EQ(kTestData[i],
349               WaitForExtensionInstall()) << kTestData[i];
350     EXPECT_EQ(kTestData[i], mock_prompt->did_succeed());
351     EXPECT_EQ(kTestData[i], mock_prompt->confirmation_requested()) <<
352         kTestData[i];
353     if (kTestData[i]) {
354       EXPECT_EQ(base::string16(), mock_prompt->error()) << kTestData[i];
355     } else {
356       EXPECT_EQ(l10n_util::GetStringUTF16(
357           IDS_EXTENSION_INSTALL_DISALLOWED_ON_SITE),
358           mock_prompt->error()) << kTestData[i];
359     }
360   }
361 }
362
363 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, HiDpiThemeTest) {
364   base::FilePath crx_path = test_data_dir_.AppendASCII("theme_hidpi_crx");
365   crx_path = crx_path.AppendASCII("theme_hidpi.crx");
366
367   ASSERT_TRUE(InstallExtension(crx_path,1));
368
369   const std::string extension_id("gllekhaobjnhgeagipipnkpmmmpchacm");
370   ExtensionService* service = extensions::ExtensionSystem::Get(
371       browser()->profile())->extension_service();
372   ASSERT_TRUE(service);
373   const extensions::Extension* extension =
374      service->GetExtensionById(extension_id, false);
375   ASSERT_TRUE(extension);
376   EXPECT_EQ(extension_id, extension->id());
377
378   UninstallExtension(extension_id);
379   EXPECT_FALSE(service->GetExtensionById(extension_id, false));
380 }
381
382 // See http://crbug.com/315299.
383 #if defined(OS_WIN)
384 #define MAYBE_InstallDelayedUntilNextUpdate \
385         DISABLED_InstallDelayedUntilNextUpdate
386 #else
387 #define MAYBE_InstallDelayedUntilNextUpdate InstallDelayedUntilNextUpdate
388 #endif  // defined(OS_WIN)
389 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
390                        MAYBE_InstallDelayedUntilNextUpdate) {
391   const std::string extension_id("ldnnhddmnhbkjipkidpdiheffobcpfmf");
392   base::FilePath crx_path = test_data_dir_.AppendASCII("delayed_install");
393   ExtensionSystem* extension_system = extensions::ExtensionSystem::Get(
394       browser()->profile());
395   ExtensionService* service = extension_system->extension_service();
396   ASSERT_TRUE(service);
397
398   // Install version 1 of the test extension. This extension does not have
399   // a background page but does have a browser action.
400   ASSERT_TRUE(InstallExtension(crx_path.AppendASCII("v1.crx"), 1));
401   const extensions::Extension* extension =
402      service->GetExtensionById(extension_id, false);
403   ASSERT_TRUE(extension);
404   ASSERT_EQ(extension_id, extension->id());
405   ASSERT_EQ("1.0", extension->version()->GetString());
406
407   // Make test extension non-idle by opening the extension's browser action
408   // popup. This should cause the installation to be delayed.
409   content::WindowedNotificationObserver loading_observer(
410       chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
411       content::Source<Profile>(profile()));
412   BrowserActionTestUtil util(browser());
413   // There is only one extension, so just click the first browser action.
414   ASSERT_EQ(1, util.NumberOfBrowserActions());
415   util.Press(0);
416   loading_observer.Wait();
417   ExtensionHost* extension_host =
418       content::Details<ExtensionHost>(loading_observer.details()).ptr();
419
420   // Install version 2 of the extension and check that it is indeed delayed.
421   ASSERT_TRUE(UpdateExtensionWaitForIdle(
422       extension_id, crx_path.AppendASCII("v2.crx"), 0));
423
424   ASSERT_EQ(1u, service->delayed_installs()->size());
425   extension = service->GetExtensionById(extension_id, false);
426   ASSERT_EQ("1.0", extension->version()->GetString());
427
428   // Make the extension idle again by closing the popup. This should not trigger
429   //the delayed install.
430   content::RenderProcessHostWatcher terminated_observer(
431       extension_host->render_process_host(),
432       content::RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
433   extension_host->render_view_host()->ClosePage();
434   terminated_observer.Wait();
435   ASSERT_EQ(1u, service->delayed_installs()->size());
436
437   // Install version 3 of the extension. Because the extension is idle,
438   // this install should succeed.
439   ASSERT_TRUE(UpdateExtensionWaitForIdle(
440       extension_id, crx_path.AppendASCII("v3.crx"), 0));
441   extension = service->GetExtensionById(extension_id, false);
442   ASSERT_EQ("3.0", extension->version()->GetString());
443
444   // The version 2 delayed install should be cleaned up, and finishing
445   // delayed extension installation shouldn't break anything.
446   ASSERT_EQ(0u, service->delayed_installs()->size());
447   service->MaybeFinishDelayedInstallations();
448   extension = service->GetExtensionById(extension_id, false);
449   ASSERT_EQ("3.0", extension->version()->GetString());
450 }
451
452 #if defined(FULL_SAFE_BROWSING)
453 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, Blacklist) {
454   scoped_refptr<FakeSafeBrowsingDatabaseManager> blacklist_db(
455       new FakeSafeBrowsingDatabaseManager(true));
456   Blacklist::ScopedDatabaseManagerForTest scoped_blacklist_db(blacklist_db);
457
458   blacklist_db->SetUnsafe("gllekhaobjnhgeagipipnkpmmmpchacm");
459
460   base::FilePath crx_path = test_data_dir_.AppendASCII("theme_hidpi_crx")
461                                           .AppendASCII("theme_hidpi.crx");
462   EXPECT_FALSE(InstallExtension(crx_path, 0));
463 }
464 #endif
465
466 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, NonStrictManifestCheck) {
467   scoped_refptr<MockPromptProxy> mock_prompt =
468       CreateMockPromptProxyForBrowser(browser());
469
470   // We want to simulate the case where the webstore sends a more recent
471   // version of the manifest, but the downloaded .crx file is old since
472   // the newly published version hasn't fully propagated to all the download
473   // servers yet. So load the v2 manifest, but then install the v1 crx file.
474   std::string id = "lhnaeclnpobnlbjbgogdanmhadigfnjp";
475   scoped_ptr<WebstoreInstaller::Approval> approval =
476       GetApproval("crx_installer/v2_no_permission_change/", id, false);
477
478   RunCrxInstaller(approval.get(), mock_prompt->CreatePrompt(),
479                   test_data_dir_.AppendASCII("crx_installer/v1.crx"));
480
481   EXPECT_TRUE(mock_prompt->did_succeed());
482 }
483
484 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, KioskOnlyTest) {
485   base::FilePath crx_path =
486       test_data_dir_.AppendASCII("kiosk/kiosk_only.crx");
487   EXPECT_FALSE(InstallExtension(crx_path, 0));
488 #if defined(OS_CHROMEOS)
489   // Simulate ChromeOS kiosk mode. |scoped_user_manager| will take over
490   // lifetime of |user_manager|.
491   chromeos::FakeUserManager* fake_user_manager =
492       new chromeos::FakeUserManager();
493   fake_user_manager->AddKioskAppUser("example@example.com");
494   fake_user_manager->LoginUser("example@example.com");
495   chromeos::ScopedUserManagerEnabler scoped_user_manager(fake_user_manager);
496   EXPECT_TRUE(InstallExtension(crx_path, 1));
497 #endif
498 }
499
500 }  // namespace extensions