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#ifndef CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_
6#define CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_
7
8#include <string>
9
10#include "base/compiler_specific.h"
11#include "base/files/file_path.h"
12#include "base/memory/ref_counted.h"
13#include "base/memory/weak_ptr.h"
14#include "base/version.h"
15#include "chrome/browser/extensions/blacklist.h"
16#include "chrome/browser/extensions/extension_install_prompt.h"
17#include "chrome/browser/extensions/extension_installer.h"
18#include "chrome/browser/extensions/sandboxed_unpacker.h"
19#include "chrome/browser/extensions/webstore_installer.h"
20#include "chrome/common/extensions/extension.h"
21#include "chrome/common/extensions/manifest.h"
22#include "sync/api/string_ordinal.h"
23
24class ExtensionService;
25class ExtensionServiceTest;
26class SkBitmap;
27struct WebApplicationInfo;
28
29namespace base {
30class SequencedTaskRunner;
31}
32
33namespace extensions {
34class CrxInstallerError;
35class ExtensionUpdaterTest;
36class RequirementsChecker;
37
38// This class installs a crx file into a profile.
39//
40// Installing a CRX is a multi-step process, including unpacking the crx,
41// validating it, prompting the user, and installing. Since many of these
42// steps must occur on the file thread, this class contains a copy of all data
43// necessary to do its job. (This also minimizes external dependencies for
44// easier testing).
45//
46// Lifetime management:
47//
48// This class is ref-counted by each call it makes to itself on another thread,
49// and by UtilityProcessHost.
50//
51// Additionally, we hold a reference to our own client so that it lives at least
52// long enough to receive the result of unpacking.
53//
54// IMPORTANT: Callers should keep a reference to a CrxInstaller while they are
55// working with it, eg:
56//
57// scoped_refptr<CrxInstaller> installer(new CrxInstaller(...));
58// installer->set_foo();
59// installer->set_bar();
60// installer->InstallCrx(...);
61//
62// Installation is aborted if the extension service learns that Chrome is
63// terminating during the install. We can't listen for the app termination
64// notification here in this class because it can be destroyed on any thread
65// and won't safely be able to clean up UI thread notification listeners.
66class CrxInstaller
67    : public SandboxedUnpackerClient,
68      public ExtensionInstallPrompt::Delegate {
69 public:
70  // Used in histograms; do not change order.
71  enum OffStoreInstallAllowReason {
72    OffStoreInstallDisallowed,
73    OffStoreInstallAllowedFromSettingsPage,
74    OffStoreInstallAllowedBecausePref,
75    OffStoreInstallAllowedInTest,
76    NumOffStoreInstallAllowReasons
77  };
78
79  // Extensions will be installed into service->install_directory(), then
80  // registered with |service|. This does a silent install - see below for
81  // other options.
82  static scoped_refptr<CrxInstaller> CreateSilent(ExtensionService* service);
83
84  // Same as above, but use |client| to generate a confirmation prompt.
85  static scoped_refptr<CrxInstaller> Create(
86      ExtensionService* service,
87      scoped_ptr<ExtensionInstallPrompt> client);
88
89  // Same as the previous method, except use the |approval| to bypass the
90  // prompt. Note that the caller retains ownership of |approval|.
91  static scoped_refptr<CrxInstaller> Create(
92      ExtensionService* service,
93      scoped_ptr<ExtensionInstallPrompt> client,
94      const WebstoreInstaller::Approval* approval);
95
96  // Install the crx in |source_file|.
97  void InstallCrx(const base::FilePath& source_file);
98
99  // Convert the specified user script into an extension and install it.
100  void InstallUserScript(const base::FilePath& source_file,
101                         const GURL& download_url);
102
103  // Convert the specified web app into an extension and install it.
104  void InstallWebApp(const WebApplicationInfo& web_app);
105
106  // Overridden from ExtensionInstallPrompt::Delegate:
107  virtual void InstallUIProceed() OVERRIDE;
108  virtual void InstallUIAbort(bool user_initiated) OVERRIDE;
109
110  int creation_flags() const { return creation_flags_; }
111  void set_creation_flags(int val) { creation_flags_ = val; }
112
113  const GURL& download_url() const { return download_url_; }
114  void set_download_url(const GURL& val) { download_url_ = val; }
115
116  const base::FilePath& source_file() const { return source_file_; }
117
118  Manifest::Location install_source() const {
119    return install_source_;
120  }
121  void set_install_source(Manifest::Location source) {
122    install_source_ = source;
123  }
124
125  const std::string& expected_id() const { return expected_id_; }
126  void set_expected_id(const std::string& val) { expected_id_ = val; }
127
128  void set_expected_version(const Version& val) {
129    expected_version_.reset(new Version(val));
130  }
131
132  bool delete_source() const { return delete_source_; }
133  void set_delete_source(bool val) { delete_source_ = val; }
134
135  bool allow_silent_install() const { return allow_silent_install_; }
136  void set_allow_silent_install(bool val) { allow_silent_install_ = val; }
137
138  bool is_gallery_install() const {
139    return (creation_flags_ & Extension::FROM_WEBSTORE) > 0;
140  }
141  void set_is_gallery_install(bool val) {
142    if (val)
143      creation_flags_ |= Extension::FROM_WEBSTORE;
144    else
145      creation_flags_ &= ~Extension::FROM_WEBSTORE;
146  }
147
148  // The original download URL should be set when the WebstoreInstaller is
149  // tracking the installation. The WebstoreInstaller uses this URL to match
150  // failure notifications to the extension.
151  const GURL& original_download_url() const { return original_download_url_; }
152  void set_original_download_url(const GURL& url) {
153    original_download_url_ = url;
154  }
155
156  // If |apps_require_extension_mime_type_| is set to true, be sure to set
157  // |original_mime_type_| as well.
158  void set_apps_require_extension_mime_type(
159      bool apps_require_extension_mime_type) {
160    apps_require_extension_mime_type_ = apps_require_extension_mime_type;
161  }
162
163  void set_original_mime_type(const std::string& original_mime_type) {
164    original_mime_type_ = original_mime_type;
165  }
166
167  extension_misc::CrxInstallCause install_cause() const {
168    return install_cause_;
169  }
170  void set_install_cause(extension_misc::CrxInstallCause install_cause) {
171    install_cause_ = install_cause;
172  }
173
174  OffStoreInstallAllowReason off_store_install_allow_reason() const {
175    return off_store_install_allow_reason_;
176  }
177  void set_off_store_install_allow_reason(OffStoreInstallAllowReason reason) {
178    off_store_install_allow_reason_ = reason;
179  }
180
181  void set_page_ordinal(const syncer::StringOrdinal& page_ordinal) {
182    page_ordinal_ = page_ordinal;
183  }
184
185  void set_error_on_unsupported_requirements(bool val) {
186    error_on_unsupported_requirements_ = val;
187  }
188
189  void set_install_wait_for_idle(bool val) {
190    install_wait_for_idle_ = val;
191  }
192
193  bool did_handle_successfully() const { return did_handle_successfully_; }
194
195  Profile* profile() { return installer_.profile(); }
196
197  const Extension* extension() { return installer_.extension().get(); }
198
199 private:
200  friend class ::ExtensionServiceTest;
201  friend class ExtensionUpdaterTest;
202  friend class ExtensionCrxInstallerTest;
203
204  CrxInstaller(base::WeakPtr<ExtensionService> service_weak,
205               scoped_ptr<ExtensionInstallPrompt> client,
206               const WebstoreInstaller::Approval* approval);
207  virtual ~CrxInstaller();
208
209  // Converts the source user script to an extension.
210  void ConvertUserScriptOnFileThread();
211
212  // Converts the source web app to an extension.
213  void ConvertWebAppOnFileThread(const WebApplicationInfo& web_app,
214                                 const base::FilePath& install_directory);
215
216  // Called after OnUnpackSuccess as a last check to see whether the install
217  // should complete.
218  CrxInstallerError AllowInstall(const Extension* extension);
219
220  // SandboxedUnpackerClient
221  virtual void OnUnpackFailure(const string16& error_message) OVERRIDE;
222  virtual void OnUnpackSuccess(const base::FilePath& temp_dir,
223                               const base::FilePath& extension_dir,
224                               const base::DictionaryValue* original_manifest,
225                               const Extension* extension,
226                               const SkBitmap& install_icon) OVERRIDE;
227
228  // Called on the UI thread to start the requirements check on the extension.
229  void CheckImportsAndRequirements();
230
231  // Runs on the UI thread. Callback from RequirementsChecker.
232  void OnRequirementsChecked(std::vector<std::string> requirement_errors);
233
234  // Runs on the UI thread. Callback from Blacklist.
235  void OnBlacklistChecked(
236      extensions::Blacklist::BlacklistState blacklist_state);
237
238  // Runs on the UI thread. Confirms the installation to the ExtensionService.
239  void ConfirmInstall();
240
241  // Runs on File thread. Install the unpacked extension into the profile and
242  // notify the frontend.
243  void CompleteInstall();
244
245  // Result reporting.
246  void ReportFailureFromFileThread(const CrxInstallerError& error);
247  void ReportFailureFromUIThread(const CrxInstallerError& error);
248  void ReportSuccessFromFileThread();
249  void ReportSuccessFromUIThread();
250  void NotifyCrxInstallComplete(bool success);
251
252  // Deletes temporary directory and crx file if needed.
253  void CleanupTempFiles();
254
255  // Checks whether the current installation is initiated by the user from
256  // the extension settings page to update an existing extension or app.
257  void CheckUpdateFromSettingsPage();
258
259  // Show re-enable prompt if the update is initiated from the settings page
260  // and needs additional permissions.
261  void ConfirmReEnable();
262
263  // The file we're installing.
264  base::FilePath source_file_;
265
266  // The URL the file was downloaded from.
267  GURL download_url_;
268
269  // The directory extensions are installed to.
270  base::FilePath install_directory_;
271
272  // The location the installation came from (bundled with Chromium, registry,
273  // manual install, etc). This metadata is saved with the installation if
274  // successful. Defaults to INTERNAL.
275  Manifest::Location install_source_;
276
277  // Indicates whether the user has already approved the extension to be
278  // installed. If true, |expected_manifest_| and |expected_id_| must match
279  // those of the CRX.
280  bool approved_;
281
282  // For updates, external and webstore installs we have an ID we're expecting
283  // the extension to contain.
284  std::string expected_id_;
285
286  // A parsed copy of the expected manifest, before any transformations like
287  // localization have taken place. If |approved_| is true, then the
288  // extension's manifest must match this for the install to proceed.
289  scoped_ptr<Manifest> expected_manifest_;
290
291  // If non-NULL, contains the expected version of the extension we're
292  // installing.  Important for external sources, where claiming the wrong
293  // version could cause unnecessary unpacking of an extension at every
294  // restart.
295  scoped_ptr<Version> expected_version_;
296
297  // Whether manual extension installation is enabled. We can't just check this
298  // before trying to install because themes are special-cased to always be
299  // allowed.
300  bool extensions_enabled_;
301
302  // Whether we're supposed to delete the source file on destruction. Defaults
303  // to false.
304  bool delete_source_;
305
306  // The download URL, before redirects, if this is a gallery install.
307  GURL original_download_url_;
308
309  // Whether to create an app shortcut after successful installation. This is
310  // set based on the user's selection in the UI and can only ever be true for
311  // apps.
312  bool create_app_shortcut_;
313
314  // The ordinal of the NTP apps page |extension_| will be shown on.
315  syncer::StringOrdinal page_ordinal_;
316
317  // A parsed copy of the unmodified original manifest, before any
318  // transformations like localization have taken place.
319  scoped_ptr<Manifest> original_manifest_;
320
321  // If non-empty, contains the current version of the extension we're
322  // installing (for upgrades).
323  std::string current_version_;
324
325  // The icon we will display in the installation UI, if any.
326  scoped_ptr<SkBitmap> install_icon_;
327
328  // The temp directory extension resources were unpacked to. We own this and
329  // must delete it when we are done with it.
330  base::FilePath temp_dir_;
331
332  // The frontend we will report results back to.
333  base::WeakPtr<ExtensionService> service_weak_;
334
335  // The client we will work with to do the installation. This can be NULL, in
336  // which case the install is silent.
337  // NOTE: we may be deleted on the file thread. To ensure the UI is deleted on
338  // the main thread we don't use a scoped_ptr here.
339  ExtensionInstallPrompt* client_;
340
341  // The root of the unpacked extension directory. This is a subdirectory of
342  // temp_dir_, so we don't have to delete it explicitly.
343  base::FilePath unpacked_extension_root_;
344
345  // True when the CRX being installed was just downloaded.
346  // Used to trigger extra checks before installing.
347  bool apps_require_extension_mime_type_;
348
349  // Allows for the possibility of a normal install (one in which a |client|
350  // is provided in the ctor) to procede without showing the permissions prompt
351  // dialog.
352  bool allow_silent_install_;
353
354  // The value of the content type header sent with the CRX.
355  // Ignorred unless |require_extension_mime_type_| is true.
356  std::string original_mime_type_;
357
358  // What caused this install?  Used only for histograms that report
359  // on failure rates, broken down by the cause of the install.
360  extension_misc::CrxInstallCause install_cause_;
361
362  // Creation flags to use for the extension.  These flags will be used
363  // when calling Extenion::Create() by the crx installer.
364  int creation_flags_;
365
366  // Whether to allow off store installation.
367  OffStoreInstallAllowReason off_store_install_allow_reason_;
368
369  // Whether the installation was handled successfully. This is used to
370  // indicate to the client whether the file should be removed and any UI
371  // initiating the installation can be removed. This is different than whether
372  // there was an error; if there was an error that rejects installation we
373  // still consider the installation 'handled'.
374  bool did_handle_successfully_;
375
376  // Whether we should produce an error if the manifest declares requirements
377  // that are not met. If false and there is an unmet requirement, the install
378  // will continue but the extension will be distabled.
379  bool error_on_unsupported_requirements_;
380
381  bool has_requirement_errors_;
382
383  extensions::Blacklist::BlacklistState blacklist_state_;
384
385  bool install_wait_for_idle_;
386
387  // Sequenced task runner where file I/O operations will be performed.
388  scoped_refptr<base::SequencedTaskRunner> installer_task_runner_;
389
390  // Used to show the install dialog.
391  ExtensionInstallPrompt::ShowDialogCallback show_dialog_callback_;
392
393  // Whether the update is initiated by the user from the extension settings
394  // page.
395  bool update_from_settings_page_;
396
397  // Gives access to common methods and data of an extension installer.
398  ExtensionInstaller installer_;
399
400  DISALLOW_COPY_AND_ASSIGN(CrxInstaller);
401};
402
403}  // namespace extensions
404
405#endif  // CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_
406