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