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