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