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 <map>
8 #include <set>
9 #include <utility>
10 
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/files/file_util.h"
14 #include "base/files/scoped_temp_dir.h"
15 #include "base/lazy_instance.h"
16 #include "base/macros.h"
17 #include "base/metrics/histogram_macros.h"
18 #include "base/sequenced_task_runner.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/threading/thread_restrictions.h"
22 #include "base/time/time.h"
23 #include "base/version.h"
24 #include "build/build_config.h"
25 #include "chrome/browser/extensions/blocklist_check.h"
26 #include "chrome/browser/extensions/convert_user_script.h"
27 #include "chrome/browser/extensions/convert_web_app.h"
28 #include "chrome/browser/extensions/extension_assets_manager.h"
29 #include "chrome/browser/extensions/extension_service.h"
30 #include "chrome/browser/extensions/forced_extensions/install_stage_tracker.h"
31 #include "chrome/browser/extensions/install_tracker.h"
32 #include "chrome/browser/extensions/install_tracker_factory.h"
33 #include "chrome/browser/extensions/load_error_reporter.h"
34 #include "chrome/browser/extensions/permissions_updater.h"
35 #include "chrome/browser/extensions/webstore_installer.h"
36 #include "chrome/browser/profiles/profile.h"
37 #include "chrome/browser/web_applications/components/web_application_info.h"
38 #include "chrome/common/chrome_paths.h"
39 #include "chrome/common/chrome_switches.h"
40 #include "chrome/common/extensions/extension_constants.h"
41 #include "chrome/grit/generated_resources.h"
42 #include "components/crx_file/crx_verifier.h"
43 #include "content/public/browser/browser_task_traits.h"
44 #include "content/public/browser/browser_thread.h"
45 #include "content/public/browser/notification_service.h"
46 #include "extensions/browser/content_verifier.h"
47 #include "extensions/browser/extension_file_task_runner.h"
48 #include "extensions/browser/extension_prefs.h"
49 #include "extensions/browser/extension_registry.h"
50 #include "extensions/browser/extension_system.h"
51 #include "extensions/browser/install/crx_install_error.h"
52 #include "extensions/browser/install/extension_install_ui.h"
53 #include "extensions/browser/install_flag.h"
54 #include "extensions/browser/install_stage.h"
55 #include "extensions/browser/notification_types.h"
56 #include "extensions/browser/policy_check.h"
57 #include "extensions/browser/preload_check_group.h"
58 #include "extensions/browser/requirements_checker.h"
59 #include "extensions/common/extension_icon_set.h"
60 #include "extensions/common/file_util.h"
61 #include "extensions/common/manifest.h"
62 #include "extensions/common/manifest_handlers/kiosk_mode_info.h"
63 #include "extensions/common/manifest_handlers/shared_module_info.h"
64 #include "extensions/common/manifest_url_handlers.h"
65 #include "extensions/common/permissions/permission_message_provider.h"
66 #include "extensions/common/permissions/permission_set.h"
67 #include "extensions/common/permissions/permissions_data.h"
68 #include "extensions/common/user_script.h"
69 #include "extensions/common/verifier_formats.h"
70 #include "extensions/strings/grit/extensions_strings.h"
71 #include "third_party/skia/include/core/SkBitmap.h"
72 #include "ui/base/l10n/l10n_util.h"
73 
74 #if defined(OS_CHROMEOS)
75 #include "components/user_manager/user_manager.h"
76 #endif
77 
78 using content::BrowserThread;
79 
80 namespace extensions {
81 
82 // static
CreateSilent(ExtensionService * frontend)83 scoped_refptr<CrxInstaller> CrxInstaller::CreateSilent(
84     ExtensionService* frontend) {
85   return new CrxInstaller(frontend->AsWeakPtr(),
86                           std::unique_ptr<ExtensionInstallPrompt>(), NULL);
87 }
88 
89 // static
Create(ExtensionService * frontend,std::unique_ptr<ExtensionInstallPrompt> client)90 scoped_refptr<CrxInstaller> CrxInstaller::Create(
91     ExtensionService* frontend,
92     std::unique_ptr<ExtensionInstallPrompt> client) {
93   return new CrxInstaller(frontend->AsWeakPtr(), std::move(client), NULL);
94 }
95 
96 // static
Create(ExtensionService * service,std::unique_ptr<ExtensionInstallPrompt> client,const WebstoreInstaller::Approval * approval)97 scoped_refptr<CrxInstaller> CrxInstaller::Create(
98     ExtensionService* service,
99     std::unique_ptr<ExtensionInstallPrompt> client,
100     const WebstoreInstaller::Approval* approval) {
101   return new CrxInstaller(service->AsWeakPtr(), std::move(client), approval);
102 }
103 
CrxInstaller(base::WeakPtr<ExtensionService> service_weak,std::unique_ptr<ExtensionInstallPrompt> client,const WebstoreInstaller::Approval * approval)104 CrxInstaller::CrxInstaller(base::WeakPtr<ExtensionService> service_weak,
105                            std::unique_ptr<ExtensionInstallPrompt> client,
106                            const WebstoreInstaller::Approval* approval)
107     : profile_(service_weak->profile()),
108       install_directory_(service_weak->install_directory()),
109       install_source_(Manifest::INTERNAL),
110       approved_(false),
111       verification_check_failed_(false),
112       expected_manifest_check_level_(
113           WebstoreInstaller::MANIFEST_CHECK_LEVEL_STRICT),
114       fail_install_if_unexpected_version_(false),
115       extensions_enabled_(service_weak->extensions_enabled()),
116       delete_source_(false),
117       service_weak_(service_weak),
118       // See header file comment on |client_| for why we use a raw pointer here.
119       client_(client.release()),
120       apps_require_extension_mime_type_(false),
121       allow_silent_install_(false),
122       grant_permissions_(true),
123       install_cause_(extension_misc::INSTALL_CAUSE_UNSET),
124       creation_flags_(Extension::NO_FLAGS),
125       off_store_install_allow_reason_(OffStoreInstallDisallowed),
126       did_handle_successfully_(true),
127       error_on_unsupported_requirements_(false),
128       shared_file_task_runner_(GetExtensionFileTaskRunner()),
129       update_from_settings_page_(false),
130       install_flags_(kInstallFlagNone) {
131   if (!approval)
132     return;
133 
134   CHECK(profile()->IsSameOrParent(approval->profile));
135   if (client_) {
136     client_->install_ui()->SetUseAppInstalledBubble(
137         approval->use_app_installed_bubble);
138     client_->install_ui()->SetSkipPostInstallUI(approval->skip_post_install_ui);
139   }
140 
141   if (approval->skip_install_dialog) {
142     // Mark the extension as approved, but save the expected manifest and ID
143     // so we can check that they match the CRX's.
144     approved_ = true;
145     expected_manifest_check_level_ = approval->manifest_check_level;
146     if (expected_manifest_check_level_ !=
147         WebstoreInstaller::MANIFEST_CHECK_LEVEL_NONE) {
148       expected_manifest_ = approval->manifest->CreateDeepCopy();
149     }
150     expected_id_ = approval->extension_id;
151   }
152   if (approval->minimum_version.get())
153     minimum_version_ = base::Version(*approval->minimum_version);
154 
155   show_dialog_callback_ = approval->show_dialog_callback;
156 }
157 
~CrxInstaller()158 CrxInstaller::~CrxInstaller() {
159   DCHECK(!service_weak_ || service_weak_->browser_terminating() ||
160          installer_callback_.is_null());
161   DCHECK_CURRENTLY_ON(BrowserThread::UI);
162   // Ensure |client_| and |install_checker_| data members are destroyed on the
163   // UI thread. The |client_| dialog has a weak reference as |this| is its
164   // delegate, and |install_checker_| owns WeakPtrs, so must be destroyed on the
165   // same thread that created it.
166 }
167 
InstallCrx(const base::FilePath & source_file)168 void CrxInstaller::InstallCrx(const base::FilePath& source_file) {
169   crx_file::VerifierFormat format =
170       off_store_install_allow_reason_ == OffStoreInstallDisallowed
171           ? GetWebstoreVerifierFormat(
172                 base::CommandLine::ForCurrentProcess()->HasSwitch(
173                     ::switches::kAppsGalleryURL))
174           : GetExternalVerifierFormat();
175   InstallCrxFile(CRXFileInfo(source_file, format));
176 }
177 
InstallCrxFile(const CRXFileInfo & source_file)178 void CrxInstaller::InstallCrxFile(const CRXFileInfo& source_file) {
179   ExtensionService* service = service_weak_.get();
180   if (!service || service->browser_terminating())
181     return;
182 
183   NotifyCrxInstallBegin();
184 
185   source_file_ = source_file.path;
186 
187   auto unpacker = base::MakeRefCounted<SandboxedUnpacker>(
188       install_source_, creation_flags_, install_directory_,
189       GetUnpackerTaskRunner(), this);
190 
191   if (!GetUnpackerTaskRunner()->PostTask(
192           FROM_HERE, base::BindOnce(&SandboxedUnpacker::StartWithCrx, unpacker,
193                                     source_file))) {
194     NOTREACHED();
195   }
196 }
197 
InstallUnpackedCrx(const std::string & extension_id,const std::string & public_key,const base::FilePath & unpacked_dir)198 void CrxInstaller::InstallUnpackedCrx(const std::string& extension_id,
199                                       const std::string& public_key,
200                                       const base::FilePath& unpacked_dir) {
201   ExtensionService* service = service_weak_.get();
202   if (!service || service->browser_terminating())
203     return;
204 
205   NotifyCrxInstallBegin();
206 
207   source_file_ = unpacked_dir;
208 
209   auto unpacker = base::MakeRefCounted<SandboxedUnpacker>(
210       install_source_, creation_flags_, install_directory_,
211       GetUnpackerTaskRunner(), this);
212 
213   if (!GetUnpackerTaskRunner()->PostTask(
214           FROM_HERE,
215           base::BindOnce(&SandboxedUnpacker::StartWithDirectory, unpacker,
216                          extension_id, public_key, unpacked_dir))) {
217     NOTREACHED();
218   }
219 }
220 
InstallUserScript(const base::FilePath & source_file,const GURL & download_url)221 void CrxInstaller::InstallUserScript(const base::FilePath& source_file,
222                                      const GURL& download_url) {
223   DCHECK(!download_url.is_empty());
224 
225   NotifyCrxInstallBegin();
226 
227   source_file_ = source_file;
228   download_url_ = download_url;
229 
230   if (!shared_file_task_runner_->PostTask(
231           FROM_HERE,
232           base::BindOnce(&CrxInstaller::ConvertUserScriptOnSharedFileThread,
233                          this)))
234     NOTREACHED();
235 }
236 
ConvertUserScriptOnSharedFileThread()237 void CrxInstaller::ConvertUserScriptOnSharedFileThread() {
238   base::string16 error;
239   scoped_refptr<Extension> extension = ConvertUserScriptToExtension(
240       source_file_, download_url_, install_directory_, &error);
241   if (!extension.get()) {
242     ReportFailureFromSharedFileThread(CrxInstallError(
243         CrxInstallErrorType::OTHER,
244         CrxInstallErrorDetail::CONVERT_USER_SCRIPT_TO_EXTENSION_FAILED, error));
245     return;
246   }
247 
248   OnUnpackSuccessOnSharedFileThread(extension->path(), extension->path(),
249                                     nullptr, extension, SkBitmap(),
250                                     {} /* ruleset_install_prefs */);
251 }
252 
InstallWebApp(const WebApplicationInfo & web_app)253 void CrxInstaller::InstallWebApp(const WebApplicationInfo& web_app) {
254   NotifyCrxInstallBegin();
255 
256   if (!shared_file_task_runner_->PostTask(
257           FROM_HERE,
258           base::BindOnce(&CrxInstaller::ConvertWebAppOnSharedFileThread, this,
259                          web_app)))
260     NOTREACHED();
261 }
262 
UpdateExtensionFromUnpackedCrx(const std::string & extension_id,const std::string & public_key,const base::FilePath & unpacked_dir)263 void CrxInstaller::UpdateExtensionFromUnpackedCrx(
264     const std::string& extension_id,
265     const std::string& public_key,
266     const base::FilePath& unpacked_dir) {
267   ExtensionService* service = service_weak_.get();
268   if (!service || service->browser_terminating())
269     return;
270 
271   const Extension* extension = ExtensionRegistry::Get(service->profile())
272                                    ->GetInstalledExtension(extension_id);
273   if (!extension) {
274     LOG(WARNING) << "Will not update extension " << extension_id
275                  << " because it is not installed";
276     if (delete_source_)
277       temp_dir_ = unpacked_dir;
278     if (installer_callback_.is_null()) {
279       shared_file_task_runner_->PostTask(
280           FROM_HERE, base::BindOnce(&CrxInstaller::CleanupTempFiles, this));
281     } else {
282       shared_file_task_runner_->PostTaskAndReply(
283           FROM_HERE, base::BindOnce(&CrxInstaller::CleanupTempFiles, this),
284           base::BindOnce(
285               std::move(installer_callback_),
286               CrxInstallError(
287                   CrxInstallErrorType::OTHER,
288                   CrxInstallErrorDetail::UPDATE_NON_EXISTING_EXTENSION)));
289     }
290     return;
291   }
292 
293   expected_id_ = extension_id;
294   install_source_ = extension->location();
295   install_cause_ = extension_misc::INSTALL_CAUSE_UPDATE;
296   InitializeCreationFlagsForUpdate(extension, Extension::NO_FLAGS);
297 
298   const ExtensionPrefs* extension_prefs =
299       ExtensionPrefs::Get(service->GetBrowserContext());
300   DCHECK(extension_prefs);
301   set_do_not_sync(extension_prefs->DoNotSync(extension_id));
302 
303   InstallUnpackedCrx(extension_id, public_key, unpacked_dir);
304 }
305 
ConvertWebAppOnSharedFileThread(const WebApplicationInfo & web_app)306 void CrxInstaller::ConvertWebAppOnSharedFileThread(
307     const WebApplicationInfo& web_app) {
308   scoped_refptr<Extension> extension(
309       ConvertWebAppToExtension(web_app, base::Time::Now(), install_directory_,
310                                creation_flags_, install_source_));
311   if (!extension.get()) {
312     // Validation should have stopped any potential errors before getting here.
313     NOTREACHED() << "Could not convert web app to extension.";
314     return;
315   }
316 
317   // TODO(aa): conversion data gets lost here :(
318 
319   OnUnpackSuccessOnSharedFileThread(extension->path(), extension->path(),
320                                     nullptr, extension, SkBitmap(),
321                                     {} /* ruleset_install_prefs */);
322 }
323 
CheckExpectations(const Extension * extension)324 base::Optional<CrxInstallError> CrxInstaller::CheckExpectations(
325     const Extension* extension) {
326   DCHECK(shared_file_task_runner_->RunsTasksInCurrentSequence());
327 
328   // Make sure the expected ID matches if one was supplied or if we want to
329   // bypass the prompt.
330   if ((approved_ || !expected_id_.empty()) &&
331       expected_id_ != extension->id()) {
332     return CrxInstallError(
333         CrxInstallErrorType::OTHER, CrxInstallErrorDetail::UNEXPECTED_ID,
334         l10n_util::GetStringFUTF16(IDS_EXTENSION_INSTALL_UNEXPECTED_ID,
335                                    base::ASCIIToUTF16(expected_id_),
336                                    base::ASCIIToUTF16(extension->id())));
337   }
338 
339   if (expected_version_.IsValid() && fail_install_if_unexpected_version_ &&
340       expected_version_ != extension->version()) {
341     return CrxInstallError(
342         CrxInstallErrorType::OTHER, CrxInstallErrorDetail::MISMATCHED_VERSION,
343         l10n_util::GetStringFUTF16(
344             IDS_EXTENSION_INSTALL_UNEXPECTED_VERSION,
345             base::ASCIIToUTF16(expected_version_.GetString()),
346             base::ASCIIToUTF16(extension->version().GetString())));
347   }
348 
349   return base::nullopt;
350 }
351 
AllowInstall(const Extension * extension)352 base::Optional<CrxInstallError> CrxInstaller::AllowInstall(
353     const Extension* extension) {
354   DCHECK(shared_file_task_runner_->RunsTasksInCurrentSequence());
355 
356   if (minimum_version_.IsValid() &&
357       extension->version().CompareTo(minimum_version_) < 0) {
358     return CrxInstallError(
359         CrxInstallErrorType::OTHER, CrxInstallErrorDetail::UNEXPECTED_VERSION,
360         l10n_util::GetStringFUTF16(
361             IDS_EXTENSION_INSTALL_UNEXPECTED_VERSION,
362             base::ASCIIToUTF16(minimum_version_.GetString() + "+"),
363             base::ASCIIToUTF16(extension->version().GetString())));
364   }
365 
366   // Make sure the manifests match if we want to bypass the prompt.
367   if (approved_) {
368     bool valid = false;
369     if (expected_manifest_check_level_ ==
370         WebstoreInstaller::MANIFEST_CHECK_LEVEL_NONE) {
371       // To skip manifest checking, the extension must be a shared module
372       // and not request any permissions.
373       if (SharedModuleInfo::IsSharedModule(extension) &&
374           extension->permissions_data()->active_permissions().IsEmpty()) {
375         valid = true;
376       }
377     } else {
378       valid = expected_manifest_->Equals(original_manifest_.get());
379       if (!valid && expected_manifest_check_level_ ==
380           WebstoreInstaller::MANIFEST_CHECK_LEVEL_LOOSE) {
381         std::string error;
382         scoped_refptr<Extension> dummy_extension =
383             Extension::Create(base::FilePath(),
384                               install_source_,
385                               *expected_manifest_->value(),
386                               creation_flags_,
387                               extension->id(),
388                               &error);
389         if (error.empty()) {
390           valid = !(PermissionMessageProvider::Get()->IsPrivilegeIncrease(
391               dummy_extension->permissions_data()->active_permissions(),
392               extension->permissions_data()->active_permissions(),
393               extension->GetType()));
394         }
395       }
396     }
397 
398     if (!valid)
399       return CrxInstallError(
400           CrxInstallErrorType::OTHER, CrxInstallErrorDetail::MANIFEST_INVALID,
401           l10n_util::GetStringUTF16(IDS_EXTENSION_MANIFEST_INVALID));
402   }
403 
404   // The checks below are skipped for themes, external installs, and bookmark
405   // apps.
406   // TODO(pamg): After ManagementPolicy refactoring is complete, remove this
407   // and other uses of install_source_ that are no longer needed now that the
408   // SandboxedUnpacker sets extension->location.
409   if (extension->is_theme() || extension->from_bookmark() ||
410       Manifest::IsExternalLocation(install_source_)) {
411     return base::nullopt;
412   }
413 
414   if (!extensions_enabled_) {
415     return CrxInstallError(
416         CrxInstallErrorType::DECLINED,
417         CrxInstallErrorDetail::INSTALL_NOT_ENABLED,
418         l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_NOT_ENABLED));
419   }
420 
421   if (install_cause_ == extension_misc::INSTALL_CAUSE_USER_DOWNLOAD &&
422       !is_gallery_install() &&
423       off_store_install_allow_reason_ == OffStoreInstallDisallowed) {
424     // Don't delete source in this case so that the user can install
425     // manually if they want.
426     delete_source_ = false;
427     did_handle_successfully_ = false;
428 
429     return CrxInstallError(
430         CrxInstallErrorType::OTHER,
431         CrxInstallErrorDetail::OFFSTORE_INSTALL_DISALLOWED,
432         l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_DISALLOWED_ON_SITE));
433   }
434 
435   if (extension_->is_app()) {
436     // If the app was downloaded, apps_require_extension_mime_type_
437     // will be set.  In this case, check that it was served with the
438     // right mime type.  Make an exception for file URLs, which come
439     // from the users computer and have no headers.
440     if (!download_url_.SchemeIsFile() &&
441         apps_require_extension_mime_type_ &&
442         original_mime_type_ != Extension::kMimeType) {
443       return CrxInstallError(
444           CrxInstallErrorType::OTHER,
445           CrxInstallErrorDetail::INCORRECT_APP_CONTENT_TYPE,
446           l10n_util::GetStringFUTF16(
447               IDS_EXTENSION_INSTALL_INCORRECT_APP_CONTENT_TYPE,
448               base::ASCIIToUTF16(Extension::kMimeType)));
449     }
450 
451     // If the client_ is NULL, then the app is either being installed via
452     // an internal mechanism like sync, external_extensions, or default apps.
453     // In that case, we don't want to enforce things like the install origin.
454     if (!is_gallery_install() && client_) {
455       // For apps with a gallery update URL, require that they be installed
456       // from the gallery.
457       // TODO(erikkay) Apply this rule for paid extensions and themes as well.
458       if (ManifestURL::UpdatesFromGallery(extension)) {
459         return CrxInstallError(
460             CrxInstallErrorType::OTHER,
461             CrxInstallErrorDetail::NOT_INSTALLED_FROM_GALLERY,
462             l10n_util::GetStringFUTF16(
463                 IDS_EXTENSION_INSTALL_GALLERY_ONLY,
464                 l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE)));
465       }
466 
467       // For self-hosted apps, verify that the entire extent is on the same
468       // host (or a subdomain of the host) the download happened from.  There's
469       // no way for us to verify that the app controls any other hosts.
470       URLPattern pattern(UserScript::ValidUserScriptSchemes());
471       pattern.SetHost(download_url_.host());
472       pattern.SetMatchSubdomains(true);
473 
474       const URLPatternSet& patterns = extension_->web_extent();
475       for (auto i = patterns.begin(); i != patterns.end(); ++i) {
476         if (!pattern.MatchesHost(i->host())) {
477           return CrxInstallError(
478               CrxInstallErrorType::OTHER,
479               CrxInstallErrorDetail::INCORRECT_INSTALL_HOST,
480               l10n_util::GetStringUTF16(
481                   IDS_EXTENSION_INSTALL_INCORRECT_INSTALL_HOST));
482         }
483       }
484     }
485   }
486 
487   return base::nullopt;
488 }
489 
ShouldComputeHashesOnUI(scoped_refptr<const Extension> extension,base::OnceCallback<void (bool)> callback)490 void CrxInstaller::ShouldComputeHashesOnUI(
491     scoped_refptr<const Extension> extension,
492     base::OnceCallback<void(bool)> callback) {
493   DCHECK_CURRENTLY_ON(BrowserThread::UI);
494   ExtensionService* service = service_weak_.get();
495   if (!service || service->browser_terminating())
496     return;
497 
498   extensions::ContentVerifier* content_verifier =
499       extensions::ExtensionSystem::Get(profile_)->content_verifier();
500   bool result = content_verifier &&
501                 content_verifier->ShouldComputeHashesOnInstall(*extension);
502   GetUnpackerTaskRunner()->PostTask(
503       FROM_HERE, base::BindOnce(std::move(callback), result));
504 }
505 
ShouldComputeHashesForOffWebstoreExtension(scoped_refptr<const Extension> extension,base::OnceCallback<void (bool)> callback)506 void CrxInstaller::ShouldComputeHashesForOffWebstoreExtension(
507     scoped_refptr<const Extension> extension,
508     base::OnceCallback<void(bool)> callback) {
509   DCHECK(GetUnpackerTaskRunner()->RunsTasksInCurrentSequence());
510   if (!content::GetUIThreadTaskRunner({})->PostTask(
511           FROM_HERE,
512           base::BindOnce(&CrxInstaller::ShouldComputeHashesOnUI, this,
513                          std::move(extension), std::move(callback)))) {
514     NOTREACHED();
515   }
516 }
517 
OnUnpackFailure(const CrxInstallError & error)518 void CrxInstaller::OnUnpackFailure(const CrxInstallError& error) {
519   DCHECK(GetUnpackerTaskRunner()->RunsTasksInCurrentSequence());
520   if (!content::GetUIThreadTaskRunner({})->PostTask(
521           FROM_HERE, base::BindOnce(&CrxInstaller::ReportFailureFromUIThread,
522                                     this, error))) {
523     NOTREACHED();
524   }
525 }
526 
OnUnpackSuccess(const base::FilePath & temp_dir,const base::FilePath & extension_dir,std::unique_ptr<base::DictionaryValue> original_manifest,const Extension * extension,const SkBitmap & install_icon,declarative_net_request::RulesetInstallPrefs ruleset_install_prefs)527 void CrxInstaller::OnUnpackSuccess(
528     const base::FilePath& temp_dir,
529     const base::FilePath& extension_dir,
530     std::unique_ptr<base::DictionaryValue> original_manifest,
531     const Extension* extension,
532     const SkBitmap& install_icon,
533     declarative_net_request::RulesetInstallPrefs ruleset_install_prefs) {
534   DCHECK(GetUnpackerTaskRunner()->RunsTasksInCurrentSequence());
535   shared_file_task_runner_->PostTask(
536       FROM_HERE,
537       base::BindOnce(&CrxInstaller::OnUnpackSuccessOnSharedFileThread, this,
538                      temp_dir, extension_dir, std::move(original_manifest),
539                      scoped_refptr<const Extension>(extension), install_icon,
540                      std::move(ruleset_install_prefs)));
541 }
542 
OnUnpackSuccessOnSharedFileThread(base::FilePath temp_dir,base::FilePath extension_dir,std::unique_ptr<base::DictionaryValue> original_manifest,scoped_refptr<const Extension> extension,SkBitmap install_icon,declarative_net_request::RulesetInstallPrefs ruleset_install_prefs)543 void CrxInstaller::OnUnpackSuccessOnSharedFileThread(
544     base::FilePath temp_dir,
545     base::FilePath extension_dir,
546     std::unique_ptr<base::DictionaryValue> original_manifest,
547     scoped_refptr<const Extension> extension,
548     SkBitmap install_icon,
549     declarative_net_request::RulesetInstallPrefs ruleset_install_prefs) {
550   DCHECK(shared_file_task_runner_->RunsTasksInCurrentSequence());
551 
552   extension_ = extension;
553   temp_dir_ = temp_dir;
554   ruleset_install_prefs_ = std::move(ruleset_install_prefs);
555   ReportInstallationStage(InstallationStage::kCheckingExpectations);
556 
557   if (!install_icon.empty())
558     install_icon_ = std::make_unique<SkBitmap>(install_icon);
559 
560   if (original_manifest) {
561     original_manifest_ = std::make_unique<Manifest>(
562         Manifest::INVALID_LOCATION, std::move(original_manifest));
563   }
564 
565   // We don't have to delete the unpack dir explicity since it is a child of
566   // the temp dir.
567   unpacked_extension_root_ = extension_dir;
568 
569   // Check whether the crx matches the set expectations.
570   base::Optional<CrxInstallError> expectations_error =
571       CheckExpectations(extension.get());
572   if (expectations_error) {
573     DCHECK_NE(CrxInstallErrorType::NONE, expectations_error->type());
574     ReportFailureFromSharedFileThread(*expectations_error);
575     return;
576   }
577 
578   // The |expectations_error| could be non-null in case of version mismatch if
579   // |fail_install_if_unexpected_version_| is set to false.
580   // If |expectations_passed_callback_| is set, the installer owns the crx file,
581   // and there is no version mismatch, invoke the callback and transfer the
582   // ownership. The responsibility to delete the crx file now lies with the
583   // callback.
584   if (!expectations_verified_callback_.is_null() && delete_source_ &&
585       (!expected_version_.IsValid() ||
586        expected_version_ == extension->version())) {
587     delete_source_ = false;
588     if (!content::GetUIThreadTaskRunner({})->PostTask(
589             FROM_HERE,
590             base::BindOnce(std::move(expectations_verified_callback_)))) {
591       NOTREACHED();
592     }
593   }
594 
595   base::Optional<CrxInstallError> error = AllowInstall(extension.get());
596   if (error) {
597     DCHECK_NE(CrxInstallErrorType::NONE, error->type());
598     ReportFailureFromSharedFileThread(*error);
599     return;
600   }
601 
602   if (!content::GetUIThreadTaskRunner({})->PostTask(
603           FROM_HERE, base::BindOnce(&CrxInstaller::CheckInstall, this)))
604     NOTREACHED();
605 }
606 
OnStageChanged(InstallationStage stage)607 void CrxInstaller::OnStageChanged(InstallationStage stage) {
608   ReportInstallationStage(stage);
609 }
610 
CheckInstall()611 void CrxInstaller::CheckInstall() {
612   DCHECK_CURRENTLY_ON(BrowserThread::UI);
613   ExtensionService* service = service_weak_.get();
614   if (!service || service->browser_terminating())
615     return;
616 
617   // TODO(crbug.com/420147): Move this code to a utility class to avoid
618   // duplication of SharedModuleService::CheckImports code.
619   if (SharedModuleInfo::ImportsModules(extension())) {
620     const std::vector<SharedModuleInfo::ImportInfo>& imports =
621         SharedModuleInfo::GetImports(extension());
622     ExtensionRegistry* registry = ExtensionRegistry::Get(service->profile());
623     for (const auto& import : imports) {
624       const Extension* imported_module = registry->GetExtensionById(
625           import.extension_id, ExtensionRegistry::EVERYTHING);
626       if (!imported_module)
627         continue;
628 
629       if (!SharedModuleInfo::IsSharedModule(imported_module)) {
630         ReportFailureFromUIThread(CrxInstallError(
631             CrxInstallErrorType::DECLINED,
632             CrxInstallErrorDetail::DEPENDENCY_NOT_SHARED_MODULE,
633             l10n_util::GetStringFUTF16(
634                 IDS_EXTENSION_INSTALL_DEPENDENCY_NOT_SHARED_MODULE,
635                 base::UTF8ToUTF16(imported_module->name()))));
636         return;
637       }
638       base::Version version_required(import.minimum_version);
639       if (version_required.IsValid() &&
640           imported_module->version().CompareTo(version_required) < 0) {
641         ReportFailureFromUIThread(CrxInstallError(
642             CrxInstallErrorType::DECLINED,
643             CrxInstallErrorDetail::DEPENDENCY_OLD_VERSION,
644             l10n_util::GetStringFUTF16(
645                 IDS_EXTENSION_INSTALL_DEPENDENCY_OLD_VERSION,
646                 base::UTF8ToUTF16(imported_module->name()),
647                 base::ASCIIToUTF16(import.minimum_version),
648                 base::ASCIIToUTF16(imported_module->version().GetString()))));
649         return;
650       }
651       if (!SharedModuleInfo::IsExportAllowedByAllowlist(imported_module,
652                                                         extension()->id())) {
653         ReportFailureFromUIThread(CrxInstallError(
654             CrxInstallErrorType::DECLINED,
655             CrxInstallErrorDetail::DEPENDENCY_NOT_ALLOWLISTED,
656             l10n_util::GetStringFUTF16(
657                 IDS_EXTENSION_INSTALL_DEPENDENCY_NOT_ALLOWLISTED,
658                 base::UTF8ToUTF16(extension()->name()),
659                 base::UTF8ToUTF16(imported_module->name()))));
660         return;
661       }
662     }
663   }
664 
665   // Skip the checks if the extension is a bookmark app.
666   if (extension()->from_bookmark()) {
667     ConfirmInstall();
668     return;
669   }
670 
671   // Run the policy, requirements and blocklist checks in parallel.
672   check_group_ = std::make_unique<PreloadCheckGroup>();
673 
674   policy_check_ = std::make_unique<PolicyCheck>(profile_, extension());
675   requirements_check_ = std::make_unique<RequirementsChecker>(extension());
676   blocklist_check_ =
677       std::make_unique<BlocklistCheck>(Blocklist::Get(profile_), extension_);
678 
679   check_group_->AddCheck(policy_check_.get());
680   check_group_->AddCheck(requirements_check_.get());
681   check_group_->AddCheck(blocklist_check_.get());
682 
683   check_group_->Start(
684       base::BindOnce(&CrxInstaller::OnInstallChecksComplete, this));
685 }
686 
OnInstallChecksComplete(const PreloadCheck::Errors & errors)687 void CrxInstaller::OnInstallChecksComplete(const PreloadCheck::Errors& errors) {
688   DCHECK_CURRENTLY_ON(BrowserThread::UI);
689   if (!service_weak_)
690     return;
691 
692   if (errors.empty()) {
693     ConfirmInstall();
694     return;
695   }
696 
697   // Check for requirement errors.
698   if (!requirements_check_->GetErrorMessage().empty()) {
699     if (error_on_unsupported_requirements_) {
700       ReportFailureFromUIThread(
701           CrxInstallError(CrxInstallErrorType::DECLINED,
702                           CrxInstallErrorDetail::UNSUPPORTED_REQUIREMENTS,
703                           requirements_check_->GetErrorMessage()));
704       return;
705     }
706     install_flags_ |= kInstallFlagHasRequirementErrors;
707   }
708 
709   // Check the blocklist state.
710   if (errors.count(PreloadCheck::BLOCKLISTED_ID) ||
711       errors.count(PreloadCheck::BLOCKLISTED_UNKNOWN)) {
712     if (allow_silent_install_) {
713       // NOTE: extension may still be blocklisted, but we're forced to silently
714       // install it. In this case, ExtensionService::OnExtensionInstalled needs
715       // to deal with it.
716       if (errors.count(PreloadCheck::BLOCKLISTED_ID))
717         install_flags_ |= kInstallFlagIsBlocklistedForMalware;
718     } else {
719       // User tried to install a blocklisted extension. Show an error and
720       // refuse to install it.
721       ReportFailureFromUIThread(CrxInstallError(
722           CrxInstallErrorType::DECLINED,
723           CrxInstallErrorDetail::EXTENSION_IS_BLOCKLISTED,
724           l10n_util::GetStringFUTF16(IDS_EXTENSION_IS_BLOCKLISTED,
725                                      base::UTF8ToUTF16(extension()->name()))));
726       UMA_HISTOGRAM_ENUMERATION("ExtensionBlacklist.BlockCRX",
727                                 extension()->location(),
728                                 Manifest::NUM_LOCATIONS);
729       return;
730     }
731   }
732 
733   // Check for policy errors.
734   if (errors.count(PreloadCheck::DISALLOWED_BY_POLICY)) {
735     // We don't want to show the error infobar for installs from the WebStore,
736     // because the WebStore already shows an error dialog itself.
737     // Note: |client_| can be NULL in unit_tests!
738     if (extension()->from_webstore() && client_)
739       client_->install_ui()->SetSkipPostInstallUI(true);
740 
741     ReportFailureFromUIThread(
742         CrxInstallError(CrxInstallErrorType::DECLINED,
743                         CrxInstallErrorDetail::DISALLOWED_BY_POLICY,
744                         policy_check_->GetErrorMessage()));
745     return;
746   }
747 
748   ConfirmInstall();
749 }
750 
ConfirmInstall()751 void CrxInstaller::ConfirmInstall() {
752   DCHECK_CURRENTLY_ON(BrowserThread::UI);
753   ReportInstallationStage(InstallationStage::kFinalizing);
754   ExtensionService* service = service_weak_.get();
755   if (!service || service->browser_terminating())
756     return;
757 
758   if (KioskModeInfo::IsKioskOnly(extension())) {
759     bool in_kiosk_mode = false;
760 #if defined(OS_CHROMEOS)
761     user_manager::UserManager* user_manager = user_manager::UserManager::Get();
762     in_kiosk_mode = user_manager && user_manager->IsLoggedInAsKioskApp();
763 #endif
764     if (!in_kiosk_mode) {
765       ReportFailureFromUIThread(CrxInstallError(
766           CrxInstallErrorType::DECLINED, CrxInstallErrorDetail::KIOSK_MODE_ONLY,
767           l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_KIOSK_MODE_ONLY)));
768       return;
769     }
770   }
771 
772   // Check whether this install is initiated from the settings page to
773   // update an existing extension or app.
774   CheckUpdateFromSettingsPage();
775 
776   GURL overlapping_url;
777   ExtensionRegistry* registry = ExtensionRegistry::Get(service->profile());
778   const Extension* overlapping_extension =
779       registry->enabled_extensions().GetHostedAppByOverlappingWebExtent(
780           extension()->web_extent());
781   if (overlapping_extension &&
782       overlapping_extension->id() != extension()->id()) {
783     ReportFailureFromUIThread(
784         CrxInstallError(CrxInstallErrorType::OTHER,
785                         CrxInstallErrorDetail::OVERLAPPING_WEB_EXTENT,
786                         l10n_util::GetStringFUTF16(
787                             IDS_EXTENSION_OVERLAPPING_WEB_EXTENT,
788                             base::UTF8ToUTF16(extension()->name()),
789                             base::UTF8ToUTF16(overlapping_extension->name()))));
790     return;
791   }
792 
793   current_version_ = base::Version(ExtensionPrefs::Get(service->profile())
794                          ->GetVersionString(extension()->id()));
795 
796   if (client_ &&
797       (!allow_silent_install_ || !approved_) &&
798       !update_from_settings_page_) {
799     AddRef();  // Balanced in OnInstallPromptDone().
800     client_->ShowDialog(base::Bind(&CrxInstaller::OnInstallPromptDone, this),
801                         extension(), nullptr, show_dialog_callback_);
802   } else {
803     UpdateCreationFlagsAndCompleteInstall(kDontWithholdPermissions);
804   }
805 }
806 
OnInstallPromptDone(ExtensionInstallPrompt::Result result)807 void CrxInstaller::OnInstallPromptDone(ExtensionInstallPrompt::Result result) {
808   DCHECK_CURRENTLY_ON(BrowserThread::UI);
809 
810   // If update_from_settings_page_ boolean is true, this functions is
811   // getting called in response to ExtensionInstallPrompt::ConfirmReEnable()
812   // and if it is false, this function is called in response to
813   // ExtensionInstallPrompt::ShowDialog().
814 
815   ExtensionService* service = service_weak_.get();
816   switch (result) {
817     case ExtensionInstallPrompt::Result::ACCEPTED:
818       if (!service || service->browser_terminating())
819         return;
820 
821       // Install (or re-enable) the extension with full permissions.
822       if (update_from_settings_page_)
823         service->GrantPermissionsAndEnableExtension(extension());
824       else
825         UpdateCreationFlagsAndCompleteInstall(kDontWithholdPermissions);
826       break;
827     case ExtensionInstallPrompt::Result::ACCEPTED_AND_OPTION_CHECKED:
828       if (!service || service->browser_terminating())
829         return;
830 
831       // TODO(tjudkins): Add support for withholding permissions on the
832       // re-enable prompt here once we know how that should be handled.
833       DCHECK(!update_from_settings_page_);
834       // Install the extension with permissions withheld.
835       UpdateCreationFlagsAndCompleteInstall(kWithholdPermissions);
836       break;
837     case ExtensionInstallPrompt::Result::USER_CANCELED:
838       if (!update_from_settings_page_) {
839         ExtensionService::RecordPermissionMessagesHistogram(extension(),
840                                                             "InstallCancel");
841         NotifyCrxInstallComplete(CrxInstallError(
842             CrxInstallErrorType::OTHER, CrxInstallErrorDetail::USER_CANCELED));
843       }
844       break;
845     case ExtensionInstallPrompt::Result::ABORTED:
846       if (!update_from_settings_page_) {
847         ExtensionService::RecordPermissionMessagesHistogram(extension(),
848                                                             "InstallAbort");
849         NotifyCrxInstallComplete(CrxInstallError(
850             CrxInstallErrorType::OTHER, CrxInstallErrorDetail::USER_ABORTED));
851       }
852       break;
853   }
854 
855   Release();  // balanced in ConfirmInstall() or ConfirmReEnable().
856 }
857 
InitializeCreationFlagsForUpdate(const Extension * extension,const int initial_flags)858 void CrxInstaller::InitializeCreationFlagsForUpdate(const Extension* extension,
859                                                     const int initial_flags) {
860   DCHECK(extension);
861 
862   creation_flags_ = initial_flags;
863 
864   // If the extension was installed from or has migrated to the webstore, or
865   // its auto-update URL is from the webstore, treat it as a webstore install.
866   // Note that we ignore some older extensions with blank auto-update URLs
867   // because we are mostly concerned with restrictions on NaCl extensions,
868   // which are newer.
869   if (extension->from_webstore() || ManifestURL::UpdatesFromGallery(extension))
870     creation_flags_ |= Extension::FROM_WEBSTORE;
871 
872   // Bookmark apps being updated is kind of a contradiction, but that's because
873   // we mark the default apps as bookmark apps, and they're hosted in the web
874   // store, thus they can get updated. See http://crbug.com/101605 for more
875   // details.
876   if (extension->from_bookmark())
877     creation_flags_ |= Extension::FROM_BOOKMARK;
878 
879   if (extension->was_installed_by_default())
880     creation_flags_ |= Extension::WAS_INSTALLED_BY_DEFAULT;
881 
882   if (extension->was_installed_by_oem())
883     creation_flags_ |= Extension::WAS_INSTALLED_BY_OEM;
884 }
885 
UpdateCreationFlagsAndCompleteInstall(WithholdingBehavior withholding_behavior)886 void CrxInstaller::UpdateCreationFlagsAndCompleteInstall(
887     WithholdingBehavior withholding_behavior) {
888   creation_flags_ = extension()->creation_flags() | Extension::REQUIRE_KEY;
889   // If the extension was already installed and had file access, also grant file
890   // access to the updated extension.
891   if (ExtensionPrefs::Get(profile())->AllowFileAccess(extension()->id()))
892     creation_flags_ |= Extension::ALLOW_FILE_ACCESS;
893 
894   if (withholding_behavior == kWithholdPermissions)
895     creation_flags_ |= Extension::WITHHOLD_PERMISSIONS;
896 
897   if (!shared_file_task_runner_->PostTask(
898           FROM_HERE, base::BindOnce(&CrxInstaller::CompleteInstall, this))) {
899     NOTREACHED();
900   }
901 }
902 
CompleteInstall()903 void CrxInstaller::CompleteInstall() {
904   DCHECK(shared_file_task_runner_->RunsTasksInCurrentSequence());
905 
906   if (current_version_.IsValid() &&
907       current_version_.CompareTo(extension()->version()) > 0) {
908     ReportFailureFromSharedFileThread(CrxInstallError(
909         CrxInstallErrorType::DECLINED,
910         CrxInstallErrorDetail::CANT_DOWNGRADE_VERSION,
911         l10n_util::GetStringUTF16(extension()->is_app()
912                                       ? IDS_APP_CANT_DOWNGRADE_VERSION
913                                       : IDS_EXTENSION_CANT_DOWNGRADE_VERSION)));
914     return;
915   }
916 
917   ExtensionAssetsManager* assets_manager =
918       ExtensionAssetsManager::GetInstance();
919   assets_manager->InstallExtension(
920       extension(),
921       unpacked_extension_root_,
922       install_directory_,
923       profile(),
924       base::Bind(&CrxInstaller::ReloadExtensionAfterInstall, this));
925 }
926 
ReloadExtensionAfterInstall(const base::FilePath & version_dir)927 void CrxInstaller::ReloadExtensionAfterInstall(
928     const base::FilePath& version_dir) {
929   DCHECK(shared_file_task_runner_->RunsTasksInCurrentSequence());
930 
931   if (version_dir.empty()) {
932     ReportFailureFromSharedFileThread(
933         CrxInstallError(CrxInstallErrorType::OTHER,
934                         CrxInstallErrorDetail::MOVE_DIRECTORY_TO_PROFILE_FAILED,
935                         l10n_util::GetStringUTF16(
936                             IDS_EXTENSION_MOVE_DIRECTORY_TO_PROFILE_FAILED)));
937     return;
938   }
939 
940   // This is lame, but we must reload the extension because absolute paths
941   // inside the content scripts are established inside InitFromValue() and we
942   // just moved the extension.
943   // TODO(aa): All paths to resources inside extensions should be created
944   // lazily and based on the Extension's root path at that moment.
945   // TODO(rdevlin.cronin): Continue removing std::string errors and replacing
946   // with base::string16
947   std::string extension_id = extension()->id();
948   std::string error;
949   extension_ = file_util::LoadExtension(
950       version_dir, install_source_,
951       // Note: modified by UpdateCreationFlagsAndCompleteInstall.
952       creation_flags_, &error);
953 
954   if (extension()) {
955     ReportSuccessFromSharedFileThread();
956   } else {
957     LOG(ERROR) << error << " " << extension_id << " " << download_url_;
958     ReportFailureFromSharedFileThread(CrxInstallError(
959         CrxInstallErrorType::OTHER, CrxInstallErrorDetail::CANT_LOAD_EXTENSION,
960         base::UTF8ToUTF16(error)));
961   }
962 }
963 
ReportFailureFromSharedFileThread(const CrxInstallError & error)964 void CrxInstaller::ReportFailureFromSharedFileThread(
965     const CrxInstallError& error) {
966   DCHECK(shared_file_task_runner_->RunsTasksInCurrentSequence());
967   if (!content::GetUIThreadTaskRunner({})->PostTask(
968           FROM_HERE, base::BindOnce(&CrxInstaller::ReportFailureFromUIThread,
969                                     this, error))) {
970     NOTREACHED();
971   }
972 }
973 
ReportFailureFromUIThread(const CrxInstallError & error)974 void CrxInstaller::ReportFailureFromUIThread(const CrxInstallError& error) {
975   DCHECK_CURRENTLY_ON(BrowserThread::UI);
976   DCHECK_NE(CrxInstallErrorType::NONE, error.type());
977 
978   if (!service_weak_.get() || service_weak_->browser_terminating())
979     return;
980 
981   content::NotificationService* service =
982       content::NotificationService::current();
983   service->Notify(NOTIFICATION_EXTENSION_INSTALL_ERROR,
984                   content::Source<CrxInstaller>(this),
985                   content::Details<const CrxInstallError>(&error));
986 
987   // This isn't really necessary, it is only used because unit tests expect to
988   // see errors get reported via this interface.
989   //
990   // TODO(aa): Need to go through unit tests and clean them up too, probably get
991   // rid of this line.
992   LoadErrorReporter::GetInstance()->ReportError(error.message(),
993                                                 false);  // Be quiet.
994 
995   if (client_)
996     client_->OnInstallFailure(error);
997 
998   NotifyCrxInstallComplete(error);
999 
1000   // Delete temporary files.
1001   CleanupTempFiles();
1002 }
1003 
ReportSuccessFromSharedFileThread()1004 void CrxInstaller::ReportSuccessFromSharedFileThread() {
1005   DCHECK(shared_file_task_runner_->RunsTasksInCurrentSequence());
1006 
1007   // Tracking number of extensions installed by users
1008   if (install_cause() == extension_misc::INSTALL_CAUSE_USER_DOWNLOAD)
1009     UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionInstalled", 1, 2);
1010 
1011   if (!content::GetUIThreadTaskRunner({})->PostTask(
1012           FROM_HERE,
1013           base::BindOnce(&CrxInstaller::ReportSuccessFromUIThread, this)))
1014     NOTREACHED();
1015 
1016   // Delete temporary files.
1017   CleanupTempFiles();
1018 }
1019 
ReportSuccessFromUIThread()1020 void CrxInstaller::ReportSuccessFromUIThread() {
1021   DCHECK_CURRENTLY_ON(BrowserThread::UI);
1022 
1023   if (!service_weak_.get() || service_weak_->browser_terminating())
1024     return;
1025 
1026   extension()->permissions_data()->BindToCurrentThread();
1027 
1028   if (!update_from_settings_page_) {
1029     // If there is a client, tell the client about installation.
1030     if (client_)
1031       client_->OnInstallSuccess(extension_, install_icon_.get());
1032 
1033     // We update the extension's granted permissions if the user already
1034     // approved the install (client_ is non NULL), or we are allowed to install
1035     // this silently.
1036     if ((client_ || allow_silent_install_) && grant_permissions_ &&
1037         (!expected_version_.IsValid() ||
1038          expected_version_ == extension()->version())) {
1039       PermissionsUpdater perms_updater(profile());
1040       perms_updater.InitializePermissions(extension());
1041       perms_updater.GrantActivePermissions(extension());
1042     }
1043   }
1044 
1045   service_weak_->OnExtensionInstalled(extension(), page_ordinal_,
1046                                       install_flags_, ruleset_install_prefs_);
1047   NotifyCrxInstallComplete(base::nullopt);
1048 }
1049 
ReportInstallationStage(InstallationStage stage)1050 void CrxInstaller::ReportInstallationStage(InstallationStage stage) {
1051   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
1052     DCHECK(GetUnpackerTaskRunner()->RunsTasksInCurrentSequence() ||
1053            shared_file_task_runner_->RunsTasksInCurrentSequence());
1054     if (!content::GetUIThreadTaskRunner({})->PostTask(
1055             FROM_HERE, base::BindOnce(&CrxInstaller::ReportInstallationStage,
1056                                       this, stage))) {
1057       NOTREACHED();
1058     }
1059     return;
1060   }
1061 
1062   if (!service_weak_.get() || service_weak_->browser_terminating())
1063     return;
1064   // In case of force installed extensions, expected_id_ should always be set.
1065   // We do not want to report in case of other extensions.
1066   if (expected_id_.empty())
1067     return;
1068   InstallStageTracker* install_stage_tracker =
1069       InstallStageTracker::Get(profile_);
1070   install_stage_tracker->ReportCRXInstallationStage(expected_id_, stage);
1071 }
1072 
NotifyCrxInstallBegin()1073 void CrxInstaller::NotifyCrxInstallBegin() {
1074   InstallTrackerFactory::GetForBrowserContext(profile())
1075       ->OnBeginCrxInstall(expected_id_);
1076 }
1077 
NotifyCrxInstallComplete(const base::Optional<CrxInstallError> & error)1078 void CrxInstaller::NotifyCrxInstallComplete(
1079     const base::Optional<CrxInstallError>& error) {
1080   ReportInstallationStage(InstallationStage::kComplete);
1081   const std::string extension_id =
1082       expected_id_.empty() && extension() ? extension()->id() : expected_id_;
1083   InstallStageTracker* install_stage_tracker =
1084       InstallStageTracker::Get(profile_);
1085   install_stage_tracker->ReportInstallationStage(
1086       extension_id, InstallStageTracker::Stage::COMPLETE);
1087   const bool success = !error.has_value();
1088 
1089   if (extension()) {
1090     install_stage_tracker->ReportExtensionType(extension_id,
1091                                                extension()->GetType());
1092   }
1093 
1094   if (!success && (!expected_id_.empty() || extension())) {
1095     switch (error->type()) {
1096       case CrxInstallErrorType::DECLINED:
1097         install_stage_tracker->ReportCrxInstallError(
1098             extension_id,
1099             InstallStageTracker::FailureReason::CRX_INSTALL_ERROR_DECLINED,
1100             error->detail());
1101         break;
1102       case CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE:
1103         install_stage_tracker->ReportSandboxedUnpackerFailureReason(
1104             extension_id, error->sandbox_failure_detail());
1105         break;
1106       case CrxInstallErrorType::OTHER:
1107         install_stage_tracker->ReportCrxInstallError(
1108             extension_id,
1109             InstallStageTracker::FailureReason::CRX_INSTALL_ERROR_OTHER,
1110             error->detail());
1111         break;
1112       case CrxInstallErrorType::NONE:
1113         NOTREACHED();
1114         break;
1115     }
1116   }
1117 
1118   // Some users (such as the download shelf) need to know when a
1119   // CRXInstaller is done.  Listening for the EXTENSION_* events
1120   // is problematic because they don't know anything about the
1121   // extension before it is unpacked, so they cannot filter based
1122   // on the extension.
1123   content::NotificationService::current()->Notify(
1124       NOTIFICATION_CRX_INSTALLER_DONE, content::Source<CrxInstaller>(this),
1125       content::Details<const Extension>(success ? extension() : NULL));
1126 
1127   InstallTrackerFactory::GetForBrowserContext(profile())
1128       ->OnFinishCrxInstall(success ? extension()->id() : expected_id_, success);
1129 
1130   if (success)
1131     ConfirmReEnable();
1132 
1133   if (!installer_callback_.is_null() &&
1134       !content::GetUIThreadTaskRunner({})->PostTask(
1135           FROM_HERE, base::BindOnce(std::move(installer_callback_), error))) {
1136     NOTREACHED();
1137   }
1138 }
1139 
CleanupTempFiles()1140 void CrxInstaller::CleanupTempFiles() {
1141   if (!shared_file_task_runner_->RunsTasksInCurrentSequence()) {
1142     if (!shared_file_task_runner_->PostTask(
1143             FROM_HERE, base::BindOnce(&CrxInstaller::CleanupTempFiles, this))) {
1144       NOTREACHED();
1145     }
1146     return;
1147   }
1148 
1149   // Delete the temp directory and crx file as necessary.
1150   if (!temp_dir_.value().empty()) {
1151     base::DeletePathRecursively(temp_dir_);
1152     temp_dir_ = base::FilePath();
1153   }
1154 
1155   if (delete_source_ && !source_file_.value().empty()) {
1156     base::DeleteFile(source_file_);
1157     source_file_ = base::FilePath();
1158   }
1159 }
1160 
CheckUpdateFromSettingsPage()1161 void CrxInstaller::CheckUpdateFromSettingsPage() {
1162   DCHECK_CURRENTLY_ON(BrowserThread::UI);
1163 
1164   ExtensionService* service = service_weak_.get();
1165   if (!service || service->browser_terminating())
1166     return;
1167 
1168   if (off_store_install_allow_reason_ != OffStoreInstallAllowedFromSettingsPage)
1169     return;
1170 
1171   const Extension* installed_extension =
1172       ExtensionRegistry::Get(service->profile())
1173           ->GetInstalledExtension(extension()->id());
1174   if (installed_extension) {
1175     // Previous version of the extension exists.
1176     update_from_settings_page_ = true;
1177     expected_id_ = installed_extension->id();
1178     install_source_ = installed_extension->location();
1179     install_cause_ = extension_misc::INSTALL_CAUSE_UPDATE;
1180   }
1181 }
1182 
ConfirmReEnable()1183 void CrxInstaller::ConfirmReEnable() {
1184   DCHECK_CURRENTLY_ON(BrowserThread::UI);
1185 
1186   ExtensionService* service = service_weak_.get();
1187   if (!service || service->browser_terminating())
1188     return;
1189 
1190   if (!update_from_settings_page_)
1191     return;
1192 
1193   ExtensionPrefs* prefs = ExtensionPrefs::Get(service->profile());
1194   if (!prefs->DidExtensionEscalatePermissions(extension()->id()))
1195     return;
1196 
1197   if (client_) {
1198     AddRef();  // Balanced in OnInstallPromptDone().
1199     ExtensionInstallPrompt::PromptType type =
1200         ExtensionInstallPrompt::GetReEnablePromptTypeForExtension(
1201             service->profile(), extension());
1202     client_->ShowDialog(base::Bind(&CrxInstaller::OnInstallPromptDone, this),
1203                         extension(), nullptr,
1204                         std::make_unique<ExtensionInstallPrompt::Prompt>(type),
1205                         ExtensionInstallPrompt::GetDefaultShowDialogCallback());
1206   }
1207 }
1208 
GetUnpackerTaskRunner()1209 base::SequencedTaskRunner* CrxInstaller::GetUnpackerTaskRunner() {
1210   if (!unpacker_task_runner_) {
1211     bool low_priority =
1212         (creation_flags_ & Extension::WAS_INSTALLED_BY_DEFAULT) &&
1213         !(creation_flags_ & Extension::WAS_INSTALLED_BY_OEM);
1214     unpacker_task_runner_ = GetOneShotFileTaskRunner(
1215         low_priority ? base::TaskPriority::BEST_EFFORT
1216                      : base::TaskPriority::USER_VISIBLE);
1217   }
1218   return unpacker_task_runner_.get();
1219 }
1220 
set_installer_callback(InstallerResultCallback callback)1221 void CrxInstaller::set_installer_callback(InstallerResultCallback callback) {
1222   installer_callback_ = std::move(callback);
1223 }
1224 
set_expectations_verified_callback(ExpectationsVerifiedCallback callback)1225 void CrxInstaller::set_expectations_verified_callback(
1226     ExpectationsVerifiedCallback callback) {
1227   expectations_verified_callback_ = std::move(callback);
1228 }
1229 
1230 }  // namespace extensions
1231