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
19class ExtensionService;
20class 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(...);
45class 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