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 "chrome/browser/extensions/crx_installer.h"
6 
7 #include <stddef.h>
8 
9 #include <utility>
10 
11 #include "base/at_exit.h"
12 #include "base/bind.h"
13 #include "base/files/file_path.h"
14 #include "base/files/file_util.h"
15 #include "base/files/scoped_temp_dir.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/memory/ref_counted.h"
18 #include "base/optional.h"
19 #include "base/run_loop.h"
20 #include "base/stl_util.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/threading/thread_restrictions.h"
23 #include "build/build_config.h"
24 #include "chrome/browser/download/download_crx_util.h"
25 #include "chrome/browser/extensions/extension_browsertest.h"
26 #include "chrome/browser/extensions/extension_install_prompt.h"
27 #include "chrome/browser/extensions/extension_install_prompt_show_params.h"
28 #include "chrome/browser/extensions/extension_service.h"
29 #include "chrome/browser/extensions/extension_tab_util.h"
30 #include "chrome/browser/extensions/extension_util.h"
31 #include "chrome/browser/extensions/fake_safe_browsing_database_manager.h"
32 #include "chrome/browser/extensions/forced_extensions/install_stage_tracker.h"
33 #include "chrome/browser/extensions/scripting_permissions_modifier.h"
34 #include "chrome/browser/profiles/profile.h"
35 #include "chrome/browser/ui/browser.h"
36 #include "chrome/browser/ui/browser_window.h"
37 #include "chrome/browser/ui/tabs/tab_strip_model.h"
38 #include "chrome/browser/web_applications/components/web_application_info.h"
39 #include "chrome/grit/generated_resources.h"
40 #include "chrome/test/base/ui_test_utils.h"
41 #include "components/safe_browsing/buildflags.h"
42 #include "content/public/browser/browser_thread.h"
43 #include "content/public/browser/download_manager.h"
44 #include "content/public/browser/render_view_host.h"
45 #include "content/public/test/browser_test.h"
46 #include "content/public/test/browser_test_utils.h"
47 #include "content/public/test/download_test_observer.h"
48 #include "content/public/test/test_utils.h"
49 #include "extensions/browser/extension_dialog_auto_confirm.h"
50 #include "extensions/browser/extension_prefs.h"
51 #include "extensions/browser/extension_registry.h"
52 #include "extensions/browser/extension_system.h"
53 #include "extensions/browser/install/crx_install_error.h"
54 #include "extensions/browser/install/sandboxed_unpacker_failure_reason.h"
55 #include "extensions/browser/management_policy.h"
56 #include "extensions/browser/notification_types.h"
57 #include "extensions/common/extension.h"
58 #include "extensions/common/extension_builder.h"
59 #include "extensions/common/extension_features.h"
60 #include "extensions/common/feature_switch.h"
61 #include "extensions/common/file_util.h"
62 #include "extensions/common/permissions/api_permission.h"
63 #include "extensions/common/permissions/permission_set.h"
64 #include "extensions/common/permissions/permissions_data.h"
65 #include "extensions/common/switches.h"
66 #include "extensions/test/test_extension_dir.h"
67 #include "third_party/skia/include/core/SkBitmap.h"
68 #include "ui/base/l10n/l10n_util.h"
69 
70 #if defined(OS_CHROMEOS)
71 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
72 #include "chrome/browser/extensions/extension_assets_manager_chromeos.h"
73 #include "chromeos/constants/chromeos_switches.h"
74 #include "components/user_manager/scoped_user_manager.h"
75 #endif
76 
77 class SkBitmap;
78 
79 namespace {
80 
81 const char kAppUrl[] = "http://www.google.com";
82 const char kAppTitle[] = "Test title";
83 const char kAppDescription[] = "Test description";
84 const char kShortcutItemName[] = "shortcut";
85 const char kShortcutUrl[] = "http://www.google.com/shortcut";
86 const char kShortcutIconUrl[] = "http://www.google.com/shortcut/icon.png";
87 
88 }  // anonymous namespace
89 
90 namespace extensions {
91 
92 namespace {
93 
94 class MockInstallPrompt;
95 
96 // This class holds information about things that happen with a
97 // MockInstallPrompt. We create the MockInstallPrompt but need to pass
98 // ownership of it to CrxInstaller, so it isn't safe to hang this data on
99 // MockInstallPrompt itself because we can't guarantee it's lifetime.
100 class MockPromptProxy {
101  public:
102   MockPromptProxy(content::WebContents* web_contents,
103                   ScopedTestDialogAutoConfirm::AutoConfirm confirm_mode);
104   ~MockPromptProxy();
105 
did_succeed() const106   bool did_succeed() const { return !extension_id_.empty(); }
extension_id()107   const std::string& extension_id() { return extension_id_; }
confirmation_requested() const108   bool confirmation_requested() const { return confirmation_requested_; }
error() const109   const base::string16& error() const { return error_; }
110 
set_extension_id(const std::string & id)111   void set_extension_id(const std::string& id) { extension_id_ = id; }
set_confirmation_requested(bool requested)112   void set_confirmation_requested(bool requested) {
113     confirmation_requested_ = requested;
114   }
set_error(const base::string16 & error)115   void set_error(const base::string16& error) { error_ = error; }
116 
117   std::unique_ptr<ExtensionInstallPrompt> CreatePrompt();
118 
119  private:
120   // Data used to create a prompt.
121   content::WebContents* web_contents_;
122 
123   // Data reported back to us by the prompt we created.
124   bool confirmation_requested_;
125   std::string extension_id_;
126   base::string16 error_;
127 
128   std::unique_ptr<ScopedTestDialogAutoConfirm> auto_confirm;
129 
130   DISALLOW_COPY_AND_ASSIGN(MockPromptProxy);
131 };
132 
CreateSquareBitmap(int size)133 SkBitmap CreateSquareBitmap(int size) {
134   SkBitmap bitmap;
135   bitmap.allocN32Pixels(size, size);
136   bitmap.eraseColor(SK_ColorRED);
137   return bitmap;
138 }
139 
CreateWebAppInfo(const char * title,const char * description,const char * start_url,int size,bool create_with_shortcuts)140 WebApplicationInfo CreateWebAppInfo(const char* title,
141                                     const char* description,
142                                     const char* start_url,
143                                     int size,
144                                     bool create_with_shortcuts) {
145   WebApplicationInfo web_app_info;
146   web_app_info.title = base::UTF8ToUTF16(title);
147   web_app_info.description = base::UTF8ToUTF16(description);
148   web_app_info.start_url = GURL(start_url);
149   web_app_info.scope = GURL(start_url);
150   web_app_info.icon_bitmaps_any[size] = CreateSquareBitmap(size);
151   if (create_with_shortcuts) {
152     WebApplicationShortcutsMenuItemInfo shortcut_item;
153     WebApplicationShortcutsMenuItemInfo::Icon icon;
154     std::map<SquareSizePx, SkBitmap> shortcut_icon_bitmaps;
155     shortcut_item.name = base::UTF8ToUTF16(kShortcutItemName);
156     shortcut_item.url = GURL(kShortcutUrl);
157     icon.url = GURL(kShortcutIconUrl);
158     icon.square_size_px = size;
159     shortcut_item.shortcut_icon_infos.push_back(std::move(icon));
160     web_app_info.shortcuts_menu_item_infos.emplace_back(
161         std::move(shortcut_item));
162     shortcut_icon_bitmaps[size] = CreateSquareBitmap(size);
163     web_app_info.shortcuts_menu_icons_bitmaps.emplace_back(
164         std::move(shortcut_icon_bitmaps));
165   }
166   return web_app_info;
167 }
168 
169 class MockInstallPrompt : public ExtensionInstallPrompt {
170  public:
MockInstallPrompt(content::WebContents * web_contents,MockPromptProxy * proxy)171   MockInstallPrompt(content::WebContents* web_contents,
172                     MockPromptProxy* proxy) :
173       ExtensionInstallPrompt(web_contents),
174       proxy_(proxy) {}
175 
176   // Overriding some of the ExtensionInstallUI API.
OnInstallSuccess(scoped_refptr<const Extension> extension,SkBitmap * icon)177   void OnInstallSuccess(scoped_refptr<const Extension> extension,
178                         SkBitmap* icon) override {
179     proxy_->set_extension_id(extension->id());
180     proxy_->set_confirmation_requested(did_call_show_dialog());
181   }
OnInstallFailure(const CrxInstallError & error)182   void OnInstallFailure(const CrxInstallError& error) override {
183     proxy_->set_error(error.message());
184     proxy_->set_confirmation_requested(did_call_show_dialog());
185   }
186 
187  private:
188   MockPromptProxy* proxy_;
189 
190   DISALLOW_COPY_AND_ASSIGN(MockInstallPrompt);
191 };
192 
MockPromptProxy(content::WebContents * web_contents,ScopedTestDialogAutoConfirm::AutoConfirm confirm_mode)193 MockPromptProxy::MockPromptProxy(
194     content::WebContents* web_contents,
195     ScopedTestDialogAutoConfirm::AutoConfirm confirm_mode)
196     : web_contents_(web_contents),
197       confirmation_requested_(false),
198       auto_confirm(new ScopedTestDialogAutoConfirm(confirm_mode)) {}
199 
200 MockPromptProxy::~MockPromptProxy() = default;
201 
CreatePrompt()202 std::unique_ptr<ExtensionInstallPrompt> MockPromptProxy::CreatePrompt() {
203   return std::unique_ptr<MockInstallPrompt>(
204       new MockInstallPrompt(web_contents_, this));
205 }
206 
CreateMockPromptProxyForBrowserWithConfirmMode(Browser * browser,ScopedTestDialogAutoConfirm::AutoConfirm confirm_mode)207 std::unique_ptr<MockPromptProxy> CreateMockPromptProxyForBrowserWithConfirmMode(
208     Browser* browser,
209     ScopedTestDialogAutoConfirm::AutoConfirm confirm_mode) {
210   return std::make_unique<MockPromptProxy>(
211       browser->tab_strip_model()->GetActiveWebContents(), confirm_mode);
212 }
213 
CreateMockPromptProxyForBrowser(Browser * browser)214 std::unique_ptr<MockPromptProxy> CreateMockPromptProxyForBrowser(
215     Browser* browser) {
216   return CreateMockPromptProxyForBrowserWithConfirmMode(
217       browser, ScopedTestDialogAutoConfirm::ACCEPT);
218 }
219 
220 class ManagementPolicyMock : public extensions::ManagementPolicy::Provider {
221  public:
222   ManagementPolicyMock() = default;
223 
GetDebugPolicyProviderName() const224   std::string GetDebugPolicyProviderName() const override {
225     return "ManagementPolicyMock";
226   }
227 
UserMayLoad(const Extension * extension,base::string16 * error) const228   bool UserMayLoad(const Extension* extension,
229                    base::string16* error) const override {
230     if (error)
231       *error = base::UTF8ToUTF16("Dummy error message");
232     return false;
233   }
234 };
235 
236 }  // namespace
237 
238 class ExtensionCrxInstallerTest : public ExtensionBrowserTest {
239  protected:
GetApproval(const char * manifest_dir,const std::string & id,bool strict_manifest_checks)240   std::unique_ptr<WebstoreInstaller::Approval> GetApproval(
241       const char* manifest_dir,
242       const std::string& id,
243       bool strict_manifest_checks) {
244     std::unique_ptr<WebstoreInstaller::Approval> result;
245 
246     base::ScopedAllowBlockingForTesting allow_io;
247     base::FilePath ext_path = test_data_dir_.AppendASCII(manifest_dir);
248     std::string error;
249     std::unique_ptr<base::DictionaryValue> parsed_manifest(
250         file_util::LoadManifest(ext_path, &error));
251     if (!parsed_manifest.get() || !error.empty())
252       return result;
253 
254     return WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
255         browser()->profile(), id, std::move(parsed_manifest),
256         strict_manifest_checks);
257   }
258 
GetInstalledExtension(const std::string & extension_id)259   const Extension* GetInstalledExtension(const std::string& extension_id) {
260     return extension_registry()->GetInstalledExtension(extension_id);
261   }
262 
UnpackedCrxTempDir()263   std::unique_ptr<base::ScopedTempDir> UnpackedCrxTempDir() {
264     auto temp_dir = std::make_unique<base::ScopedTempDir>();
265     EXPECT_TRUE(temp_dir->CreateUniqueTempDir());
266     EXPECT_TRUE(base::PathExists(temp_dir->GetPath()));
267 
268     base::FilePath unpacked_path =
269         test_data_dir_.AppendASCII("simple_with_popup");
270     EXPECT_TRUE(base::PathExists(unpacked_path));
271     EXPECT_TRUE(base::CopyDirectory(unpacked_path, temp_dir->GetPath(), false));
272 
273     return temp_dir;
274   }
275 
276   // Helper function that creates a file at |relative_path| within |directory|
277   // and fills it with |content|.
AddFileToDirectory(const base::FilePath & directory,const base::FilePath & relative_path,const std::string & content) const278   bool AddFileToDirectory(const base::FilePath& directory,
279                           const base::FilePath& relative_path,
280                           const std::string& content) const {
281     const base::FilePath full_path = directory.Append(relative_path);
282     if (!CreateDirectory(full_path.DirName()))
283       return false;
284     return base::WriteFile(full_path, content);
285   }
286 
AddExtension(const std::string & extension_id,const std::string & version)287   void AddExtension(const std::string& extension_id,
288                     const std::string& version) {
289     base::ScopedTempDir temp_dir;
290     ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
291     ASSERT_TRUE(base::PathExists(temp_dir.GetPath()));
292 
293     base::FilePath foo_js(FILE_PATH_LITERAL("foo.js"));
294     base::FilePath bar_html(FILE_PATH_LITERAL("bar/bar.html"));
295     ASSERT_TRUE(AddFileToDirectory(temp_dir.GetPath(), foo_js, "hello"))
296         << "Failed to write " << temp_dir.GetPath().value() << "/"
297         << foo_js.value();
298     ASSERT_TRUE(AddFileToDirectory(temp_dir.GetPath(), bar_html, "world"));
299 
300     ExtensionBuilder builder;
301     builder.SetManifest(DictionaryBuilder()
302                             .Set("name", "My First Extension")
303                             .Set("version", version)
304                             .Set("manifest_version", 2)
305                             .Build());
306     builder.SetID(extension_id);
307     builder.SetPath(temp_dir.GetPath());
308     ExtensionRegistry::Get(browser()->profile())->AddEnabled(builder.Build());
309 
310     const Extension* extension = GetInstalledExtension(extension_id);
311     ASSERT_NE(nullptr, extension);
312     ASSERT_EQ(version, extension->VersionString());
313   }
314 
InstallerCallback(base::OnceClosure quit_closure,CrxInstaller::InstallerResultCallback callback,const base::Optional<CrxInstallError> & error)315   static void InstallerCallback(base::OnceClosure quit_closure,
316                                 CrxInstaller::InstallerResultCallback callback,
317                                 const base::Optional<CrxInstallError>& error) {
318     if (!callback.is_null())
319       std::move(callback).Run(error);
320     std::move(quit_closure).Run();
321   }
322 
RunCrxInstaller(const WebstoreInstaller::Approval * approval,std::unique_ptr<ExtensionInstallPrompt> prompt,CrxInstaller::InstallerResultCallback callback,const base::FilePath & crx_path)323   void RunCrxInstaller(const WebstoreInstaller::Approval* approval,
324                        std::unique_ptr<ExtensionInstallPrompt> prompt,
325                        CrxInstaller::InstallerResultCallback callback,
326                        const base::FilePath& crx_path) {
327     base::RunLoop run_loop;
328 
329     scoped_refptr<CrxInstaller> installer(
330         CrxInstaller::Create(extension_service(), std::move(prompt), approval));
331     installer->set_allow_silent_install(true);
332     installer->set_is_gallery_install(true);
333     installer->set_installer_callback(
334         base::BindOnce(&ExtensionCrxInstallerTest::InstallerCallback,
335                        run_loop.QuitWhenIdleClosure(), std::move(callback)));
336     installer->InstallCrx(crx_path);
337 
338     run_loop.Run();
339   }
340 
RunCrxInstallerFromUnpackedDirectory(std::unique_ptr<ExtensionInstallPrompt> prompt,CrxInstaller::InstallerResultCallback callback,const std::string & extension_id,const std::string & public_key,const base::FilePath & crx_directory)341   void RunCrxInstallerFromUnpackedDirectory(
342       std::unique_ptr<ExtensionInstallPrompt> prompt,
343       CrxInstaller::InstallerResultCallback callback,
344       const std::string& extension_id,
345       const std::string& public_key,
346       const base::FilePath& crx_directory) {
347     base::RunLoop run_loop;
348 
349     scoped_refptr<CrxInstaller> installer(
350         CrxInstaller::Create(extension_service(), std::move(prompt)));
351     installer->set_allow_silent_install(true);
352     installer->set_is_gallery_install(true);
353     installer->set_installer_callback(
354         base::BindOnce(&ExtensionCrxInstallerTest::InstallerCallback,
355                        run_loop.QuitWhenIdleClosure(), std::move(callback)));
356     installer->set_delete_source(true);
357     installer->InstallUnpackedCrx(extension_id, public_key, crx_directory);
358 
359     run_loop.Run();
360   }
361 
RunUpdateExtension(std::unique_ptr<ExtensionInstallPrompt> prompt,const std::string & extension_id,const std::string & public_key,const base::FilePath & unpacked_dir,CrxInstaller::InstallerResultCallback callback)362   void RunUpdateExtension(std::unique_ptr<ExtensionInstallPrompt> prompt,
363                           const std::string& extension_id,
364                           const std::string& public_key,
365                           const base::FilePath& unpacked_dir,
366                           CrxInstaller::InstallerResultCallback callback) {
367     base::RunLoop run_loop;
368 
369     scoped_refptr<CrxInstaller> installer(
370         CrxInstaller::Create(extension_service(), std::move(prompt)));
371     installer->set_delete_source(true);
372     installer->set_installer_callback(
373         base::BindOnce(&ExtensionCrxInstallerTest::InstallerCallback,
374                        run_loop.QuitWhenIdleClosure(), std::move(callback)));
375     installer->UpdateExtensionFromUnpackedCrx(extension_id, public_key,
376                                               unpacked_dir);
377 
378     run_loop.Run();
379   }
380 
381   // Installs a crx from |crx_relpath| (a path relative to the extension test
382   // data dir) with expected id |id|.
InstallWithPrompt(const char * ext_relpath,const std::string & id,CrxInstaller::InstallerResultCallback callback,MockPromptProxy * mock_install_prompt)383   void InstallWithPrompt(const char* ext_relpath,
384                          const std::string& id,
385                          CrxInstaller::InstallerResultCallback callback,
386                          MockPromptProxy* mock_install_prompt) {
387     base::FilePath ext_path = test_data_dir_.AppendASCII(ext_relpath);
388 
389     std::unique_ptr<WebstoreInstaller::Approval> approval;
390     if (!id.empty())
391       approval = GetApproval(ext_relpath, id, true);
392 
393     base::FilePath crx_path = PackExtension(ext_path);
394     EXPECT_FALSE(crx_path.empty());
395     RunCrxInstaller(approval.get(), mock_install_prompt->CreatePrompt(),
396                     std::move(callback), crx_path);
397 
398     EXPECT_TRUE(mock_install_prompt->did_succeed());
399   }
400 
401   // Installs an extension and checks that it has scopes granted IFF
402   // |record_oauth2_grant| is true.
CheckHasEmptyScopesAfterInstall(const std::string & ext_relpath,CrxInstaller::InstallerResultCallback callback,bool record_oauth2_grant)403   void CheckHasEmptyScopesAfterInstall(
404       const std::string& ext_relpath,
405       CrxInstaller::InstallerResultCallback callback,
406       bool record_oauth2_grant) {
407     std::unique_ptr<MockPromptProxy> mock_prompt =
408         CreateMockPromptProxyForBrowser(browser());
409 
410     InstallWithPrompt("browsertest/scopes", std::string(), std::move(callback),
411                       mock_prompt.get());
412 
413     std::unique_ptr<const PermissionSet> permissions =
414         ExtensionPrefs::Get(browser()->profile())
415             ->GetGrantedPermissions(mock_prompt->extension_id());
416     ASSERT_TRUE(permissions.get());
417   }
418 
InstallWebAppAndVerifyNoErrors()419   void InstallWebAppAndVerifyNoErrors() {
420     scoped_refptr<CrxInstaller> crx_installer(
421         CrxInstaller::CreateSilent(extension_service()));
422     crx_installer->set_error_on_unsupported_requirements(true);
423     crx_installer->InstallWebApp(
424         CreateWebAppInfo(kAppTitle, kAppDescription, kAppUrl, 64, false));
425     EXPECT_TRUE(WaitForCrxInstallerDone());
426     ASSERT_TRUE(crx_installer->extension());
427   }
428 
InstallWebAppWithShortcutsAndVerifyNoErrors()429   void InstallWebAppWithShortcutsAndVerifyNoErrors() {
430     scoped_refptr<CrxInstaller> crx_installer(
431         CrxInstaller::CreateSilent(extension_service()));
432     crx_installer->set_error_on_unsupported_requirements(true);
433     crx_installer->InstallWebApp(
434         CreateWebAppInfo(kAppTitle, kAppDescription, kAppUrl, 64, true));
435     EXPECT_TRUE(WaitForCrxInstallerDone());
436     ASSERT_TRUE(crx_installer->extension());
437   }
438 };
439 
440 class ExtensionCrxInstallerTestWithExperimentalApis
441     : public ExtensionCrxInstallerTest {
442  protected:
SetUpCommandLine(base::CommandLine * command_line)443   void SetUpCommandLine(base::CommandLine* command_line) override {
444     ExtensionCrxInstallerTest::SetUpCommandLine(command_line);
445     command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
446   }
447 };
448 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,ExperimentalExtensionFromGallery)449 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
450                        ExperimentalExtensionFromGallery) {
451   // Gallery-installed extensions should have their experimental permission
452   // preserved, since we allow the Webstore to make that decision.
453   const Extension* extension = InstallExtensionFromWebstore(
454       test_data_dir_.AppendASCII("experimental.crx"), 1);
455   ASSERT_TRUE(extension);
456   EXPECT_TRUE(extension->permissions_data()->HasAPIPermission(
457       APIPermission::kExperimental));
458 }
459 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,ExperimentalExtensionFromOutsideGallery)460 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
461                        ExperimentalExtensionFromOutsideGallery) {
462   // Non-gallery-installed extensions should lose their experimental
463   // permission if the flag isn't enabled.
464   const Extension* extension = InstallExtension(
465       test_data_dir_.AppendASCII("experimental.crx"), 1);
466   ASSERT_TRUE(extension);
467   EXPECT_FALSE(extension->permissions_data()->HasAPIPermission(
468       APIPermission::kExperimental));
469 }
470 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTestWithExperimentalApis,ExperimentalExtensionFromOutsideGalleryWithFlag)471 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTestWithExperimentalApis,
472                        ExperimentalExtensionFromOutsideGalleryWithFlag) {
473   // Non-gallery-installed extensions should maintain their experimental
474   // permission if the flag is enabled.
475   const Extension* extension = InstallExtension(
476       test_data_dir_.AppendASCII("experimental.crx"), 1);
477   ASSERT_TRUE(extension);
478   EXPECT_TRUE(extension->permissions_data()->HasAPIPermission(
479       APIPermission::kExperimental));
480 }
481 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTestWithExperimentalApis,PlatformAppCrx)482 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTestWithExperimentalApis,
483                        PlatformAppCrx) {
484   EXPECT_TRUE(InstallExtension(
485       test_data_dir_.AppendASCII("minimal_platform_app.crx"), 1));
486 }
487 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,BlockedFileTypes)488 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, BlockedFileTypes) {
489   const Extension* extension =
490       InstallExtension(test_data_dir_.AppendASCII("blocked_file_types.crx"), 1);
491   base::ScopedAllowBlockingForTesting allow_io;
492   EXPECT_TRUE(base::PathExists(extension->path().AppendASCII("test.html")));
493   EXPECT_TRUE(base::PathExists(extension->path().AppendASCII("test.nexe")));
494   EXPECT_FALSE(base::PathExists(extension->path().AppendASCII("test1.EXE")));
495   EXPECT_FALSE(base::PathExists(extension->path().AppendASCII("test2.exe")));
496 }
497 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,AllowedThemeFileTypes)498 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, AllowedThemeFileTypes) {
499   const Extension* extension = InstallExtension(
500       test_data_dir_.AppendASCII("theme_with_extension.crx"), 1);
501   ASSERT_TRUE(extension);
502   const base::FilePath& path = extension->path();
503   base::ScopedAllowBlockingForTesting allow_io;
504   EXPECT_TRUE(
505       base::PathExists(path.AppendASCII("images/theme_frame_camo.PNG")));
506   EXPECT_TRUE(
507       base::PathExists(path.AppendASCII("images/theme_ntp_background.png")));
508   EXPECT_TRUE(base::PathExists(
509       path.AppendASCII("images/theme_ntp_background_norepeat.png")));
510   EXPECT_TRUE(
511       base::PathExists(path.AppendASCII("images/theme_toolbar_camo.png")));
512   EXPECT_TRUE(base::PathExists(path.AppendASCII("images/redirect_target.GIF")));
513   EXPECT_TRUE(base::PathExists(path.AppendASCII("test.image.bmp")));
514   EXPECT_TRUE(
515       base::PathExists(path.AppendASCII("test_image_with_no_extension")));
516 
517   EXPECT_FALSE(base::PathExists(path.AppendASCII("non_images/test.html")));
518   EXPECT_FALSE(base::PathExists(path.AppendASCII("non_images/test.nexe")));
519   EXPECT_FALSE(base::PathExists(path.AppendASCII("non_images/test1.EXE")));
520   EXPECT_FALSE(base::PathExists(path.AppendASCII("non_images/test2.exe")));
521   EXPECT_FALSE(base::PathExists(path.AppendASCII("non_images/test.txt")));
522   EXPECT_FALSE(base::PathExists(path.AppendASCII("non_images/test.css")));
523 }
524 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,PackAndInstallExtensionFromDownload)525 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
526                        PackAndInstallExtensionFromDownload) {
527   std::unique_ptr<base::AutoReset<bool>> allow_offstore_install =
528       download_crx_util::OverrideOffstoreInstallAllowedForTesting(true);
529 
530   const int kNumDownloadsExpected = 1;
531 
532   base::FilePath crx_path = PackExtension(
533       test_data_dir_.AppendASCII("common/background_page"));
534   ASSERT_FALSE(crx_path.empty());
535   std::string crx_path_string(crx_path.value().begin(), crx_path.value().end());
536   GURL url = GURL(std::string("file:///").append(crx_path_string));
537 
538   std::unique_ptr<MockPromptProxy> mock_prompt =
539       CreateMockPromptProxyForBrowser(browser());
540   download_crx_util::SetMockInstallPromptForTesting(
541       mock_prompt->CreatePrompt());
542 
543   content::DownloadManager* download_manager =
544       content::BrowserContext::GetDownloadManager(browser()->profile());
545 
546   std::unique_ptr<content::DownloadTestObserver> observer(
547       new content::DownloadTestObserverTerminal(
548           download_manager, kNumDownloadsExpected,
549           content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_ACCEPT));
550   ui_test_utils::NavigateToURLWithDisposition(
551       browser(), url, WindowOpenDisposition::CURRENT_TAB,
552       ui_test_utils::BROWSER_TEST_NONE);
553 
554   EXPECT_TRUE(WaitForCrxInstallerDone());
555   EXPECT_TRUE(mock_prompt->confirmation_requested());
556 }
557 
558 // Tests that scopes are only granted if |record_oauth2_grant_| on the prompt is
559 // true.
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTestWithExperimentalApis,GrantScopes)560 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTestWithExperimentalApis,
561                        GrantScopes) {
562   EXPECT_NO_FATAL_FAILURE(CheckHasEmptyScopesAfterInstall(
563       "browsertest/scopes", CrxInstaller::InstallerResultCallback(), true));
564 }
565 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTestWithExperimentalApis,GrantScopes_WithCallback)566 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTestWithExperimentalApis,
567                        GrantScopes_WithCallback) {
568   EXPECT_NO_FATAL_FAILURE(CheckHasEmptyScopesAfterInstall(
569       "browsertest/scopes",
570       base::BindOnce([](const base::Optional<CrxInstallError>& error) {
571         EXPECT_EQ(base::nullopt, error);
572       }),
573       true));
574 }
575 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTestWithExperimentalApis,DoNotGrantScopes)576 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTestWithExperimentalApis,
577                        DoNotGrantScopes) {
578   EXPECT_NO_FATAL_FAILURE(CheckHasEmptyScopesAfterInstall(
579       "browsertest/scopes", CrxInstaller::InstallerResultCallback(), false));
580 }
581 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTestWithExperimentalApis,DoNotGrantScopes_WithCallback)582 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTestWithExperimentalApis,
583                        DoNotGrantScopes_WithCallback) {
584   EXPECT_NO_FATAL_FAILURE(CheckHasEmptyScopesAfterInstall(
585       "browsertest/scopes",
586       base::BindOnce([](const base::Optional<CrxInstallError>& error) {
587         EXPECT_EQ(base::nullopt, error);
588       }),
589       false));
590 }
591 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,AllowOffStore)592 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, AllowOffStore) {
593   const bool kTestData[] = {false, true};
594 
595   for (size_t i = 0; i < base::size(kTestData); ++i) {
596     std::unique_ptr<MockPromptProxy> mock_prompt =
597         CreateMockPromptProxyForBrowser(browser());
598 
599     scoped_refptr<CrxInstaller> crx_installer(
600         CrxInstaller::Create(extension_service(), mock_prompt->CreatePrompt()));
601     crx_installer->set_install_cause(
602         extension_misc::INSTALL_CAUSE_USER_DOWNLOAD);
603 
604     if (kTestData[i]) {
605       crx_installer->set_off_store_install_allow_reason(
606           CrxInstaller::OffStoreInstallAllowedInTest);
607     }
608 
609     base::RunLoop run_loop;
610     crx_installer->set_installer_callback(
611         base::BindOnce(&ExtensionCrxInstallerTest::InstallerCallback,
612                        run_loop.QuitWhenIdleClosure(),
613                        CrxInstaller::InstallerResultCallback()));
614     crx_installer->InstallCrx(test_data_dir_.AppendASCII("good.crx"));
615     // The |mock_prompt| will quit running the loop once the |crx_installer|
616     // is done.
617     run_loop.Run();
618     EXPECT_EQ(kTestData[i], mock_prompt->did_succeed());
619     EXPECT_EQ(kTestData[i], mock_prompt->confirmation_requested()) <<
620         kTestData[i];
621     if (kTestData[i]) {
622       EXPECT_EQ(base::string16(), mock_prompt->error()) << kTestData[i];
623     } else {
624       EXPECT_EQ(l10n_util::GetStringUTF16(
625           IDS_EXTENSION_INSTALL_DISALLOWED_ON_SITE),
626           mock_prompt->error()) << kTestData[i];
627     }
628   }
629 }
630 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,HiDpiThemeTest)631 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, HiDpiThemeTest) {
632   base::FilePath crx_path = test_data_dir_.AppendASCII("theme_hidpi_crx");
633   crx_path = crx_path.AppendASCII("theme_hidpi.crx");
634 
635   ASSERT_TRUE(InstallExtension(crx_path, 1));
636 
637   const std::string extension_id("gllekhaobjnhgeagipipnkpmmmpchacm");
638   ExtensionRegistry* registry = ExtensionRegistry::Get(
639       browser()->profile());
640   const extensions::Extension* extension =
641      registry->enabled_extensions().GetByID(extension_id);
642   ASSERT_TRUE(extension);
643   EXPECT_EQ(extension_id, extension->id());
644 
645   UninstallExtension(extension_id);
646   EXPECT_FALSE(registry->enabled_extensions().GetByID(extension_id));
647 }
648 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,InstallDelayedUntilNextUpdate)649 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
650                        InstallDelayedUntilNextUpdate) {
651   const std::string extension_id("ldnnhddmnhbkjipkidpdiheffobcpfmf");
652   base::FilePath base_path = test_data_dir_.AppendASCII("delayed_install");
653 
654   ExtensionService* service = extension_service();
655   ASSERT_TRUE(service);
656   ExtensionRegistry* registry = ExtensionRegistry::Get(
657       browser()->profile());
658   ASSERT_TRUE(registry);
659 
660   // Install version 1 of the test extension. This extension does not have
661   // a background page but does have a browser action.
662   base::FilePath v1_path = PackExtension(base_path.AppendASCII("v1"));
663   ASSERT_FALSE(v1_path.empty());
664   ASSERT_TRUE(InstallExtension(v1_path, 1));
665   const extensions::Extension* extension =
666      registry->enabled_extensions().GetByID(extension_id);
667   ASSERT_TRUE(extension);
668   ASSERT_EQ(extension_id, extension->id());
669   ASSERT_EQ("1.0", extension->version().GetString());
670 
671   // Make test extension non-idle by opening the extension's options page.
672   ExtensionTabUtil::OpenOptionsPage(extension, browser());
673   WaitForExtensionNotIdle(extension_id);
674 
675   // Install version 2 of the extension and check that it is indeed delayed.
676   base::FilePath v2_path = PackExtension(base_path.AppendASCII("v2"));
677   ASSERT_FALSE(v2_path.empty());
678   ASSERT_TRUE(UpdateExtensionWaitForIdle(extension_id, v2_path, 0));
679 
680   ASSERT_EQ(1u, service->delayed_installs()->size());
681   extension = registry->enabled_extensions().GetByID(extension_id);
682   ASSERT_EQ("1.0", extension->version().GetString());
683 
684   // Make the extension idle again by navigating away from the options page.
685   // This should not trigger the delayed install.
686   ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
687   WaitForExtensionIdle(extension_id);
688   ASSERT_EQ(1u, service->delayed_installs()->size());
689   extension = registry->enabled_extensions().GetByID(extension_id);
690   ASSERT_EQ("1.0", extension->version().GetString());
691 
692   // Install version 3 of the extension. Because the extension is idle,
693   // this install should succeed.
694   base::FilePath v3_path = PackExtension(base_path.AppendASCII("v3"));
695   ASSERT_FALSE(v3_path.empty());
696   ASSERT_TRUE(UpdateExtensionWaitForIdle(extension_id, v3_path, 0));
697   extension = registry->enabled_extensions().GetByID(extension_id);
698   ASSERT_EQ("3.0", extension->version().GetString());
699 
700   // The version 2 delayed install should be cleaned up, and finishing
701   // delayed extension installation shouldn't break anything.
702   ASSERT_EQ(0u, service->delayed_installs()->size());
703   service->MaybeFinishDelayedInstallations();
704   extension = registry->enabled_extensions().GetByID(extension_id);
705   ASSERT_EQ("3.0", extension->version().GetString());
706 }
707 
708 #if BUILDFLAG(FULL_SAFE_BROWSING)
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,Blocklist)709 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, Blocklist) {
710   scoped_refptr<FakeSafeBrowsingDatabaseManager> blocklist_db(
711       new FakeSafeBrowsingDatabaseManager(true));
712   Blocklist::ScopedDatabaseManagerForTest scoped_blocklist_db(blocklist_db);
713 
714   const std::string extension_id = "gllekhaobjnhgeagipipnkpmmmpchacm";
715   blocklist_db->SetUnsafe(extension_id);
716 
717   base::FilePath crx_path = test_data_dir_.AppendASCII("theme_hidpi_crx")
718                                           .AppendASCII("theme_hidpi.crx");
719   EXPECT_FALSE(InstallExtension(crx_path, 0));
720 
721   auto installation_failure =
722       InstallStageTracker::Get(profile())->Get(extension_id);
723   EXPECT_EQ(InstallStageTracker::FailureReason::CRX_INSTALL_ERROR_DECLINED,
724             installation_failure.failure_reason);
725   EXPECT_EQ(CrxInstallErrorDetail::EXTENSION_IS_BLOCKLISTED,
726             installation_failure.install_error_detail);
727 }
728 #endif
729 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,NonStrictManifestCheck)730 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, NonStrictManifestCheck) {
731   std::unique_ptr<MockPromptProxy> mock_prompt =
732       CreateMockPromptProxyForBrowser(browser());
733 
734   // We want to simulate the case where the webstore sends a more recent
735   // version of the manifest, but the downloaded .crx file is old since
736   // the newly published version hasn't fully propagated to all the download
737   // servers yet. So load the v2 manifest, but then install the v1 crx file.
738   std::string id = "ooklpoaelmiimcjipecogjfcejghbogp";
739   std::unique_ptr<WebstoreInstaller::Approval> approval =
740       GetApproval("crx_installer/v2_no_permission_change/", id, false);
741 
742   RunCrxInstaller(approval.get(), mock_prompt->CreatePrompt(),
743                   CrxInstaller::InstallerResultCallback(),
744                   test_data_dir_.AppendASCII("crx_installer/v1.crx"));
745 
746   EXPECT_TRUE(mock_prompt->did_succeed());
747 }
748 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,NonStrictManifestCheck_WithCallback)749 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
750                        NonStrictManifestCheck_WithCallback) {
751   std::unique_ptr<MockPromptProxy> mock_prompt =
752       CreateMockPromptProxyForBrowser(browser());
753 
754   // We want to simulate the case where the webstore sends a more recent
755   // version of the manifest, but the downloaded .crx file is old since
756   // the newly published version hasn't fully propagated to all the download
757   // servers yet. So load the v2 manifest, but then install the v1 crx file.
758   const std::string id = "ooklpoaelmiimcjipecogjfcejghbogp";
759   std::unique_ptr<WebstoreInstaller::Approval> approval =
760       GetApproval("crx_installer/v2_no_permission_change/", id, false);
761 
762   RunCrxInstaller(
763       approval.get(), mock_prompt->CreatePrompt(),
764       base::BindOnce([](const base::Optional<CrxInstallError>& error) {
765         EXPECT_EQ(base::nullopt, error);
766       }),
767       test_data_dir_.AppendASCII("crx_installer/v1.crx"));
768 
769   EXPECT_TRUE(mock_prompt->did_succeed());
770 }
771 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,InstallUnpackedCrx_FolderDoesNotExist)772 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
773                        InstallUnpackedCrx_FolderDoesNotExist) {
774   base::ScopedAllowBlockingForTesting allow_io;
775   std::unique_ptr<MockPromptProxy> mock_prompt =
776       CreateMockPromptProxyForBrowser(browser());
777 
778   base::ScopedTempDir temp_dir;
779   EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
780 
781   const base::FilePath folder = temp_dir.GetPath().AppendASCII("abcdef");
782   EXPECT_FALSE(base::PathExists(folder));
783 
784   const std::string public_key = "123456";
785   RunCrxInstallerFromUnpackedDirectory(
786       mock_prompt->CreatePrompt(),
787       base::BindOnce([](const base::Optional<CrxInstallError>& error) {
788         ASSERT_NE(base::nullopt, error);
789         ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE,
790                   error->type());
791         EXPECT_EQ(SandboxedUnpackerFailureReason::DIRECTORY_MOVE_FAILED,
792                   error->sandbox_failure_detail());
793       }),
794       std::string(), public_key, folder);
795 
796   EXPECT_FALSE(mock_prompt->did_succeed());
797 }
798 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,InstallUnpackedCrx_EmptyFolder)799 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
800                        InstallUnpackedCrx_EmptyFolder) {
801   base::ScopedAllowBlockingForTesting allow_io;
802   std::unique_ptr<MockPromptProxy> mock_prompt =
803       CreateMockPromptProxyForBrowser(browser());
804 
805   base::ScopedTempDir temp_dir;
806   EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
807   EXPECT_TRUE(base::PathExists(temp_dir.GetPath()));
808 
809   const std::string public_key = "123456";
810   RunCrxInstallerFromUnpackedDirectory(
811       mock_prompt->CreatePrompt(),
812       base::BindOnce([](const base::Optional<CrxInstallError>& error) {
813         ASSERT_NE(base::nullopt, error);
814         ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE,
815                   error->type());
816         EXPECT_EQ(SandboxedUnpackerFailureReason::UNPACKER_CLIENT_FAILED,
817                   error->sandbox_failure_detail());
818       }),
819       std::string(), public_key, temp_dir.GetPath());
820 
821   EXPECT_FALSE(mock_prompt->did_succeed());
822   EXPECT_FALSE(base::PathExists(temp_dir.GetPath()));
823 }
824 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,InstallUnpackedCrx_InvalidPublicKey)825 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
826                        InstallUnpackedCrx_InvalidPublicKey) {
827   base::ScopedAllowBlockingForTesting allow_io;
828   std::unique_ptr<MockPromptProxy> mock_prompt =
829       CreateMockPromptProxyForBrowser(browser());
830 
831   base::ScopedTempDir temp_dir;
832   EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
833   EXPECT_TRUE(base::PathExists(temp_dir.GetPath()));
834 
835   const base::FilePath unpacked_path =
836       test_data_dir_.AppendASCII("simple_with_popup");
837   EXPECT_TRUE(base::PathExists(unpacked_path));
838   EXPECT_TRUE(base::CopyDirectory(unpacked_path, temp_dir.GetPath(), false));
839 
840   const std::string public_key = "123456";
841   RunCrxInstallerFromUnpackedDirectory(
842       mock_prompt->CreatePrompt(),
843       base::BindOnce([](const base::Optional<CrxInstallError>& error) {
844         ASSERT_NE(base::nullopt, error);
845         ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE,
846                   error->type());
847         EXPECT_EQ(SandboxedUnpackerFailureReason::INVALID_MANIFEST,
848                   error->sandbox_failure_detail());
849       }),
850       std::string(), public_key, temp_dir.GetPath());
851 
852   EXPECT_FALSE(mock_prompt->did_succeed());
853   EXPECT_FALSE(base::PathExists(temp_dir.GetPath()));
854 }
855 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,InstallUnpackedCrx_Success)856 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, InstallUnpackedCrx_Success) {
857   base::ScopedAllowBlockingForTesting allow_io;
858   std::unique_ptr<MockPromptProxy> mock_prompt =
859       CreateMockPromptProxyForBrowser(browser());
860 
861   base::ScopedTempDir temp_dir;
862   EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
863   EXPECT_TRUE(base::PathExists(temp_dir.GetPath()));
864 
865   const base::FilePath unpacked_path =
866       test_data_dir_.AppendASCII("simple_with_popup");
867   EXPECT_TRUE(base::PathExists(unpacked_path));
868   EXPECT_TRUE(base::CopyDirectory(unpacked_path, temp_dir.GetPath(), false));
869 
870   const std::string public_key =
871       "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8c4fBSPZ6utYoZ8NiWF/"
872       "DSaimBhihjwgOsskyleFGaurhi3TDClTVSGPxNkgCzrz0wACML7M4aNjpd05qupdbR2d294j"
873       "kDuI7caxEGUucpP7GJRRHnm8Sx+"
874       "y0ury28n8jbN0PnInKKWcxpIXXmNQyC19HBuO3QIeUq9Dqc+7YFQIDAQAB";
875   RunCrxInstallerFromUnpackedDirectory(
876       mock_prompt->CreatePrompt(),
877       base::BindOnce([](const base::Optional<CrxInstallError>& error) {
878         EXPECT_EQ(base::nullopt, error);
879       }),
880       std::string(), public_key, temp_dir.GetPath());
881 
882   EXPECT_TRUE(mock_prompt->did_succeed());
883   EXPECT_FALSE(base::PathExists(temp_dir.GetPath()));
884 }
885 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,UpdateExtensionFromUnpackedCrx_NewExtension)886 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
887                        UpdateExtensionFromUnpackedCrx_NewExtension) {
888   base::ScopedAllowBlockingForTesting allow_io;
889   std::unique_ptr<MockPromptProxy> mock_prompt =
890       CreateMockPromptProxyForBrowser(browser());
891 
892   // Update won't work as the extension doesn't exist.
893   const std::string extension_id = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
894   const std::string public_key =
895       "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8c4fBSPZ6utYoZ8NiWF/"
896       "DSaimBhihjwgOsskyleFGaurhi3TDClTVSGPxNkgCzrz0wACML7M4aNjpd05qupdbR2d294j"
897       "kDuI7caxEGUucpP7GJRRHnm8Sx+"
898       "y0ury28n8jbN0PnInKKWcxpIXXmNQyC19HBuO3QIeUq9Dqc+7YFQIDAQAB";
899   ASSERT_EQ(nullptr, GetInstalledExtension(extension_id));
900   auto temp_dir = UnpackedCrxTempDir();
901   RunUpdateExtension(
902       mock_prompt->CreatePrompt(), extension_id, public_key,
903       temp_dir->GetPath(),
904       base::BindOnce([](const base::Optional<CrxInstallError>& error) {
905         ASSERT_NE(base::nullopt, error);
906         EXPECT_EQ(CrxInstallErrorType::OTHER, error->type());
907         EXPECT_EQ(CrxInstallErrorDetail::UPDATE_NON_EXISTING_EXTENSION,
908                   error->detail());
909       }));
910 
911   // The unpacked folder should be deleted.
912   EXPECT_FALSE(mock_prompt->did_succeed());
913   EXPECT_FALSE(base::PathExists(temp_dir->GetPath()));
914   EXPECT_EQ(nullptr, GetInstalledExtension(extension_id));
915 }
916 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,UpdateExtensionFromUnpackedCrx_UpdateExistingExtension)917 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
918                        UpdateExtensionFromUnpackedCrx_UpdateExistingExtension) {
919   base::ScopedAllowBlockingForTesting allow_io;
920   std::unique_ptr<MockPromptProxy> mock_prompt =
921       CreateMockPromptProxyForBrowser(browser());
922 
923   const std::string extension_id = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
924   const std::string public_key =
925       "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8c4fBSPZ6utYoZ8NiWF/"
926       "DSaimBhihjwgOsskyleFGaurhi3TDClTVSGPxNkgCzrz0wACML7M4aNjpd05qupdbR2d294j"
927       "kDuI7caxEGUucpP7GJRRHnm8Sx+"
928       "y0ury28n8jbN0PnInKKWcxpIXXmNQyC19HBuO3QIeUq9Dqc+7YFQIDAQAB";
929 
930   // Test updating an existing extension.
931   AddExtension(extension_id, "0.0");
932 
933   auto temp_dir = UnpackedCrxTempDir();
934   RunUpdateExtension(
935       mock_prompt->CreatePrompt(), extension_id, public_key,
936       temp_dir->GetPath(),
937       base::BindOnce([](const base::Optional<CrxInstallError>& error) {
938         EXPECT_EQ(base::nullopt, error);
939       }));
940 
941   EXPECT_TRUE(mock_prompt->did_succeed());
942 
943   // The unpacked folder should be deleted.
944   EXPECT_FALSE(base::PathExists(temp_dir->GetPath()));
945 
946   const Extension* extension = GetInstalledExtension(extension_id);
947   ASSERT_NE(nullptr, extension);
948   EXPECT_EQ("1.0", extension->VersionString());
949 }
950 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,UpdateExtensionFromUnpackedCrx_InvalidPublicKey)951 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
952                        UpdateExtensionFromUnpackedCrx_InvalidPublicKey) {
953   base::ScopedAllowBlockingForTesting allow_io;
954   std::unique_ptr<MockPromptProxy> mock_prompt =
955       CreateMockPromptProxyForBrowser(browser());
956 
957   const std::string extension_id = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
958   const std::string public_key = "invalid public key";
959 
960   // Test updating an existing extension.
961   AddExtension(extension_id, "0.0");
962 
963   auto temp_dir = UnpackedCrxTempDir();
964   RunUpdateExtension(
965       mock_prompt->CreatePrompt(), extension_id, public_key,
966       temp_dir->GetPath(),
967       base::BindOnce([](const base::Optional<CrxInstallError>& error) {
968         ASSERT_NE(base::nullopt, error);
969         ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE,
970                   error->type());
971         EXPECT_EQ(SandboxedUnpackerFailureReason::INVALID_MANIFEST,
972                   error->sandbox_failure_detail());
973       }));
974 
975   EXPECT_FALSE(mock_prompt->did_succeed());
976 
977   // The unpacked folder should be deleted.
978   EXPECT_FALSE(base::PathExists(temp_dir->GetPath()));
979 
980   const Extension* extension = GetInstalledExtension(extension_id);
981   ASSERT_NE(nullptr, extension);
982   EXPECT_EQ("0.0", extension->VersionString());
983 
984   auto installation_failure =
985       InstallStageTracker::Get(profile())->Get(extension_id);
986   EXPECT_EQ(InstallStageTracker::FailureReason::
987                 CRX_INSTALL_ERROR_SANDBOXED_UNPACKER_FAILURE,
988             installation_failure.failure_reason);
989   EXPECT_EQ(base::nullopt, installation_failure.install_error_detail);
990 }
991 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,UpdateExtensionFromUnpackedCrx_WrongPublicKey)992 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
993                        UpdateExtensionFromUnpackedCrx_WrongPublicKey) {
994   base::ScopedAllowBlockingForTesting allow_io;
995   std::unique_ptr<MockPromptProxy> mock_prompt =
996       CreateMockPromptProxyForBrowser(browser());
997 
998   const std::string extension_id = "gllekhaobjnhgeagipipnkpmmmpchacm";
999   const std::string public_key =
1000       "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8c4fBSPZ6utYoZ8NiWF/"
1001       "DSaimBhihjwgOsskyleFGaurhi3TDClTVSGPxNkgCzrz0wACML7M4aNjpd05qupdbR2d294j"
1002       "kDuI7caxEGUucpP7GJRRHnm8Sx+"
1003       "y0ury28n8jbN0PnInKKWcxpIXXmNQyC19HBuO3QIeUq9Dqc+7YFQIDAQAB";
1004 
1005   // Test updating an existing extension.
1006   AddExtension(extension_id, "0.0");
1007 
1008   auto temp_dir = UnpackedCrxTempDir();
1009   RunUpdateExtension(
1010       mock_prompt->CreatePrompt(), extension_id, public_key,
1011       temp_dir->GetPath(),
1012       base::BindOnce([](const base::Optional<CrxInstallError>& error) {
1013         ASSERT_NE(base::nullopt, error);
1014         EXPECT_EQ(CrxInstallErrorType::OTHER, error->type());
1015         EXPECT_EQ(CrxInstallErrorDetail::UNEXPECTED_ID, error->detail());
1016       }));
1017 
1018   EXPECT_FALSE(mock_prompt->did_succeed());
1019 
1020   // The unpacked folder should be deleted.
1021   EXPECT_FALSE(base::PathExists(temp_dir->GetPath()));
1022 
1023   const Extension* extension = GetInstalledExtension(extension_id);
1024   ASSERT_NE(nullptr, extension);
1025   EXPECT_EQ("0.0", extension->VersionString());
1026 
1027   auto installation_failure =
1028       InstallStageTracker::Get(profile())->Get(extension_id);
1029   EXPECT_EQ(InstallStageTracker::FailureReason::CRX_INSTALL_ERROR_OTHER,
1030             installation_failure.failure_reason);
1031   EXPECT_EQ(CrxInstallErrorDetail::UNEXPECTED_ID,
1032             *installation_failure.install_error_detail);
1033 }
1034 
1035 #if defined(OS_CHROMEOS)
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,KioskOnlyTest)1036 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, KioskOnlyTest) {
1037   base::ScopedAllowBlockingForTesting allow_io;
1038   // kiosk_only is allowlisted from non-chromeos.
1039   base::FilePath crx_path =
1040       test_data_dir_.AppendASCII("kiosk/kiosk_only.crx");
1041   EXPECT_FALSE(InstallExtension(crx_path, 0));
1042   // Simulate ChromeOS kiosk mode. |scoped_user_manager| will take over
1043   // lifetime of |user_manager|.
1044   chromeos::FakeChromeUserManager* fake_user_manager =
1045       new chromeos::FakeChromeUserManager();
1046   const AccountId account_id(AccountId::FromUserEmail("example@example.com"));
1047   fake_user_manager->AddKioskAppUser(account_id);
1048   fake_user_manager->LoginUser(account_id);
1049   user_manager::ScopedUserManager scoped_user_manager(
1050       base::WrapUnique(fake_user_manager));
1051   EXPECT_TRUE(InstallExtension(crx_path, 1));
1052 }
1053 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,InstallToSharedLocation)1054 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, InstallToSharedLocation) {
1055   base::ScopedAllowBlockingForTesting allow_io;
1056   base::CommandLine::ForCurrentProcess()->AppendSwitch(
1057       chromeos::switches::kEnableExtensionAssetsSharing);
1058   base::ScopedTempDir cache_dir;
1059   ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
1060   ExtensionAssetsManagerChromeOS::SetSharedInstallDirForTesting(
1061       cache_dir.GetPath());
1062 
1063   base::FilePath crx_path = test_data_dir_.AppendASCII("crx_installer/v1.crx");
1064   const extensions::Extension* extension = InstallExtension(
1065       crx_path, 1, extensions::Manifest::EXTERNAL_PREF);
1066   base::FilePath extension_path = extension->path();
1067   EXPECT_TRUE(cache_dir.GetPath().IsParent(extension_path));
1068   EXPECT_TRUE(base::PathExists(extension_path));
1069 
1070   std::string extension_id = extension->id();
1071   UninstallExtension(extension_id);
1072   ExtensionRegistry* registry = ExtensionRegistry::Get(
1073       browser()->profile());
1074   EXPECT_FALSE(registry->enabled_extensions().GetByID(extension_id));
1075 
1076   content::RunAllTasksUntilIdle();
1077 
1078   EXPECT_FALSE(base::PathExists(extension_path));
1079 }
1080 #endif
1081 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,DoNotSync)1082 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, DoNotSync) {
1083   scoped_refptr<CrxInstaller> crx_installer(
1084       CrxInstaller::CreateSilent(extension_service()));
1085   crx_installer->set_do_not_sync(true);
1086   crx_installer->InstallCrx(test_data_dir_.AppendASCII("good.crx"));
1087   EXPECT_TRUE(WaitForCrxInstallerDone());
1088   ASSERT_TRUE(crx_installer->extension());
1089 
1090   const ExtensionPrefs* extension_prefs =
1091       ExtensionPrefs::Get(browser()->profile());
1092   EXPECT_TRUE(extension_prefs->DoNotSync(crx_installer->extension()->id()));
1093   EXPECT_FALSE(extensions::util::ShouldSync(crx_installer->extension(),
1094                                             browser()->profile()));
1095 }
1096 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,ManagementPolicy)1097 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, ManagementPolicy) {
1098   ManagementPolicyMock policy;
1099   extensions::ExtensionSystem::Get(profile())
1100       ->management_policy()
1101       ->RegisterProvider(&policy);
1102 
1103   base::FilePath crx_path = test_data_dir_.AppendASCII("crx_installer/v1.crx");
1104   EXPECT_FALSE(InstallExtension(crx_path, 0));
1105 }
1106 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,InstallWebApp)1107 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, InstallWebApp) {
1108   InstallWebAppAndVerifyNoErrors();
1109 }
1110 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,InstallWebAppWithShortcuts)1111 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, InstallWebAppWithShortcuts) {
1112   InstallWebAppWithShortcutsAndVerifyNoErrors();
1113 }
1114 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,InstallWebAppSucceedsWithBlockPolicy)1115 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
1116                        InstallWebAppSucceedsWithBlockPolicy) {
1117   // Verify that the install still works when a management policy blocking
1118   // extension installation is in force. Bookmark apps are special-cased to skip
1119   // these checks (see https://crbug.com/545541).
1120   ManagementPolicyMock policy;
1121   extensions::ExtensionSystem::Get(profile())
1122       ->management_policy()
1123       ->RegisterProvider(&policy);
1124 
1125   InstallWebAppAndVerifyNoErrors();
1126 }
1127 
IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,UpdateWithFileAccess)1128 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, UpdateWithFileAccess) {
1129   base::FilePath ext_source =
1130       test_data_dir_.AppendASCII("permissions").AppendASCII("files");
1131   base::FilePath crx_with_file_permission = PackExtension(ext_source);
1132   ASSERT_FALSE(crx_with_file_permission.empty());
1133 
1134   ExtensionService* service = extension_service();
1135 
1136   const std::string extension_id("bdkapipdccfifhdghmblnenbbncfcpid");
1137   {
1138     // Install extension.
1139     scoped_refptr<CrxInstaller> installer(CrxInstaller::CreateSilent(service));
1140     installer->InstallCrx(crx_with_file_permission);
1141     EXPECT_TRUE(WaitForCrxInstallerDone());
1142     const Extension* extension = installer->extension();
1143     ASSERT_TRUE(extension);
1144     // IDs must match, otherwise the test doesn't make any sense.
1145     ASSERT_EQ(extension_id, extension->id());
1146     // Sanity check: File access should be disabled by default.
1147     EXPECT_FALSE(ExtensionPrefs::Get(profile())->AllowFileAccess(extension_id));
1148     EXPECT_FALSE(extension->creation_flags() & Extension::ALLOW_FILE_ACCESS);
1149   }
1150 
1151   {
1152     // Uninstall and re-install the extension. Any previously granted file
1153     // permissions should be gone.
1154     ExtensionPrefs::Get(profile())->SetAllowFileAccess(extension_id, true);
1155     EXPECT_TRUE(ExtensionPrefs::Get(profile())->AllowFileAccess(extension_id));
1156     UninstallExtension(extension_id);
1157     EXPECT_FALSE(ExtensionPrefs::Get(profile())->AllowFileAccess(extension_id));
1158 
1159     scoped_refptr<CrxInstaller> installer(CrxInstaller::CreateSilent(service));
1160     installer->InstallCrx(crx_with_file_permission);
1161     EXPECT_TRUE(WaitForCrxInstallerDone());
1162     const Extension* extension = installer->extension();
1163     ASSERT_TRUE(extension);
1164     ASSERT_EQ(extension_id, extension->id());
1165     EXPECT_FALSE(ExtensionPrefs::Get(profile())->AllowFileAccess(extension_id));
1166     EXPECT_FALSE(extension->creation_flags() & Extension::ALLOW_FILE_ACCESS);
1167   }
1168 
1169   {
1170     // Grant file access and update the extension. File access should be kept.
1171     ExtensionPrefs::Get(profile())->SetAllowFileAccess(extension_id, true);
1172     EXPECT_TRUE(ExtensionPrefs::Get(profile())->AllowFileAccess(extension_id));
1173     base::FilePath crx_update_with_file_permission = PackExtension(ext_source);
1174 
1175     scoped_refptr<CrxInstaller> installer(CrxInstaller::CreateSilent(service));
1176     installer->InstallCrx(crx_update_with_file_permission);
1177     EXPECT_TRUE(WaitForCrxInstallerDone());
1178     const Extension* extension = installer->extension();
1179     ASSERT_TRUE(extension);
1180     ASSERT_EQ(extension_id, extension->id());
1181     EXPECT_TRUE(ExtensionPrefs::Get(profile())->AllowFileAccess(extension_id));
1182     EXPECT_TRUE(extension->creation_flags() & Extension::ALLOW_FILE_ACCESS);
1183   }
1184 }
1185 
1186 class ExtensionCrxInstallerTestWithWithholdingUI
1187     : public ExtensionCrxInstallerTest,
1188       public testing::WithParamInterface<bool> {
1189  public:
ExtensionCrxInstallerTestWithWithholdingUI()1190   ExtensionCrxInstallerTestWithWithholdingUI() {
1191     feature_list_.InitAndEnableFeature(
1192         extensions_features::kAllowWithholdingExtensionPermissionsOnInstall);
1193   }
1194 
1195  private:
1196   base::test::ScopedFeatureList feature_list_;
1197 };
1198 
IN_PROC_BROWSER_TEST_P(ExtensionCrxInstallerTestWithWithholdingUI,WithholdingHostsOnInstall)1199 IN_PROC_BROWSER_TEST_P(ExtensionCrxInstallerTestWithWithholdingUI,
1200                        WithholdingHostsOnInstall) {
1201   bool should_check_box = GetParam();
1202   ScopedTestDialogAutoConfirm::AutoConfirm mode =
1203       should_check_box ? ScopedTestDialogAutoConfirm::ACCEPT_AND_OPTION
1204                        : ScopedTestDialogAutoConfirm::ACCEPT;
1205   std::unique_ptr<MockPromptProxy> mock_prompt =
1206       CreateMockPromptProxyForBrowserWithConfirmMode(browser(), mode);
1207 
1208   scoped_refptr<CrxInstaller> crx_installer(
1209       CrxInstaller::Create(extension_service(), mock_prompt->CreatePrompt()));
1210 
1211   // Install a simple extension with google.com as a permission.
1212   base::RunLoop run_loop;
1213   crx_installer->set_installer_callback(base::BindOnce(
1214       &ExtensionCrxInstallerTest::InstallerCallback,
1215       run_loop.QuitWhenIdleClosure(), CrxInstaller::InstallerResultCallback()));
1216   base::FilePath crx_with_host =
1217       PackExtension(test_data_dir_.AppendASCII("simple_with_host"));
1218   crx_installer->InstallCrx(crx_with_host);
1219   run_loop.Run();
1220 
1221   EXPECT_TRUE(mock_prompt->did_succeed());
1222   EXPECT_TRUE(mock_prompt->confirmation_requested());
1223 
1224   // Access to google.com should be withheld only when the box was checked.
1225   const Extension* extension =
1226       GetInstalledExtension(mock_prompt->extension_id());
1227   ScriptingPermissionsModifier modifier(browser()->profile(), extension);
1228   EXPECT_EQ(should_check_box, modifier.HasWithheldHostPermissions());
1229   const ScriptingPermissionsModifier::SiteAccess site_access =
1230       modifier.GetSiteAccess(GURL("https://google.com"));
1231   EXPECT_EQ(should_check_box, site_access.withheld_site_access);
1232   EXPECT_EQ(!should_check_box, site_access.has_site_access);
1233 }
1234 
1235 INSTANTIATE_TEST_SUITE_P(All,
1236                          ExtensionCrxInstallerTestWithWithholdingUI,
1237                          testing::Bool());
1238 
1239 }  // namespace extensions
1240