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 "extensions/common/extension.h"
21#include "extensions/common/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    expected_version_strict_checking_ = true;
131  }
132
133  bool delete_source() const { return delete_source_; }
134  void set_delete_source(bool val) { delete_source_ = val; }
135
136  bool allow_silent_install() const { return allow_silent_install_; }
137  void set_allow_silent_install(bool val) { allow_silent_install_ = val; }
138
139  bool is_gallery_install() const {
140    return (creation_flags_ & Extension::FROM_WEBSTORE) > 0;
141  }
142  void set_is_gallery_install(bool val) {
143    if (val)
144      creation_flags_ |= Extension::FROM_WEBSTORE;
145    else
146      creation_flags_ &= ~Extension::FROM_WEBSTORE;
147  }
148
149  // The original download URL should be set when the WebstoreInstaller is
150  // tracking the installation. The WebstoreInstaller uses this URL to match
151  // failure notifications to the extension.
152  const GURL& original_download_url() const { return original_download_url_; }
153  void set_original_download_url(const GURL& url) {
154    original_download_url_ = url;
155  }
156
157  // If |apps_require_extension_mime_type_| is set to true, be sure to set
158  // |original_mime_type_| as well.
159  void set_apps_require_extension_mime_type(
160      bool apps_require_extension_mime_type) {
161    apps_require_extension_mime_type_ = apps_require_extension_mime_type;
162  }
163
164  void set_original_mime_type(const std::string& original_mime_type) {
165    original_mime_type_ = original_mime_type;
166  }
167
168  extension_misc::CrxInstallCause install_cause() const {
169    return install_cause_;
170  }
171  void set_install_cause(extension_misc::CrxInstallCause install_cause) {
172    install_cause_ = install_cause;
173  }
174
175  OffStoreInstallAllowReason off_store_install_allow_reason() const {
176    return off_store_install_allow_reason_;
177  }
178  void set_off_store_install_allow_reason(OffStoreInstallAllowReason reason) {
179    off_store_install_allow_reason_ = reason;
180  }
181
182  void set_page_ordinal(const syncer::StringOrdinal& page_ordinal) {
183    page_ordinal_ = page_ordinal;
184  }
185
186  void set_error_on_unsupported_requirements(bool val) {
187    error_on_unsupported_requirements_ = val;
188  }
189
190  void set_install_wait_for_idle(bool val) {
191    install_wait_for_idle_ = val;
192  }
193
194  bool did_handle_successfully() const { return did_handle_successfully_; }
195
196  Profile* profile() { return installer_.profile(); }
197
198  const Extension* extension() { return installer_.extension().get(); }
199
200 private:
201  friend class ::ExtensionServiceTest;
202  friend class ExtensionUpdaterTest;
203  friend class ExtensionCrxInstallerTest;
204
205  CrxInstaller(base::WeakPtr<ExtensionService> service_weak,
206               scoped_ptr<ExtensionInstallPrompt> client,
207               const WebstoreInstaller::Approval* approval);
208  virtual ~CrxInstaller();
209
210  // Converts the source user script to an extension.
211  void ConvertUserScriptOnFileThread();
212
213  // Converts the source web app to an extension.
214  void ConvertWebAppOnFileThread(const WebApplicationInfo& web_app,
215                                 const base::FilePath& install_directory);
216
217  // Called after OnUnpackSuccess as a last check to see whether the install
218  // should complete.
219  CrxInstallerError AllowInstall(const Extension* extension);
220
221  // SandboxedUnpackerClient
222  virtual void OnUnpackFailure(const base::string16& error_message) OVERRIDE;
223  virtual void OnUnpackSuccess(const base::FilePath& temp_dir,
224                               const base::FilePath& extension_dir,
225                               const base::DictionaryValue* original_manifest,
226                               const Extension* extension,
227                               const SkBitmap& install_icon) OVERRIDE;
228
229  // Called on the UI thread to start the requirements check on the extension.
230  void CheckImportsAndRequirements();
231
232  // Runs on the UI thread. Callback from RequirementsChecker.
233  void OnRequirementsChecked(std::vector<std::string> requirement_errors);
234
235  // Runs on the UI thread. Callback from Blacklist.
236  void OnBlacklistChecked(
237      extensions::Blacklist::BlacklistState blacklist_state);
238
239  // Runs on the UI thread. Confirms the installation to the ExtensionService.
240  void ConfirmInstall();
241
242  // Runs on File thread. Install the unpacked extension into the profile and
243  // notify the frontend.
244  void CompleteInstall();
245
246  // Result reporting.
247  void ReportFailureFromFileThread(const CrxInstallerError& error);
248  void ReportFailureFromUIThread(const CrxInstallerError& error);
249  void ReportSuccessFromFileThread();
250  void ReportSuccessFromUIThread();
251  void NotifyCrxInstallComplete(bool success);
252
253  // Deletes temporary directory and crx file if needed.
254  void CleanupTempFiles();
255
256  // Checks whether the current installation is initiated by the user from
257  // the extension settings page to update an existing extension or app.
258  void CheckUpdateFromSettingsPage();
259
260  // Show re-enable prompt if the update is initiated from the settings page
261  // and needs additional permissions.
262  void ConfirmReEnable();
263
264  // The file we're installing.
265  base::FilePath source_file_;
266
267  // The URL the file was downloaded from.
268  GURL download_url_;
269
270  // The directory extensions are installed to.
271  base::FilePath install_directory_;
272
273  // The location the installation came from (bundled with Chromium, registry,
274  // manual install, etc). This metadata is saved with the installation if
275  // successful. Defaults to INTERNAL.
276  Manifest::Location install_source_;
277
278  // Indicates whether the user has already approved the extension to be
279  // installed. If true, |expected_manifest_| and |expected_id_| must match
280  // those of the CRX.
281  bool approved_;
282
283  // For updates, external and webstore installs we have an ID we're expecting
284  // the extension to contain.
285  std::string expected_id_;
286
287  // A parsed copy of the expected manifest, before any transformations like
288  // localization have taken place. If |approved_| is true, then the
289  // extension's manifest must match this for the install to proceed.
290  scoped_ptr<Manifest> expected_manifest_;
291
292  // The level of checking when comparing the actual manifest against
293  // the |expected_manifest_|.
294  WebstoreInstaller::ManifestCheckLevel expected_manifest_check_level_;
295
296  // If non-NULL, contains the expected version of the extension we're
297  // installing.  Important for external sources, where claiming the wrong
298  // version could cause unnecessary unpacking of an extension at every
299  // restart.
300  scoped_ptr<Version> expected_version_;
301
302  // If true, the actual version should be same with the |expected_version_|,
303  // Otherwise the actual version should be equal to or newer than
304  // the |expected_version_|.
305  bool expected_version_strict_checking_;
306
307  // Whether manual extension installation is enabled. We can't just check this
308  // before trying to install because themes are special-cased to always be
309  // allowed.
310  bool extensions_enabled_;
311
312  // Whether we're supposed to delete the source file on destruction. Defaults
313  // to false.
314  bool delete_source_;
315
316  // The download URL, before redirects, if this is a gallery install.
317  GURL original_download_url_;
318
319  // Whether to create an app shortcut after successful installation. This is
320  // set based on the user's selection in the UI and can only ever be true for
321  // apps.
322  bool create_app_shortcut_;
323
324  // The ordinal of the NTP apps page |extension_| will be shown on.
325  syncer::StringOrdinal page_ordinal_;
326
327  // A parsed copy of the unmodified original manifest, before any
328  // transformations like localization have taken place.
329  scoped_ptr<Manifest> original_manifest_;
330
331  // If non-empty, contains the current version of the extension we're
332  // installing (for upgrades).
333  std::string current_version_;
334
335  // The icon we will display in the installation UI, if any.
336  scoped_ptr<SkBitmap> install_icon_;
337
338  // The temp directory extension resources were unpacked to. We own this and
339  // must delete it when we are done with it.
340  base::FilePath temp_dir_;
341
342  // The frontend we will report results back to.
343  base::WeakPtr<ExtensionService> service_weak_;
344
345  // The client we will work with to do the installation. This can be NULL, in
346  // which case the install is silent.
347  // NOTE: we may be deleted on the file thread. To ensure the UI is deleted on
348  // the main thread we don't use a scoped_ptr here.
349  ExtensionInstallPrompt* client_;
350
351  // The root of the unpacked extension directory. This is a subdirectory of
352  // temp_dir_, so we don't have to delete it explicitly.
353  base::FilePath unpacked_extension_root_;
354
355  // True when the CRX being installed was just downloaded.
356  // Used to trigger extra checks before installing.
357  bool apps_require_extension_mime_type_;
358
359  // Allows for the possibility of a normal install (one in which a |client|
360  // is provided in the ctor) to procede without showing the permissions prompt
361  // dialog.
362  bool allow_silent_install_;
363
364  // The value of the content type header sent with the CRX.
365  // Ignorred unless |require_extension_mime_type_| is true.
366  std::string original_mime_type_;
367
368  // What caused this install?  Used only for histograms that report
369  // on failure rates, broken down by the cause of the install.
370  extension_misc::CrxInstallCause install_cause_;
371
372  // Creation flags to use for the extension.  These flags will be used
373  // when calling Extenion::Create() by the crx installer.
374  int creation_flags_;
375
376  // Whether to allow off store installation.
377  OffStoreInstallAllowReason off_store_install_allow_reason_;
378
379  // Whether the installation was handled successfully. This is used to
380  // indicate to the client whether the file should be removed and any UI
381  // initiating the installation can be removed. This is different than whether
382  // there was an error; if there was an error that rejects installation we
383  // still consider the installation 'handled'.
384  bool did_handle_successfully_;
385
386  // Whether we should produce an error if the manifest declares requirements
387  // that are not met. If false and there is an unmet requirement, the install
388  // will continue but the extension will be distabled.
389  bool error_on_unsupported_requirements_;
390
391  bool has_requirement_errors_;
392
393  extensions::Blacklist::BlacklistState blacklist_state_;
394
395  bool install_wait_for_idle_;
396
397  // Sequenced task runner where file I/O operations will be performed.
398  scoped_refptr<base::SequencedTaskRunner> installer_task_runner_;
399
400  // Used to show the install dialog.
401  ExtensionInstallPrompt::ShowDialogCallback show_dialog_callback_;
402
403  // Whether the update is initiated by the user from the extension settings
404  // page.
405  bool update_from_settings_page_;
406
407  // Gives access to common methods and data of an extension installer.
408  ExtensionInstaller installer_;
409
410  DISALLOW_COPY_AND_ASSIGN(CrxInstaller);
411};
412
413}  // namespace extensions
414
415#endif  // CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_
416