Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2011 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 #ifndef CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_
      6 #define CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_
      7 #pragma once
      8 
      9 #include <string>
     10 
     11 #include "base/file_path.h"
     12 #include "base/memory/ref_counted.h"
     13 #include "base/version.h"
     14 #include "chrome/browser/extensions/extension_install_ui.h"
     15 #include "chrome/browser/extensions/sandboxed_extension_unpacker.h"
     16 #include "chrome/common/extensions/extension.h"
     17 #include "chrome/common/web_apps.h"
     18 
     19 class ExtensionService;
     20 class SkBitmap;
     21 
     22 // This class installs a crx file into a profile.
     23 //
     24 // Installing a CRX is a multi-step process, including unpacking the crx,
     25 // validating it, prompting the user, and installing. Since many of these
     26 // steps must occur on the file thread, this class contains a copy of all data
     27 // necessary to do its job. (This also minimizes external dependencies for
     28 // easier testing).
     29 //
     30 // Lifetime management:
     31 //
     32 // This class is ref-counted by each call it makes to itself on another thread,
     33 // and by UtilityProcessHost.
     34 //
     35 // Additionally, we hold a reference to our own client so that it lives at least
     36 // long enough to receive the result of unpacking.
     37 //
     38 // IMPORTANT: Callers should keep a reference to a CrxInstaller while they are
     39 // working with it, eg:
     40 //
     41 // scoped_refptr<CrxInstaller> installer(new CrxInstaller(...));
     42 // installer->set_foo();
     43 // installer->set_bar();
     44 // installer->InstallCrx(...);
     45 class CrxInstaller
     46     : public SandboxedExtensionUnpackerClient,
     47       public ExtensionInstallUI::Delegate {
     48  public:
     49 
     50   // This is pretty lame, but given the difficulty of connecting a particular
     51   // ExtensionFunction to a resulting download in the download manager, it's
     52   // currently necessary. This is the |id| of an extension to be installed
     53   // *by the web store only* which should not get the permissions install
     54   // prompt. This should only be called on the UI thread.
     55   // crbug.com/54916
     56   static void SetWhitelistedInstallId(const std::string& id);
     57 
     58   // Exempt the next extension install with |id| from displaying a confirmation
     59   // prompt, since the user already agreed to the install via
     60   // beginInstallWithManifest. We require that the extension manifest matches
     61   // |parsed_manifest| which is what was used to prompt with. Ownership of
     62   // |parsed_manifest| is transferred here.
     63   static void SetWhitelistedManifest(const std::string& id,
     64                                      DictionaryValue* parsed_manifest);
     65 
     66   // Returns the previously stored manifest from a call to
     67   // SetWhitelistedManifest.
     68   static const DictionaryValue* GetWhitelistedManifest(const std::string& id);
     69 
     70   // Removes any whitelisted manifest for |id| and returns it. The caller owns
     71   // the return value and is responsible for deleting it.
     72   static DictionaryValue* RemoveWhitelistedManifest(const std::string& id);
     73 
     74   // Returns whether |id| is whitelisted - only call this on the UI thread.
     75   static bool IsIdWhitelisted(const std::string& id);
     76 
     77   // Returns whether |id| was found and removed (was whitelisted). This should
     78   // only be called on the UI thread.
     79   static bool ClearWhitelistedInstallId(const std::string& id);
     80 
     81   // Constructor.  Extensions will be installed into
     82   // frontend->install_directory() then registered with |frontend|. Any install
     83   // UI will be displayed using |client|. Pass NULL for |client| for silent
     84   // install.
     85   CrxInstaller(ExtensionService* frontend,
     86                ExtensionInstallUI* client);
     87 
     88   // Install the crx in |source_file|.
     89   void InstallCrx(const FilePath& source_file);
     90 
     91   // Convert the specified user script into an extension and install it.
     92   void InstallUserScript(const FilePath& source_file,
     93                          const GURL& original_url);
     94 
     95   // Convert the specified web app into an extension and install it.
     96   void InstallWebApp(const WebApplicationInfo& web_app);
     97 
     98   // Overridden from ExtensionInstallUI::Delegate:
     99   virtual void InstallUIProceed();
    100   virtual void InstallUIAbort();
    101 
    102   const GURL& original_url() const { return original_url_; }
    103   void set_original_url(const GURL& val) { original_url_ = val; }
    104 
    105   Extension::Location install_source() const { return install_source_; }
    106   void set_install_source(Extension::Location source) {
    107     install_source_ = source;
    108   }
    109 
    110   const std::string& expected_id() const { return expected_id_; }
    111   void set_expected_id(const std::string& val) { expected_id_ = val; }
    112 
    113   void set_expected_version(const Version& val) {
    114     expected_version_.reset(val.Clone());
    115   }
    116 
    117   bool delete_source() const { return delete_source_; }
    118   void set_delete_source(bool val) { delete_source_ = val; }
    119 
    120   bool allow_silent_install() const { return allow_silent_install_; }
    121   void set_allow_silent_install(bool val) { allow_silent_install_ = val; }
    122 
    123   bool is_gallery_install() const { return is_gallery_install_; }
    124   void set_is_gallery_install(bool val) { is_gallery_install_ = val; }
    125 
    126   // If |apps_require_extension_mime_type_| is set to true, be sure to set
    127   // |original_mime_type_| as well.
    128   void set_apps_require_extension_mime_type(
    129       bool apps_require_extension_mime_type) {
    130     apps_require_extension_mime_type_ = apps_require_extension_mime_type;
    131   }
    132 
    133   void set_original_mime_type(const std::string& original_mime_type) {
    134     original_mime_type_ = original_mime_type;
    135   }
    136 
    137  private:
    138   ~CrxInstaller();
    139 
    140   // Converts the source user script to an extension.
    141   void ConvertUserScriptOnFileThread();
    142 
    143   // Converts the source web app to an extension.
    144   void ConvertWebAppOnFileThread(const WebApplicationInfo& web_app);
    145 
    146   // Called after OnUnpackSuccess as a last check to see whether the install
    147   // should complete.
    148   bool AllowInstall(const Extension* extension, std::string* error);
    149 
    150   // SandboxedExtensionUnpackerClient
    151   virtual void OnUnpackFailure(const std::string& error_message);
    152   virtual void OnUnpackSuccess(const FilePath& temp_dir,
    153                                const FilePath& extension_dir,
    154                                const Extension* extension);
    155 
    156   // Returns true if we can skip confirmation because the install was
    157   // whitelisted.
    158   bool CanSkipConfirmation();
    159 
    160   // Runs on the UI thread. Confirms with the user (via ExtensionInstallUI) that
    161   // it is OK to install this extension.
    162   void ConfirmInstall();
    163 
    164   // Runs on File thread. Install the unpacked extension into the profile and
    165   // notify the frontend.
    166   void CompleteInstall();
    167 
    168   // Result reporting.
    169   void ReportFailureFromFileThread(const std::string& error);
    170   void ReportFailureFromUIThread(const std::string& error);
    171   void ReportSuccessFromFileThread();
    172   void ReportSuccessFromUIThread();
    173 
    174   // The file we're installing.
    175   FilePath source_file_;
    176 
    177   // The URL the file was downloaded from.
    178   GURL original_url_;
    179 
    180   // The directory extensions are installed to.
    181   FilePath install_directory_;
    182 
    183   // The location the installation came from (bundled with Chromium, registry,
    184   // manual install, etc). This metadata is saved with the installation if
    185   // successful. Defaults to INTERNAL.
    186   Extension::Location install_source_;
    187 
    188   // For updates and external installs we have an ID we're expecting the
    189   // extension to contain.
    190   std::string expected_id_;
    191 
    192   // If non-NULL, contains the expected version of the extension we're
    193   // installing.  Important for external sources, where claiming the wrong
    194   // version could cause unnessisary unpacking of an extension at every
    195   // restart.
    196   scoped_ptr<Version> expected_version_;
    197 
    198   // Whether manual extension installation is enabled. We can't just check this
    199   // before trying to install because themes are special-cased to always be
    200   // allowed.
    201   bool extensions_enabled_;
    202 
    203   // Whether we're supposed to delete the source file on destruction. Defaults
    204   // to false.
    205   bool delete_source_;
    206 
    207   // Whether the install originated from the gallery.
    208   bool is_gallery_install_;
    209 
    210   // Whether to create an app shortcut after successful installation. This is
    211   // set based on the user's selection in the UI and can only ever be true for
    212   // apps.
    213   bool create_app_shortcut_;
    214 
    215   // The extension we're installing. We own this and either pass it off to
    216   // ExtensionService on success, or delete it on failure.
    217   scoped_refptr<const Extension> extension_;
    218 
    219   // If non-empty, contains the current version of the extension we're
    220   // installing (for upgrades).
    221   std::string current_version_;
    222 
    223   // The icon we will display in the installation UI, if any.
    224   scoped_ptr<SkBitmap> install_icon_;
    225 
    226   // The temp directory extension resources were unpacked to. We own this and
    227   // must delete it when we are done with it.
    228   FilePath temp_dir_;
    229 
    230   // The frontend we will report results back to.
    231   scoped_refptr<ExtensionService> frontend_;
    232 
    233   // The client we will work with to do the installation. This can be NULL, in
    234   // which case the install is silent.
    235   // NOTE: we may be deleted on the file thread. To ensure the UI is deleted on
    236   // the main thread we don't use a scoped_ptr here.
    237   ExtensionInstallUI* client_;
    238 
    239   // The root of the unpacked extension directory. This is a subdirectory of
    240   // temp_dir_, so we don't have to delete it explicitly.
    241   FilePath unpacked_extension_root_;
    242 
    243   // True when the CRX being installed was just downloaded.
    244   // Used to trigger extra checks before installing.
    245   bool apps_require_extension_mime_type_;
    246 
    247   // Allows for the possibility of a normal install (one in which a |client|
    248   // is provided in the ctor) to procede without showing the permissions prompt
    249   // dialog. Note that this will only take place if |allow_silent_install_|
    250   // is true AND the unpacked id of the extension is whitelisted with
    251   // SetWhitelistedInstallId().
    252   bool allow_silent_install_;
    253 
    254   // The value of the content type header sent with the CRX.
    255   // Ignorred unless |require_extension_mime_type_| is true.
    256   std::string original_mime_type_;
    257 
    258   DISALLOW_COPY_AND_ASSIGN(CrxInstaller);
    259 };
    260 
    261 #endif  // CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_
    262