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 #include <vector> 10 11 #include "base/compiler_specific.h" 12 #include "base/files/file_path.h" 13 #include "base/memory/ref_counted.h" 14 #include "base/memory/weak_ptr.h" 15 #include "base/version.h" 16 #include "chrome/browser/extensions/blacklist.h" 17 #include "chrome/browser/extensions/extension_install_checker.h" 18 #include "chrome/browser/extensions/extension_install_prompt.h" 19 #include "chrome/browser/extensions/extension_service.h" 20 #include "chrome/browser/extensions/sandboxed_unpacker.h" 21 #include "chrome/browser/extensions/webstore_installer.h" 22 #include "chrome/common/extensions/extension_constants.h" 23 #include "extensions/browser/install_flag.h" 24 #include "extensions/common/extension.h" 25 #include "extensions/common/manifest.h" 26 #include "sync/api/string_ordinal.h" 27 28 class ExtensionService; 29 class ExtensionServiceTest; 30 class SkBitmap; 31 struct WebApplicationInfo; 32 33 namespace base { 34 class SequencedTaskRunner; 35 } 36 37 namespace extensions { 38 class CrxInstallerError; 39 class ExtensionUpdaterTest; 40 class RequirementsChecker; 41 42 // This class installs a crx file into a profile. 43 // 44 // Installing a CRX is a multi-step process, including unpacking the crx, 45 // validating it, prompting the user, and installing. Since many of these 46 // steps must occur on the file thread, this class contains a copy of all data 47 // necessary to do its job. (This also minimizes external dependencies for 48 // easier testing). 49 // 50 // Lifetime management: 51 // 52 // This class is ref-counted by each call it makes to itself on another thread, 53 // and by UtilityProcessHost. 54 // 55 // Additionally, we hold a reference to our own client so that it lives at least 56 // long enough to receive the result of unpacking. 57 // 58 // IMPORTANT: Callers should keep a reference to a CrxInstaller while they are 59 // working with it, eg: 60 // 61 // scoped_refptr<CrxInstaller> installer(new CrxInstaller(...)); 62 // installer->set_foo(); 63 // installer->set_bar(); 64 // installer->InstallCrx(...); 65 // 66 // Installation is aborted if the extension service learns that Chrome is 67 // terminating during the install. We can't listen for the app termination 68 // notification here in this class because it can be destroyed on any thread 69 // and won't safely be able to clean up UI thread notification listeners. 70 class CrxInstaller 71 : public SandboxedUnpackerClient, 72 public ExtensionInstallPrompt::Delegate { 73 public: 74 // Used in histograms; do not change order. 75 enum OffStoreInstallAllowReason { 76 OffStoreInstallDisallowed, 77 OffStoreInstallAllowedFromSettingsPage, 78 OffStoreInstallAllowedBecausePref, 79 OffStoreInstallAllowedInTest, 80 NumOffStoreInstallAllowReasons 81 }; 82 83 // Extensions will be installed into service->install_directory(), then 84 // registered with |service|. This does a silent install - see below for 85 // other options. 86 static scoped_refptr<CrxInstaller> CreateSilent(ExtensionService* service); 87 88 // Same as above, but use |client| to generate a confirmation prompt. 89 static scoped_refptr<CrxInstaller> Create( 90 ExtensionService* service, 91 scoped_ptr<ExtensionInstallPrompt> client); 92 93 // Same as the previous method, except use the |approval| to bypass the 94 // prompt. Note that the caller retains ownership of |approval|. 95 static scoped_refptr<CrxInstaller> Create( 96 ExtensionService* service, 97 scoped_ptr<ExtensionInstallPrompt> client, 98 const WebstoreInstaller::Approval* approval); 99 100 // Install the crx in |source_file|. 101 void InstallCrx(const base::FilePath& source_file); 102 103 // Convert the specified user script into an extension and install it. 104 void InstallUserScript(const base::FilePath& source_file, 105 const GURL& download_url); 106 107 // Convert the specified web app into an extension and install it. 108 void InstallWebApp(const WebApplicationInfo& web_app); 109 110 // Overridden from ExtensionInstallPrompt::Delegate: 111 virtual void InstallUIProceed() OVERRIDE; 112 virtual void InstallUIAbort(bool user_initiated) OVERRIDE; 113 114 int creation_flags() const { return creation_flags_; } 115 void set_creation_flags(int val) { creation_flags_ = val; } 116 117 const base::FilePath& source_file() const { return source_file_; } 118 119 Manifest::Location install_source() const { 120 return install_source_; 121 } 122 void set_install_source(Manifest::Location source) { 123 install_source_ = source; 124 } 125 126 const std::string& expected_id() const { return expected_id_; } 127 void set_expected_id(const std::string& val) { expected_id_ = val; } 128 129 void set_expected_version(const Version& val) { 130 expected_version_.reset(new Version(val)); 131 expected_version_strict_checking_ = true; 132 } 133 134 bool delete_source() const { return delete_source_; } 135 void set_delete_source(bool val) { delete_source_ = val; } 136 137 bool allow_silent_install() const { return allow_silent_install_; } 138 void set_allow_silent_install(bool val) { allow_silent_install_ = val; } 139 140 bool grant_permissions() const { return grant_permissions_; } 141 void set_grant_permissions(bool val) { grant_permissions_ = val; } 142 143 bool is_gallery_install() const { 144 return (creation_flags_ & Extension::FROM_WEBSTORE) > 0; 145 } 146 void set_is_gallery_install(bool val) { 147 if (val) 148 creation_flags_ |= Extension::FROM_WEBSTORE; 149 else 150 creation_flags_ &= ~Extension::FROM_WEBSTORE; 151 } 152 153 // If |apps_require_extension_mime_type_| is set to true, be sure to set 154 // |original_mime_type_| as well. 155 void set_apps_require_extension_mime_type( 156 bool apps_require_extension_mime_type) { 157 apps_require_extension_mime_type_ = apps_require_extension_mime_type; 158 } 159 160 void set_original_mime_type(const std::string& original_mime_type) { 161 original_mime_type_ = original_mime_type; 162 } 163 164 extension_misc::CrxInstallCause install_cause() const { 165 return install_cause_; 166 } 167 void set_install_cause(extension_misc::CrxInstallCause install_cause) { 168 install_cause_ = install_cause; 169 } 170 171 OffStoreInstallAllowReason off_store_install_allow_reason() const { 172 return off_store_install_allow_reason_; 173 } 174 void set_off_store_install_allow_reason(OffStoreInstallAllowReason reason) { 175 off_store_install_allow_reason_ = reason; 176 } 177 178 void set_page_ordinal(const syncer::StringOrdinal& page_ordinal) { 179 page_ordinal_ = page_ordinal; 180 } 181 182 void set_error_on_unsupported_requirements(bool val) { 183 error_on_unsupported_requirements_ = val; 184 } 185 186 void set_install_immediately(bool val) { 187 set_install_flag(kInstallFlagInstallImmediately, val); 188 } 189 void set_is_ephemeral(bool val) { 190 set_install_flag(kInstallFlagIsEphemeral, val); 191 } 192 void set_do_not_sync(bool val) { 193 set_install_flag(kInstallFlagDoNotSync, val); 194 } 195 196 bool did_handle_successfully() const { return did_handle_successfully_; } 197 198 Profile* profile() { return install_checker_.profile(); } 199 200 const Extension* extension() { return install_checker_.extension().get(); } 201 202 const std::string& current_version() const { return current_version_; } 203 204 private: 205 friend class ::ExtensionServiceTest; 206 friend class ExtensionUpdaterTest; 207 friend class ExtensionCrxInstallerTest; 208 209 CrxInstaller(base::WeakPtr<ExtensionService> service_weak, 210 scoped_ptr<ExtensionInstallPrompt> client, 211 const WebstoreInstaller::Approval* approval); 212 virtual ~CrxInstaller(); 213 214 // Converts the source user script to an extension. 215 void ConvertUserScriptOnFileThread(); 216 217 // Converts the source web app to an extension. 218 void ConvertWebAppOnFileThread(const WebApplicationInfo& web_app); 219 220 // Called after OnUnpackSuccess as a last check to see whether the install 221 // should complete. 222 CrxInstallerError AllowInstall(const Extension* extension); 223 224 // SandboxedUnpackerClient 225 virtual void OnUnpackFailure(const base::string16& error_message) OVERRIDE; 226 virtual void OnUnpackSuccess(const base::FilePath& temp_dir, 227 const base::FilePath& extension_dir, 228 const base::DictionaryValue* original_manifest, 229 const Extension* extension, 230 const SkBitmap& install_icon) OVERRIDE; 231 232 // Called on the UI thread to start the requirements, policy and blacklist 233 // checks on the extension. 234 void CheckInstall(); 235 236 // Runs on the UI thread. Callback from ExtensionInstallChecker. 237 void OnInstallChecksComplete(int failed_checks); 238 239 // Runs on the UI thread. Callback from Blacklist. 240 void OnBlacklistChecked( 241 extensions::BlacklistState blacklist_state); 242 243 // Runs on the UI thread. Confirms the installation to the ExtensionService. 244 void ConfirmInstall(); 245 246 // Runs on File thread. Install the unpacked extension into the profile and 247 // notify the frontend. 248 void CompleteInstall(); 249 250 // Reloads extension on File thread and reports installation result back 251 // to UI thread. 252 void ReloadExtensionAfterInstall(const base::FilePath& version_dir); 253 254 // Result reporting. 255 void ReportFailureFromFileThread(const CrxInstallerError& error); 256 void ReportFailureFromUIThread(const CrxInstallerError& error); 257 void ReportSuccessFromFileThread(); 258 void ReportSuccessFromUIThread(); 259 void NotifyCrxInstallBegin(); 260 void NotifyCrxInstallComplete(bool success); 261 262 // Deletes temporary directory and crx file if needed. 263 void CleanupTempFiles(); 264 265 // Checks whether the current installation is initiated by the user from 266 // the extension settings page to update an existing extension or app. 267 void CheckUpdateFromSettingsPage(); 268 269 // Show re-enable prompt if the update is initiated from the settings page 270 // and needs additional permissions. 271 void ConfirmReEnable(); 272 273 void set_install_flag(int flag, bool val) { 274 if (val) 275 install_flags_ |= flag; 276 else 277 install_flags_ &= ~flag; 278 } 279 280 // The file we're installing. 281 base::FilePath source_file_; 282 283 // The URL the file was downloaded from. 284 GURL download_url_; 285 286 // The directory extensions are installed to. 287 const base::FilePath install_directory_; 288 289 // The location the installation came from (bundled with Chromium, registry, 290 // manual install, etc). This metadata is saved with the installation if 291 // successful. Defaults to INTERNAL. 292 Manifest::Location install_source_; 293 294 // Indicates whether the user has already approved the extension to be 295 // installed. If true, |expected_manifest_| and |expected_id_| must match 296 // those of the CRX. 297 bool approved_; 298 299 // For updates, external and webstore installs we have an ID we're expecting 300 // the extension to contain. 301 std::string expected_id_; 302 303 // A parsed copy of the expected manifest, before any transformations like 304 // localization have taken place. If |approved_| is true, then the 305 // extension's manifest must match this for the install to proceed. 306 scoped_ptr<Manifest> expected_manifest_; 307 308 // The level of checking when comparing the actual manifest against 309 // the |expected_manifest_|. 310 WebstoreInstaller::ManifestCheckLevel expected_manifest_check_level_; 311 312 // If non-NULL, contains the expected version of the extension we're 313 // installing. Important for external sources, where claiming the wrong 314 // version could cause unnecessary unpacking of an extension at every 315 // restart. 316 scoped_ptr<Version> expected_version_; 317 318 // If true, the actual version should be same with the |expected_version_|, 319 // Otherwise the actual version should be equal to or newer than 320 // the |expected_version_|. 321 bool expected_version_strict_checking_; 322 323 // Whether manual extension installation is enabled. We can't just check this 324 // before trying to install because themes are special-cased to always be 325 // allowed. 326 bool extensions_enabled_; 327 328 // Whether we're supposed to delete the source file on destruction. Defaults 329 // to false. 330 bool delete_source_; 331 332 // Whether to create an app shortcut after successful installation. This is 333 // set based on the user's selection in the UI and can only ever be true for 334 // apps. 335 bool create_app_shortcut_; 336 337 // The ordinal of the NTP apps page |extension_| will be shown on. 338 syncer::StringOrdinal page_ordinal_; 339 340 // A parsed copy of the unmodified original manifest, before any 341 // transformations like localization have taken place. 342 scoped_ptr<Manifest> original_manifest_; 343 344 // If non-empty, contains the current version of the extension we're 345 // installing (for upgrades). 346 std::string current_version_; 347 348 // The icon we will display in the installation UI, if any. 349 scoped_ptr<SkBitmap> install_icon_; 350 351 // The temp directory extension resources were unpacked to. We own this and 352 // must delete it when we are done with it. 353 base::FilePath temp_dir_; 354 355 // The frontend we will report results back to. 356 base::WeakPtr<ExtensionService> service_weak_; 357 358 // The client we will work with to do the installation. This can be NULL, in 359 // which case the install is silent. 360 // NOTE: we may be deleted on the file thread. To ensure the UI is deleted on 361 // the main thread we don't use a scoped_ptr here. 362 ExtensionInstallPrompt* client_; 363 364 // The root of the unpacked extension directory. This is a subdirectory of 365 // temp_dir_, so we don't have to delete it explicitly. 366 base::FilePath unpacked_extension_root_; 367 368 // True when the CRX being installed was just downloaded. 369 // Used to trigger extra checks before installing. 370 bool apps_require_extension_mime_type_; 371 372 // Allows for the possibility of a normal install (one in which a |client| 373 // is provided in the ctor) to proceed without showing the permissions prompt 374 // dialog. 375 bool allow_silent_install_; 376 377 // Allows for the possibility of an installation without granting any 378 // permissions to the extension. 379 bool grant_permissions_; 380 381 // The value of the content type header sent with the CRX. 382 // Ignorred unless |require_extension_mime_type_| is true. 383 std::string original_mime_type_; 384 385 // What caused this install? Used only for histograms that report 386 // on failure rates, broken down by the cause of the install. 387 extension_misc::CrxInstallCause install_cause_; 388 389 // Creation flags to use for the extension. These flags will be used 390 // when calling Extenion::Create() by the crx installer. 391 int creation_flags_; 392 393 // Whether to allow off store installation. 394 OffStoreInstallAllowReason off_store_install_allow_reason_; 395 396 // Whether the installation was handled successfully. This is used to 397 // indicate to the client whether the file should be removed and any UI 398 // initiating the installation can be removed. This is different than whether 399 // there was an error; if there was an error that rejects installation we 400 // still consider the installation 'handled'. 401 bool did_handle_successfully_; 402 403 // Whether we should produce an error if the manifest declares requirements 404 // that are not met. If false and there is an unmet requirement, the install 405 // will continue but the extension will be distabled. 406 bool error_on_unsupported_requirements_; 407 408 // Sequenced task runner where file I/O operations will be performed. 409 scoped_refptr<base::SequencedTaskRunner> installer_task_runner_; 410 411 // Used to show the install dialog. 412 ExtensionInstallPrompt::ShowDialogCallback show_dialog_callback_; 413 414 // Whether the update is initiated by the user from the extension settings 415 // page. 416 bool update_from_settings_page_; 417 418 // The flags for ExtensionService::OnExtensionInstalled. 419 int install_flags_; 420 421 // Performs requirements, policy and blacklist checks on the extension. 422 ExtensionInstallChecker install_checker_; 423 424 DISALLOW_COPY_AND_ASSIGN(CrxInstaller); 425 }; 426 427 } // namespace extensions 428 429 #endif // CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_ 430