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_WEBSTORE_INSTALLER_H_
6#define CHROME_BROWSER_EXTENSIONS_WEBSTORE_INSTALLER_H_
7
8#include <list>
9#include <string>
10
11#include "base/compiler_specific.h"
12#include "base/memory/ref_counted.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/supports_user_data.h"
15#include "base/values.h"
16#include "base/version.h"
17#include "chrome/browser/extensions/extension_install_prompt.h"
18#include "content/public/browser/browser_thread.h"
19#include "content/public/browser/download_item.h"
20#include "content/public/browser/notification_observer.h"
21#include "content/public/browser/notification_registrar.h"
22#include "extensions/common/manifest_handlers/shared_module_info.h"
23#include "net/base/net_errors.h"
24#include "ui/gfx/image/image_skia.h"
25#include "url/gurl.h"
26
27class Profile;
28
29namespace base {
30class FilePath;
31}
32
33namespace content {
34class NavigationController;
35}
36
37namespace extensions {
38
39class Extension;
40class Manifest;
41
42// Downloads and installs extensions from the web store.
43class WebstoreInstaller :public content::NotificationObserver,
44                         public content::DownloadItem::Observer,
45                         public base::RefCountedThreadSafe<
46  WebstoreInstaller, content::BrowserThread::DeleteOnUIThread> {
47 public:
48  enum InstallSource {
49    // Inline installs trigger slightly different behavior (install source
50    // is different, download referrers are the item's page in the gallery).
51    INSTALL_SOURCE_INLINE,
52    INSTALL_SOURCE_APP_LAUNCHER,
53    INSTALL_SOURCE_OTHER
54  };
55
56  enum FailureReason {
57    FAILURE_REASON_CANCELLED,
58    FAILURE_REASON_DEPENDENCY_NOT_FOUND,
59    FAILURE_REASON_DEPENDENCY_NOT_SHARED_MODULE,
60    FAILURE_REASON_OTHER
61  };
62
63  enum ManifestCheckLevel {
64    // Do not check for any manifest equality.
65    MANIFEST_CHECK_LEVEL_NONE,
66
67    // Only check that the expected and actual permissions have the same
68    // effective permissions.
69    MANIFEST_CHECK_LEVEL_LOOSE,
70
71    // All data in the expected and actual manifests must match.
72    MANIFEST_CHECK_LEVEL_STRICT,
73  };
74
75  class Delegate {
76   public:
77    virtual void OnExtensionDownloadStarted(const std::string& id,
78                                            content::DownloadItem* item);
79    virtual void OnExtensionDownloadProgress(const std::string& id,
80                                             content::DownloadItem* item);
81    virtual void OnExtensionInstallSuccess(const std::string& id) = 0;
82    virtual void OnExtensionInstallFailure(const std::string& id,
83                                           const std::string& error,
84                                           FailureReason reason) = 0;
85
86   protected:
87    virtual ~Delegate() {}
88  };
89
90  // Contains information about what parts of the extension install process can
91  // be skipped or modified. If one of these is present, it means that a CRX
92  // download was initiated by WebstoreInstaller. The Approval instance should
93  // be checked further for additional details.
94  struct Approval : public base::SupportsUserData::Data {
95    static scoped_ptr<Approval> CreateWithInstallPrompt(Profile* profile);
96
97    // Creates an Approval for installing a shared module.
98    static scoped_ptr<Approval> CreateForSharedModule(Profile* profile);
99
100    // Creates an Approval that will skip putting up an install confirmation
101    // prompt if the actual manifest from the extension to be installed matches
102    // |parsed_manifest|. The |strict_manifest_check| controls whether we want
103    // to require an exact manifest match, or are willing to tolerate a looser
104    // check just that the effective permissions are the same.
105    static scoped_ptr<Approval> CreateWithNoInstallPrompt(
106        Profile* profile,
107        const std::string& extension_id,
108        scoped_ptr<base::DictionaryValue> parsed_manifest,
109        bool strict_manifest_check);
110
111    virtual ~Approval();
112
113    // The extension id that was approved for installation.
114    std::string extension_id;
115
116    // The profile the extension should be installed into.
117    Profile* profile;
118
119    // The expected manifest, before localization.
120    scoped_ptr<Manifest> manifest;
121
122    // Whether to use a bubble notification when an app is installed, instead of
123    // the default behavior of transitioning to the new tab page.
124    bool use_app_installed_bubble;
125
126    // Whether to skip the post install UI like the extension installed bubble.
127    bool skip_post_install_ui;
128
129    // Whether to skip the install dialog once the extension has been downloaded
130    // and unpacked. One reason this can be true is that in the normal webstore
131    // installation, the dialog is shown earlier, before any download is done,
132    // so there's no need to show it again.
133    bool skip_install_dialog;
134
135    // Whether we should enable the launcher before installing the app.
136    bool enable_launcher;
137
138    // Manifest check level for checking actual manifest against expected
139    // manifest.
140    ManifestCheckLevel manifest_check_level;
141
142    // Used to show the install dialog.
143    ExtensionInstallPrompt::ShowDialogCallback show_dialog_callback;
144
145    // The icon to use to display the extension while it is installing.
146    gfx::ImageSkia installing_icon;
147
148    // A dummy extension created from |manifest|;
149    scoped_refptr<Extension> dummy_extension;
150
151    // Required minimum version.
152    scoped_ptr<Version> minimum_version;
153
154    // Ephemeral apps (experimental) are not permanently installed in Chrome.
155    bool is_ephemeral;
156
157   private:
158    Approval();
159  };
160
161  // Gets the Approval associated with the |download|, or NULL if there's none.
162  // Note that the Approval is owned by |download|.
163  static const Approval* GetAssociatedApproval(
164      const content::DownloadItem& download);
165
166  // Creates a WebstoreInstaller for downloading and installing the extension
167  // with the given |id| from the Chrome Web Store. If |delegate| is not NULL,
168  // it will be notified when the install succeeds or fails. The installer will
169  // use the specified |controller| to download the extension. Only one
170  // WebstoreInstaller can use a specific controller at any given time. This
171  // also associates the |approval| with this install.
172  // Note: the delegate should stay alive until being called back.
173  WebstoreInstaller(Profile* profile,
174                    Delegate* delegate,
175                    content::NavigationController* controller,
176                    const std::string& id,
177                    scoped_ptr<Approval> approval,
178                    InstallSource source);
179
180  // Starts downloading and installing the extension.
181  void Start();
182
183  // content::NotificationObserver
184  virtual void Observe(int type,
185                       const content::NotificationSource& source,
186                       const content::NotificationDetails& details) OVERRIDE;
187
188  // Removes the reference to the delegate passed in the constructor. Used when
189  // the delegate object must be deleted before this object.
190  void InvalidateDelegate();
191
192  // Instead of using the default download directory, use |directory| instead.
193  // This does *not* transfer ownership of |directory|.
194  static void SetDownloadDirectoryForTests(base::FilePath* directory);
195
196 private:
197  FRIEND_TEST_ALL_PREFIXES(WebstoreInstallerTest, PlatformParams);
198  friend struct content::BrowserThread::DeleteOnThread<
199   content::BrowserThread::UI>;
200  friend class base::DeleteHelper<WebstoreInstaller>;
201  virtual ~WebstoreInstaller();
202
203  // Helper to get install URL.
204  static GURL GetWebstoreInstallURL(const std::string& extension_id,
205                                    InstallSource source);
206
207  // DownloadManager::DownloadUrl callback.
208  void OnDownloadStarted(content::DownloadItem* item, net::Error error);
209
210  // DownloadItem::Observer implementation:
211  virtual void OnDownloadUpdated(content::DownloadItem* download) OVERRIDE;
212  virtual void OnDownloadDestroyed(content::DownloadItem* download) OVERRIDE;
213
214  // Downloads next pending module in |pending_modules_|.
215  void DownloadNextPendingModule();
216
217  // Downloads and installs a single Crx with the given |extension_id|.
218  // This function is used for both the extension Crx and dependences.
219  void DownloadCrx(const std::string& extension_id, InstallSource source);
220
221  // Starts downloading the extension to |file_path|.
222  void StartDownload(const base::FilePath& file_path);
223
224  // Reports an install |error| to the delegate for the given extension if this
225  // managed its installation. This also removes the associated PendingInstall.
226  void ReportFailure(const std::string& error, FailureReason reason);
227
228  // Reports a successful install to the delegate for the given extension if
229  // this managed its installation. This also removes the associated
230  // PendingInstall.
231  void ReportSuccess();
232
233  // Records stats regarding an interrupted webstore download item.
234  void RecordInterrupt(const content::DownloadItem* download) const;
235
236  content::NotificationRegistrar registrar_;
237  Profile* profile_;
238  Delegate* delegate_;
239  content::NavigationController* controller_;
240  std::string id_;
241  InstallSource install_source_;
242  // The DownloadItem is owned by the DownloadManager and is valid from when
243  // OnDownloadStarted is called (with no error) until OnDownloadDestroyed().
244  content::DownloadItem* download_item_;
245  scoped_ptr<Approval> approval_;
246  GURL download_url_;
247
248  // Pending modules.
249  std::list<SharedModuleInfo::ImportInfo> pending_modules_;
250  // Total extension modules we need download and install (the main module and
251  // depedences).
252  int total_modules_;
253  bool download_started_;
254};
255
256}  // namespace extensions
257
258#endif  // CHROME_BROWSER_EXTENSIONS_WEBSTORE_INSTALLER_H_
259