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_management.h"
     13 #include "chrome/browser/extensions/webstore_installer.h"
     14 #include "chrome/browser/profiles/profile.h"
     15 #include "chrome/browser/ui/browser_finder.h"
     16 #include "chrome/browser/ui/host_desktop.h"
     17 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     18 #include "content/public/browser/download_item.h"
     19 #include "content/public/browser/notification_service.h"
     20 #include "extensions/browser/extension_system.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> CreateCrxInstaller(
     73     Profile* profile,
     74     const content::DownloadItem& download_item) {
     75   ExtensionService* service = extensions::ExtensionSystem::Get(profile)->
     76       extension_service();
     77   CHECK(service);
     78 
     79   scoped_refptr<extensions::CrxInstaller> installer(
     80       extensions::CrxInstaller::Create(
     81           service,
     82           CreateExtensionInstallPrompt(profile, download_item),
     83           WebstoreInstaller::GetAssociatedApproval(download_item)));
     84 
     85   installer->set_error_on_unsupported_requirements(true);
     86   installer->set_delete_source(true);
     87   installer->set_install_cause(extension_misc::INSTALL_CAUSE_USER_DOWNLOAD);
     88   installer->set_original_mime_type(download_item.GetOriginalMimeType());
     89   installer->set_apps_require_extension_mime_type(true);
     90 
     91   return installer;
     92 }
     93 
     94 scoped_refptr<extensions::CrxInstaller> OpenChromeExtension(
     95     Profile* profile,
     96     const DownloadItem& download_item) {
     97   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     98 
     99   scoped_refptr<extensions::CrxInstaller> installer(
    100       CreateCrxInstaller(profile, download_item));
    101 
    102   if (OffStoreInstallAllowedByPrefs(profile, download_item)) {
    103     installer->set_off_store_install_allow_reason(
    104         extensions::CrxInstaller::OffStoreInstallAllowedBecausePref);
    105   }
    106 
    107   if (extensions::UserScript::IsURLUserScript(download_item.GetURL(),
    108                                               download_item.GetMimeType())) {
    109     installer->InstallUserScript(download_item.GetFullPath(),
    110                                  download_item.GetURL());
    111   } else {
    112     DCHECK(!WebstoreInstaller::GetAssociatedApproval(download_item));
    113     installer->InstallCrx(download_item.GetFullPath());
    114   }
    115 
    116   return installer;
    117 }
    118 
    119 bool IsExtensionDownload(const DownloadItem& download_item) {
    120   if (download_item.GetTargetDisposition() ==
    121       DownloadItem::TARGET_DISPOSITION_PROMPT)
    122     return false;
    123 
    124   if (download_item.GetMimeType() == extensions::Extension::kMimeType ||
    125       extensions::UserScript::IsURLUserScript(download_item.GetURL(),
    126                                               download_item.GetMimeType())) {
    127     return true;
    128   } else {
    129     return false;
    130   }
    131 }
    132 
    133 bool OffStoreInstallAllowedByPrefs(Profile* profile, const DownloadItem& item) {
    134   // TODO(aa): RefererURL is cleared in some cases, for example when going
    135   // between secure and non-secure URLs. It would be better if DownloadItem
    136   // tracked the initiating page explicitly.
    137   return extensions::ExtensionManagementFactory::GetForBrowserContext(profile)
    138       ->IsOffstoreInstallAllowed(item.GetURL(), item.GetReferrerUrl());
    139 }
    140 
    141 }  // namespace download_crx_util
    142