Home | History | Annotate | Download | only in download
      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 // Download code which handles CRX files (extensions, themes, apps, ...).
      6 
      7 #include "chrome/browser/download/download_crx_util.h"
      8 
      9 #include "chrome/browser/chrome_notification_types.h"
     10 #include "chrome/browser/extensions/crx_installer.h"
     11 #include "chrome/browser/extensions/extension_install_prompt.h"
     12 #include "chrome/browser/extensions/extension_service.h"
     13 #include "chrome/browser/extensions/extension_system.h"
     14 #include "chrome/browser/extensions/webstore_installer.h"
     15 #include "chrome/browser/profiles/profile.h"
     16 #include "chrome/browser/ui/browser_finder.h"
     17 #include "chrome/browser/ui/host_desktop.h"
     18 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     19 #include "content/public/browser/download_item.h"
     20 #include "content/public/browser/notification_service.h"
     21 #include "extensions/common/user_script.h"
     22 
     23 using content::BrowserThread;
     24 using content::DownloadItem;
     25 using extensions::WebstoreInstaller;
     26 
     27 namespace download_crx_util {
     28 
     29 namespace {
     30 
     31 // Hold a mock ExtensionInstallPrompt object that will be used when the
     32 // download system opens a CRX.
     33 ExtensionInstallPrompt* mock_install_prompt_for_testing = NULL;
     34 
     35 // Called to get an extension install UI object.  In tests, will return
     36 // a mock if the test calls download_util::SetMockInstallPromptForTesting()
     37 // to set one.
     38 scoped_ptr<ExtensionInstallPrompt> CreateExtensionInstallPrompt(
     39     Profile* profile,
     40     const DownloadItem& download_item) {
     41   // Use a mock if one is present.  Otherwise, create a real extensions
     42   // install UI.
     43   if (mock_install_prompt_for_testing) {
     44     ExtensionInstallPrompt* result = mock_install_prompt_for_testing;
     45     mock_install_prompt_for_testing = NULL;
     46     return scoped_ptr<ExtensionInstallPrompt>(result);
     47   } else {
     48     content::WebContents* web_contents = download_item.GetWebContents();
     49     if (!web_contents) {
     50       chrome::HostDesktopType active_desktop = chrome::GetActiveDesktop();
     51       Browser* browser = chrome::FindLastActiveWithProfile(profile,
     52           active_desktop);
     53       if (!browser)
     54         browser = new Browser(Browser::CreateParams(Browser::TYPE_TABBED,
     55                                                     profile, active_desktop));
     56       web_contents = browser->tab_strip_model()->GetActiveWebContents();
     57     }
     58     return scoped_ptr<ExtensionInstallPrompt>(
     59         new ExtensionInstallPrompt(web_contents));
     60   }
     61 }
     62 
     63 }  // namespace
     64 
     65 // Tests can call this method to inject a mock ExtensionInstallPrompt
     66 // to be used to confirm permissions on a downloaded CRX.
     67 void SetMockInstallPromptForTesting(
     68     scoped_ptr<ExtensionInstallPrompt> mock_prompt) {
     69   mock_install_prompt_for_testing = mock_prompt.release();
     70 }
     71 
     72 scoped_refptr<extensions::CrxInstaller> OpenChromeExtension(
     73     Profile* profile,
     74     const DownloadItem& download_item) {
     75   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     76 
     77   ExtensionService* service = extensions::ExtensionSystem::Get(profile)->
     78       extension_service();
     79   CHECK(service);
     80 
     81   scoped_refptr<extensions::CrxInstaller> installer(
     82       extensions::CrxInstaller::Create(
     83           service,
     84           CreateExtensionInstallPrompt(profile, download_item),
     85           WebstoreInstaller::GetAssociatedApproval(download_item)));
     86 
     87   installer->set_error_on_unsupported_requirements(true);
     88   installer->set_delete_source(true);
     89   installer->set_install_cause(extension_misc::INSTALL_CAUSE_USER_DOWNLOAD);
     90 
     91   if (OffStoreInstallAllowedByPrefs(profile, download_item)) {
     92     installer->set_off_store_install_allow_reason(
     93         extensions::CrxInstaller::OffStoreInstallAllowedBecausePref);
     94   }
     95 
     96   if (extensions::UserScript::IsURLUserScript(download_item.GetURL(),
     97                                               download_item.GetMimeType())) {
     98     installer->InstallUserScript(download_item.GetFullPath(),
     99                                  download_item.GetURL());
    100   } else {
    101     bool is_gallery_download =
    102         WebstoreInstaller::GetAssociatedApproval(download_item) != NULL;
    103     installer->set_original_mime_type(download_item.GetOriginalMimeType());
    104     installer->set_apps_require_extension_mime_type(true);
    105     installer->set_download_url(download_item.GetURL());
    106     installer->set_is_gallery_install(is_gallery_download);
    107     if (is_gallery_download)
    108       installer->set_original_download_url(download_item.GetOriginalUrl());
    109     installer->set_allow_silent_install(is_gallery_download);
    110     installer->InstallCrx(download_item.GetFullPath());
    111   }
    112 
    113   return installer;
    114 }
    115 
    116 bool IsExtensionDownload(const DownloadItem& download_item) {
    117   if (download_item.GetTargetDisposition() ==
    118       DownloadItem::TARGET_DISPOSITION_PROMPT)
    119     return false;
    120 
    121   if (download_item.GetMimeType() == extensions::Extension::kMimeType ||
    122       extensions::UserScript::IsURLUserScript(download_item.GetURL(),
    123                                               download_item.GetMimeType())) {
    124     return true;
    125   } else {
    126     return false;
    127   }
    128 }
    129 
    130 bool OffStoreInstallAllowedByPrefs(Profile* profile, const DownloadItem& item) {
    131   ExtensionService* service = extensions::ExtensionSystem::Get(
    132       profile)->extension_service();
    133   if (!service)
    134     return false;
    135 
    136   extensions::ExtensionPrefs* prefs = service->extension_prefs();
    137   CHECK(prefs);
    138 
    139   extensions::URLPatternSet url_patterns = prefs->GetAllowedInstallSites();
    140 
    141   if (!url_patterns.MatchesURL(item.GetURL()))
    142     return false;
    143 
    144   // The referrer URL must also be whitelisted, unless the URL has the file
    145   // scheme (there's no referrer for those URLs).
    146   // TODO(aa): RefererURL is cleared in some cases, for example when going
    147   // between secure and non-secure URLs. It would be better if DownloadItem
    148   // tracked the initiating page explicitly.
    149   return url_patterns.MatchesURL(item.GetReferrerUrl()) ||
    150          item.GetURL().SchemeIsFile();
    151 }
    152 
    153 }  // namespace download_crx_util
    154