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