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 24 class ExtensionService; 25 class ExtensionServiceTest; 26 class SkBitmap; 27 struct WebApplicationInfo; 28 29 namespace base { 30 class SequencedTaskRunner; 31 } 32 33 namespace extensions { 34 class CrxInstallerError; 35 class ExtensionUpdaterTest; 36 class 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. 66 class 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 creation_flags()110 int creation_flags() const { return creation_flags_; } set_creation_flags(int val)111 void set_creation_flags(int val) { creation_flags_ = val; } 112 download_url()113 const GURL& download_url() const { return download_url_; } set_download_url(const GURL & val)114 void set_download_url(const GURL& val) { download_url_ = val; } 115 source_file()116 const base::FilePath& source_file() const { return source_file_; } 117 install_source()118 Manifest::Location install_source() const { 119 return install_source_; 120 } set_install_source(Manifest::Location source)121 void set_install_source(Manifest::Location source) { 122 install_source_ = source; 123 } 124 expected_id()125 const std::string& expected_id() const { return expected_id_; } set_expected_id(const std::string & val)126 void set_expected_id(const std::string& val) { expected_id_ = val; } 127 set_expected_version(const Version & val)128 void set_expected_version(const Version& val) { 129 expected_version_.reset(new Version(val)); 130 expected_version_strict_checking_ = true; 131 } 132 delete_source()133 bool delete_source() const { return delete_source_; } set_delete_source(bool val)134 void set_delete_source(bool val) { delete_source_ = val; } 135 allow_silent_install()136 bool allow_silent_install() const { return allow_silent_install_; } set_allow_silent_install(bool val)137 void set_allow_silent_install(bool val) { allow_silent_install_ = val; } 138 is_gallery_install()139 bool is_gallery_install() const { 140 return (creation_flags_ & Extension::FROM_WEBSTORE) > 0; 141 } set_is_gallery_install(bool val)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. original_download_url()152 const GURL& original_download_url() const { return original_download_url_; } set_original_download_url(const GURL & 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. set_apps_require_extension_mime_type(bool apps_require_extension_mime_type)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 set_original_mime_type(const std::string & original_mime_type)164 void set_original_mime_type(const std::string& original_mime_type) { 165 original_mime_type_ = original_mime_type; 166 } 167 install_cause()168 extension_misc::CrxInstallCause install_cause() const { 169 return install_cause_; 170 } set_install_cause(extension_misc::CrxInstallCause install_cause)171 void set_install_cause(extension_misc::CrxInstallCause install_cause) { 172 install_cause_ = install_cause; 173 } 174 off_store_install_allow_reason()175 OffStoreInstallAllowReason off_store_install_allow_reason() const { 176 return off_store_install_allow_reason_; 177 } set_off_store_install_allow_reason(OffStoreInstallAllowReason reason)178 void set_off_store_install_allow_reason(OffStoreInstallAllowReason reason) { 179 off_store_install_allow_reason_ = reason; 180 } 181 set_page_ordinal(const syncer::StringOrdinal & page_ordinal)182 void set_page_ordinal(const syncer::StringOrdinal& page_ordinal) { 183 page_ordinal_ = page_ordinal; 184 } 185 set_error_on_unsupported_requirements(bool val)186 void set_error_on_unsupported_requirements(bool val) { 187 error_on_unsupported_requirements_ = val; 188 } 189 set_install_wait_for_idle(bool val)190 void set_install_wait_for_idle(bool val) { 191 install_wait_for_idle_ = val; 192 } 193 did_handle_successfully()194 bool did_handle_successfully() const { return did_handle_successfully_; } 195 profile()196 Profile* profile() { return installer_.profile(); } 197 extension()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