OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/crx_installer.h" | 5 #include "chrome/browser/extensions/crx_installer.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 #include <set> | 8 #include <set> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 scoped_refptr<CrxInstaller> CrxInstaller::Create( | 101 scoped_refptr<CrxInstaller> CrxInstaller::Create( |
102 ExtensionService* service, | 102 ExtensionService* service, |
103 std::unique_ptr<ExtensionInstallPrompt> client, | 103 std::unique_ptr<ExtensionInstallPrompt> client, |
104 const WebstoreInstaller::Approval* approval) { | 104 const WebstoreInstaller::Approval* approval) { |
105 return new CrxInstaller(service->AsWeakPtr(), std::move(client), approval); | 105 return new CrxInstaller(service->AsWeakPtr(), std::move(client), approval); |
106 } | 106 } |
107 | 107 |
108 CrxInstaller::CrxInstaller(base::WeakPtr<ExtensionService> service_weak, | 108 CrxInstaller::CrxInstaller(base::WeakPtr<ExtensionService> service_weak, |
109 std::unique_ptr<ExtensionInstallPrompt> client, | 109 std::unique_ptr<ExtensionInstallPrompt> client, |
110 const WebstoreInstaller::Approval* approval) | 110 const WebstoreInstaller::Approval* approval) |
111 : install_directory_(service_weak->install_directory()), | 111 : profile_(service_weak->profile()), |
| 112 install_directory_(service_weak->install_directory()), |
112 install_source_(Manifest::INTERNAL), | 113 install_source_(Manifest::INTERNAL), |
113 approved_(false), | 114 approved_(false), |
114 hash_check_failed_(false), | 115 hash_check_failed_(false), |
115 expected_manifest_check_level_( | 116 expected_manifest_check_level_( |
116 WebstoreInstaller::MANIFEST_CHECK_LEVEL_STRICT), | 117 WebstoreInstaller::MANIFEST_CHECK_LEVEL_STRICT), |
117 fail_install_if_unexpected_version_(false), | 118 fail_install_if_unexpected_version_(false), |
118 extensions_enabled_(service_weak->extensions_enabled()), | 119 extensions_enabled_(service_weak->extensions_enabled()), |
119 delete_source_(false), | 120 delete_source_(false), |
120 create_app_shortcut_(false), | 121 create_app_shortcut_(false), |
121 service_weak_(service_weak), | 122 service_weak_(service_weak), |
122 // See header file comment on |client_| for why we use a raw pointer here. | 123 // See header file comment on |client_| for why we use a raw pointer here. |
123 client_(client.release()), | 124 client_(client.release()), |
124 apps_require_extension_mime_type_(false), | 125 apps_require_extension_mime_type_(false), |
125 allow_silent_install_(false), | 126 allow_silent_install_(false), |
126 grant_permissions_(true), | 127 grant_permissions_(true), |
127 install_cause_(extension_misc::INSTALL_CAUSE_UNSET), | 128 install_cause_(extension_misc::INSTALL_CAUSE_UNSET), |
128 creation_flags_(Extension::NO_FLAGS), | 129 creation_flags_(Extension::NO_FLAGS), |
129 off_store_install_allow_reason_(OffStoreInstallDisallowed), | 130 off_store_install_allow_reason_(OffStoreInstallDisallowed), |
130 did_handle_successfully_(true), | 131 did_handle_successfully_(true), |
131 error_on_unsupported_requirements_(false), | 132 error_on_unsupported_requirements_(false), |
132 update_from_settings_page_(false), | 133 update_from_settings_page_(false), |
133 install_flags_(kInstallFlagNone), | 134 install_flags_(kInstallFlagNone) { |
134 install_checker_(service_weak->profile()) { | |
135 installer_task_runner_ = service_weak->GetFileTaskRunner(); | 135 installer_task_runner_ = service_weak->GetFileTaskRunner(); |
136 if (!approval) | 136 if (!approval) |
137 return; | 137 return; |
138 | 138 |
139 CHECK(profile()->IsSameProfile(approval->profile)); | 139 CHECK(profile()->IsSameProfile(approval->profile)); |
140 if (client_) { | 140 if (client_) { |
141 client_->install_ui()->SetUseAppInstalledBubble( | 141 client_->install_ui()->SetUseAppInstalledBubble( |
142 approval->use_app_installed_bubble); | 142 approval->use_app_installed_bubble); |
143 client_->install_ui()->SetSkipPostInstallUI(approval->skip_post_install_ui); | 143 client_->install_ui()->SetSkipPostInstallUI(approval->skip_post_install_ui); |
144 } | 144 } |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
348 // manually if they want. | 348 // manually if they want. |
349 delete_source_ = false; | 349 delete_source_ = false; |
350 did_handle_successfully_ = false; | 350 did_handle_successfully_ = false; |
351 | 351 |
352 return CrxInstallError( | 352 return CrxInstallError( |
353 CrxInstallError::ERROR_OFF_STORE, | 353 CrxInstallError::ERROR_OFF_STORE, |
354 l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_DISALLOWED_ON_SITE)); | 354 l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_DISALLOWED_ON_SITE)); |
355 } | 355 } |
356 } | 356 } |
357 | 357 |
358 if (install_checker_.extension()->is_app()) { | 358 if (extension_->is_app()) { |
359 // If the app was downloaded, apps_require_extension_mime_type_ | 359 // If the app was downloaded, apps_require_extension_mime_type_ |
360 // will be set. In this case, check that it was served with the | 360 // will be set. In this case, check that it was served with the |
361 // right mime type. Make an exception for file URLs, which come | 361 // right mime type. Make an exception for file URLs, which come |
362 // from the users computer and have no headers. | 362 // from the users computer and have no headers. |
363 if (!download_url_.SchemeIsFile() && | 363 if (!download_url_.SchemeIsFile() && |
364 apps_require_extension_mime_type_ && | 364 apps_require_extension_mime_type_ && |
365 original_mime_type_ != Extension::kMimeType) { | 365 original_mime_type_ != Extension::kMimeType) { |
366 return CrxInstallError(l10n_util::GetStringFUTF16( | 366 return CrxInstallError(l10n_util::GetStringFUTF16( |
367 IDS_EXTENSION_INSTALL_INCORRECT_APP_CONTENT_TYPE, | 367 IDS_EXTENSION_INSTALL_INCORRECT_APP_CONTENT_TYPE, |
368 base::ASCIIToUTF16(Extension::kMimeType))); | 368 base::ASCIIToUTF16(Extension::kMimeType))); |
(...skipping 12 matching lines...) Expand all Loading... |
381 l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE))); | 381 l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE))); |
382 } | 382 } |
383 | 383 |
384 // For self-hosted apps, verify that the entire extent is on the same | 384 // For self-hosted apps, verify that the entire extent is on the same |
385 // host (or a subdomain of the host) the download happened from. There's | 385 // host (or a subdomain of the host) the download happened from. There's |
386 // no way for us to verify that the app controls any other hosts. | 386 // no way for us to verify that the app controls any other hosts. |
387 URLPattern pattern(UserScript::ValidUserScriptSchemes()); | 387 URLPattern pattern(UserScript::ValidUserScriptSchemes()); |
388 pattern.SetHost(download_url_.host()); | 388 pattern.SetHost(download_url_.host()); |
389 pattern.SetMatchSubdomains(true); | 389 pattern.SetMatchSubdomains(true); |
390 | 390 |
391 URLPatternSet patterns = install_checker_.extension()->web_extent(); | 391 URLPatternSet patterns = extension_->web_extent(); |
392 for (URLPatternSet::const_iterator i = patterns.begin(); | 392 for (URLPatternSet::const_iterator i = patterns.begin(); |
393 i != patterns.end(); ++i) { | 393 i != patterns.end(); ++i) { |
394 if (!pattern.MatchesHost(i->host())) { | 394 if (!pattern.MatchesHost(i->host())) { |
395 return CrxInstallError(l10n_util::GetStringUTF16( | 395 return CrxInstallError(l10n_util::GetStringUTF16( |
396 IDS_EXTENSION_INSTALL_INCORRECT_INSTALL_HOST)); | 396 IDS_EXTENSION_INSTALL_INCORRECT_INSTALL_HOST)); |
397 } | 397 } |
398 } | 398 } |
399 } | 399 } |
400 } | 400 } |
401 | 401 |
(...skipping 22 matching lines...) Expand all Loading... |
424 DCHECK(installer_task_runner_->RunsTasksOnCurrentThread()); | 424 DCHECK(installer_task_runner_->RunsTasksOnCurrentThread()); |
425 | 425 |
426 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallSource", | 426 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallSource", |
427 install_source(), Manifest::NUM_LOCATIONS); | 427 install_source(), Manifest::NUM_LOCATIONS); |
428 | 428 |
429 | 429 |
430 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallCause", | 430 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallCause", |
431 install_cause(), | 431 install_cause(), |
432 extension_misc::NUM_INSTALL_CAUSES); | 432 extension_misc::NUM_INSTALL_CAUSES); |
433 | 433 |
434 install_checker_.set_extension(extension); | 434 extension_ = extension; |
435 temp_dir_ = temp_dir; | 435 temp_dir_ = temp_dir; |
436 if (!install_icon.empty()) | 436 if (!install_icon.empty()) |
437 install_icon_.reset(new SkBitmap(install_icon)); | 437 install_icon_.reset(new SkBitmap(install_icon)); |
438 | 438 |
439 if (original_manifest) | 439 if (original_manifest) |
440 original_manifest_.reset(new Manifest( | 440 original_manifest_.reset(new Manifest( |
441 Manifest::INVALID_LOCATION, | 441 Manifest::INVALID_LOCATION, |
442 std::unique_ptr<base::DictionaryValue>(original_manifest->DeepCopy()))); | 442 std::unique_ptr<base::DictionaryValue>(original_manifest->DeepCopy()))); |
443 | 443 |
444 // We don't have to delete the unpack dir explicity since it is a child of | 444 // We don't have to delete the unpack dir explicity since it is a child of |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
503 base::UTF8ToUTF16(extension()->name()), | 503 base::UTF8ToUTF16(extension()->name()), |
504 base::UTF8ToUTF16(imported_module->name())))); | 504 base::UTF8ToUTF16(imported_module->name())))); |
505 return; | 505 return; |
506 } | 506 } |
507 } | 507 } |
508 } | 508 } |
509 | 509 |
510 // Run the policy, requirements and blacklist checks in parallel. Skip the | 510 // Run the policy, requirements and blacklist checks in parallel. Skip the |
511 // checks if the extension is a bookmark app. | 511 // checks if the extension is a bookmark app. |
512 if (extension()->from_bookmark()) { | 512 if (extension()->from_bookmark()) { |
513 CrxInstaller::OnInstallChecksComplete(0); | 513 ConfirmInstall(); |
514 } else { | 514 } else { |
515 install_checker_.Start( | 515 install_checker_ = |
516 ExtensionInstallChecker::CHECK_ALL, | 516 base::MakeUnique<ExtensionInstallChecker>(profile_, extension_); |
517 false /* fail fast */, | 517 install_checker_->Start( |
| 518 ExtensionInstallChecker::CHECK_ALL, false /* fail fast */, |
518 base::Bind(&CrxInstaller::OnInstallChecksComplete, this)); | 519 base::Bind(&CrxInstaller::OnInstallChecksComplete, this)); |
519 } | 520 } |
520 } | 521 } |
521 | 522 |
522 void CrxInstaller::OnInstallChecksComplete(int failed_checks) { | 523 void CrxInstaller::OnInstallChecksComplete(int failed_checks) { |
523 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 524 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
524 if (!service_weak_) | 525 if (!service_weak_) |
525 return; | 526 return; |
526 | 527 |
527 // Check for requirement errors. | 528 // Check for requirement errors. |
528 if (!install_checker_.requirement_errors().empty()) { | 529 if (!install_checker_->requirement_errors().empty()) { |
529 if (error_on_unsupported_requirements_) { | 530 if (error_on_unsupported_requirements_) { |
530 ReportFailureFromUIThread( | 531 ReportFailureFromUIThread( |
531 CrxInstallError(CrxInstallError::ERROR_DECLINED, | 532 CrxInstallError(CrxInstallError::ERROR_DECLINED, |
532 base::UTF8ToUTF16(base::JoinString( | 533 base::UTF8ToUTF16(base::JoinString( |
533 install_checker_.requirement_errors(), " ")))); | 534 install_checker_->requirement_errors(), " ")))); |
534 return; | 535 return; |
535 } | 536 } |
536 install_flags_ |= kInstallFlagHasRequirementErrors; | 537 install_flags_ |= kInstallFlagHasRequirementErrors; |
537 } | 538 } |
538 | 539 |
539 // Check the blacklist state. | 540 // Check the blacklist state. |
540 if (install_checker_.blacklist_state() == BLACKLISTED_MALWARE) { | 541 if (install_checker_->blacklist_state() == BLACKLISTED_MALWARE) { |
541 install_flags_ |= kInstallFlagIsBlacklistedForMalware; | 542 install_flags_ |= kInstallFlagIsBlacklistedForMalware; |
542 } | 543 } |
543 | 544 |
544 if ((install_checker_.blacklist_state() == BLACKLISTED_MALWARE || | 545 if ((install_checker_->blacklist_state() == BLACKLISTED_MALWARE || |
545 install_checker_.blacklist_state() == BLACKLISTED_UNKNOWN) && | 546 install_checker_->blacklist_state() == BLACKLISTED_UNKNOWN) && |
546 !allow_silent_install_) { | 547 !allow_silent_install_) { |
547 // User tried to install a blacklisted extension. Show an error and | 548 // User tried to install a blacklisted extension. Show an error and |
548 // refuse to install it. | 549 // refuse to install it. |
549 ReportFailureFromUIThread(CrxInstallError( | 550 ReportFailureFromUIThread(CrxInstallError( |
550 CrxInstallError::ERROR_DECLINED, | 551 CrxInstallError::ERROR_DECLINED, |
551 l10n_util::GetStringFUTF16(IDS_EXTENSION_IS_BLACKLISTED, | 552 l10n_util::GetStringFUTF16(IDS_EXTENSION_IS_BLACKLISTED, |
552 base::UTF8ToUTF16(extension()->name())))); | 553 base::UTF8ToUTF16(extension()->name())))); |
553 UMA_HISTOGRAM_ENUMERATION("ExtensionBlacklist.BlockCRX", | 554 UMA_HISTOGRAM_ENUMERATION("ExtensionBlacklist.BlockCRX", |
554 extension()->location(), | 555 extension()->location(), |
555 Manifest::NUM_LOCATIONS); | 556 Manifest::NUM_LOCATIONS); |
556 return; | 557 return; |
557 } | 558 } |
558 | 559 |
559 // NOTE: extension may still be blacklisted, but we're forced to silently | 560 // NOTE: extension may still be blacklisted, but we're forced to silently |
560 // install it. In this case, ExtensionService::OnExtensionInstalled needs to | 561 // install it. In this case, ExtensionService::OnExtensionInstalled needs to |
561 // deal with it. | 562 // deal with it. |
562 | 563 |
563 // Check for policy errors. | 564 // Check for policy errors. |
564 if (!install_checker_.policy_error().empty()) { | 565 if (!install_checker_->policy_error().empty()) { |
565 // We don't want to show the error infobar for installs from the WebStore, | 566 // We don't want to show the error infobar for installs from the WebStore, |
566 // because the WebStore already shows an error dialog itself. | 567 // because the WebStore already shows an error dialog itself. |
567 // Note: |client_| can be NULL in unit_tests! | 568 // Note: |client_| can be NULL in unit_tests! |
568 if (extension()->from_webstore() && client_) | 569 if (extension()->from_webstore() && client_) |
569 client_->install_ui()->SetSkipPostInstallUI(true); | 570 client_->install_ui()->SetSkipPostInstallUI(true); |
570 ReportFailureFromUIThread( | 571 ReportFailureFromUIThread( |
571 CrxInstallError(CrxInstallError::ERROR_DECLINED, | 572 CrxInstallError(CrxInstallError::ERROR_DECLINED, |
572 base::UTF8ToUTF16(install_checker_.policy_error()))); | 573 base::UTF8ToUTF16(install_checker_->policy_error()))); |
573 return; | 574 return; |
574 } | 575 } |
575 | 576 |
576 ConfirmInstall(); | 577 ConfirmInstall(); |
577 } | 578 } |
578 | 579 |
579 void CrxInstaller::ConfirmInstall() { | 580 void CrxInstaller::ConfirmInstall() { |
580 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 581 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
581 ExtensionService* service = service_weak_.get(); | 582 ExtensionService* service = service_weak_.get(); |
582 if (!service || service->browser_terminating()) | 583 if (!service || service->browser_terminating()) |
583 return; | 584 return; |
584 | 585 |
585 if (KioskModeInfo::IsKioskOnly(install_checker_.extension().get())) { | 586 if (KioskModeInfo::IsKioskOnly(extension())) { |
586 bool in_kiosk_mode = false; | 587 bool in_kiosk_mode = false; |
587 #if defined(OS_CHROMEOS) | 588 #if defined(OS_CHROMEOS) |
588 user_manager::UserManager* user_manager = user_manager::UserManager::Get(); | 589 user_manager::UserManager* user_manager = user_manager::UserManager::Get(); |
589 in_kiosk_mode = user_manager && user_manager->IsLoggedInAsKioskApp(); | 590 in_kiosk_mode = user_manager && user_manager->IsLoggedInAsKioskApp(); |
590 #endif | 591 #endif |
591 if (!in_kiosk_mode) { | 592 if (!in_kiosk_mode) { |
592 ReportFailureFromUIThread(CrxInstallError( | 593 ReportFailureFromUIThread(CrxInstallError( |
593 CrxInstallError::ERROR_DECLINED, | 594 CrxInstallError::ERROR_DECLINED, |
594 l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_KIOSK_MODE_ONLY))); | 595 l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_KIOSK_MODE_ONLY))); |
595 return; | 596 return; |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
714 | 715 |
715 // This is lame, but we must reload the extension because absolute paths | 716 // This is lame, but we must reload the extension because absolute paths |
716 // inside the content scripts are established inside InitFromValue() and we | 717 // inside the content scripts are established inside InitFromValue() and we |
717 // just moved the extension. | 718 // just moved the extension. |
718 // TODO(aa): All paths to resources inside extensions should be created | 719 // TODO(aa): All paths to resources inside extensions should be created |
719 // lazily and based on the Extension's root path at that moment. | 720 // lazily and based on the Extension's root path at that moment. |
720 // TODO(rdevlin.cronin): Continue removing std::string errors and replacing | 721 // TODO(rdevlin.cronin): Continue removing std::string errors and replacing |
721 // with base::string16 | 722 // with base::string16 |
722 std::string extension_id = extension()->id(); | 723 std::string extension_id = extension()->id(); |
723 std::string error; | 724 std::string error; |
724 install_checker_.set_extension( | 725 extension_ = file_util::LoadExtension( |
725 file_util::LoadExtension( | 726 version_dir, install_source_, |
726 version_dir, | 727 // Note: modified by UpdateCreationFlagsAndCompleteInstall. |
727 install_source_, | 728 creation_flags_, &error); |
728 // Note: modified by UpdateCreationFlagsAndCompleteInstall. | |
729 creation_flags_, | |
730 &error).get()); | |
731 | 729 |
732 if (extension()) { | 730 if (extension()) { |
733 ReportSuccessFromFileThread(); | 731 ReportSuccessFromFileThread(); |
734 } else { | 732 } else { |
735 LOG(ERROR) << error << " " << extension_id << " " << download_url_; | 733 LOG(ERROR) << error << " " << extension_id << " " << download_url_; |
736 ReportFailureFromFileThread(CrxInstallError(base::UTF8ToUTF16(error))); | 734 ReportFailureFromFileThread(CrxInstallError(base::UTF8ToUTF16(error))); |
737 } | 735 } |
738 } | 736 } |
739 | 737 |
740 void CrxInstaller::ReportFailureFromFileThread(const CrxInstallError& error) { | 738 void CrxInstaller::ReportFailureFromFileThread(const CrxInstallError& error) { |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
908 ExtensionInstallPrompt::GetReEnablePromptTypeForExtension( | 906 ExtensionInstallPrompt::GetReEnablePromptTypeForExtension( |
909 service->profile(), extension()); | 907 service->profile(), extension()); |
910 client_->ShowDialog(base::Bind(&CrxInstaller::OnInstallPromptDone, this), | 908 client_->ShowDialog(base::Bind(&CrxInstaller::OnInstallPromptDone, this), |
911 extension(), nullptr, | 909 extension(), nullptr, |
912 base::MakeUnique<ExtensionInstallPrompt::Prompt>(type), | 910 base::MakeUnique<ExtensionInstallPrompt::Prompt>(type), |
913 ExtensionInstallPrompt::GetDefaultShowDialogCallback()); | 911 ExtensionInstallPrompt::GetDefaultShowDialogCallback()); |
914 } | 912 } |
915 } | 913 } |
916 | 914 |
917 } // namespace extensions | 915 } // namespace extensions |
OLD | NEW |