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_prompt.h" 18 #include "chrome/browser/extensions/extension_installer.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 creation_flags()114 int creation_flags() const { return creation_flags_; } set_creation_flags(int val)115 void set_creation_flags(int val) { creation_flags_ = val; } 116 source_file()117 const base::FilePath& source_file() const { return source_file_; } 118 install_source()119 Manifest::Location install_source() const { 120 return install_source_; 121 } set_install_source(Manifest::Location source)122 void set_install_source(Manifest::Location source) { 123 install_source_ = source; 124 } 125 expected_id()126 const std::string& expected_id() const { return expected_id_; } set_expected_id(const std::string & val)127 void set_expected_id(const std::string& val) { expected_id_ = val; } 128 set_expected_version(const Version & val)129 void set_expected_version(const Version& val) { 130 expected_version_.reset(new Version(val)); 131 expected_version_strict_checking_ = true; 132 } 133 delete_source()134 bool delete_source() const { return delete_source_; } set_delete_source(bool val)135 void set_delete_source(bool val) { delete_source_ = val; } 136 allow_silent_install()137 bool allow_silent_install() const { return allow_silent_install_; } set_allow_silent_install(bool val)138 void set_allow_silent_install(bool val) { allow_silent_install_ = val; } 139 grant_permissions()140 bool grant_permissions() const { return grant_permissions_; } set_grant_permissions(bool val)141 void set_grant_permissions(bool val) { grant_permissions_ = val; } 142 is_gallery_install()143 bool is_gallery_install() const { 144 return (creation_flags_ & Extension::FROM_WEBSTORE) > 0; 145 } set_is_gallery_install(bool val)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. set_apps_require_extension_mime_type(bool apps_require_extension_mime_type)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 set_original_mime_type(const std::string & original_mime_type)160 void set_original_mime_type(const std::string& original_mime_type) { 161 original_mime_type_ = original_mime_type; 162 } 163 install_cause()164 extension_misc::CrxInstallCause install_cause() const { 165 return install_cause_; 166 } set_install_cause(extension_misc::CrxInstallCause install_cause)167 void set_install_cause(extension_misc::CrxInstallCause install_cause) { 168 install_cause_ = install_cause; 169 } 170 off_store_install_allow_reason()171 OffStoreInstallAllowReason off_store_install_allow_reason() const { 172 return off_store_install_allow_reason_; 173 } set_off_store_install_allow_reason(OffStoreInstallAllowReason reason)174 void set_off_store_install_allow_reason(OffStoreInstallAllowReason reason) { 175 off_store_install_allow_reason_ = reason; 176 } 177 set_page_ordinal(const syncer::StringOrdinal & page_ordinal)178 void set_page_ordinal(const syncer::StringOrdinal& page_ordinal) { 179 page_ordinal_ = page_ordinal; 180 } 181 set_error_on_unsupported_requirements(bool val)182 void set_error_on_unsupported_requirements(bool val) { 183 error_on_unsupported_requirements_ = val; 184 } 185 set_install_immediately(bool val)186 void set_install_immediately(bool val) { 187 set_install_flag(kInstallFlagInstallImmediately, val); 188 } set_is_ephemeral(bool val)189 void set_is_ephemeral(bool val) { 190 set_install_flag(kInstallFlagIsEphemeral, val); 191 } set_do_not_sync(bool val)192 void set_do_not_sync(bool val) { 193 set_install_flag(kInstallFlagDoNotSync, val); 194 } 195 did_handle_successfully()196 bool did_handle_successfully() const { return did_handle_successfully_; } 197 profile()198 Profile* profile() { return installer_.profile(); } 199 extension()200 const Extension* extension() { return installer_.extension().get(); } 201 current_version()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 check on the extension. 233 void CheckImportsAndRequirements(); 234 235 // Runs on the UI thread. Callback from RequirementsChecker. 236 void OnRequirementsChecked(std::vector<std::string> requirement_errors); 237 238 // Runs on the UI thread. Callback from Blacklist. 239 void OnBlacklistChecked( 240 extensions::BlacklistState blacklist_state); 241 242 // Runs on the UI thread. Confirms the installation to the ExtensionService. 243 void ConfirmInstall(); 244 245 // Runs on File thread. Install the unpacked extension into the profile and 246 // notify the frontend. 247 void CompleteInstall(); 248 249 // Reloads extension on File thread and reports installation result back 250 // to UI thread. 251 void ReloadExtensionAfterInstall(const base::FilePath& version_dir); 252 253 // Result reporting. 254 void ReportFailureFromFileThread(const CrxInstallerError& error); 255 void ReportFailureFromUIThread(const CrxInstallerError& error); 256 void ReportSuccessFromFileThread(); 257 void ReportSuccessFromUIThread(); 258 void NotifyCrxInstallBegin(); 259 void NotifyCrxInstallComplete(bool success); 260 261 // Deletes temporary directory and crx file if needed. 262 void CleanupTempFiles(); 263 264 // Checks whether the current installation is initiated by the user from 265 // the extension settings page to update an existing extension or app. 266 void CheckUpdateFromSettingsPage(); 267 268 // Show re-enable prompt if the update is initiated from the settings page 269 // and needs additional permissions. 270 void ConfirmReEnable(); 271 set_install_flag(int flag,bool val)272 void set_install_flag(int flag, bool val) { 273 if (val) 274 install_flags_ |= flag; 275 else 276 install_flags_ &= ~flag; 277 } 278 279 // The file we're installing. 280 base::FilePath source_file_; 281 282 // The URL the file was downloaded from. 283 GURL download_url_; 284 285 // The directory extensions are installed to. 286 const base::FilePath install_directory_; 287 288 // The location the installation came from (bundled with Chromium, registry, 289 // manual install, etc). This metadata is saved with the installation if 290 // successful. Defaults to INTERNAL. 291 Manifest::Location install_source_; 292 293 // Indicates whether the user has already approved the extension to be 294 // installed. If true, |expected_manifest_| and |expected_id_| must match 295 // those of the CRX. 296 bool approved_; 297 298 // For updates, external and webstore installs we have an ID we're expecting 299 // the extension to contain. 300 std::string expected_id_; 301 302 // A parsed copy of the expected manifest, before any transformations like 303 // localization have taken place. If |approved_| is true, then the 304 // extension's manifest must match this for the install to proceed. 305 scoped_ptr<Manifest> expected_manifest_; 306 307 // The level of checking when comparing the actual manifest against 308 // the |expected_manifest_|. 309 WebstoreInstaller::ManifestCheckLevel expected_manifest_check_level_; 310 311 // If non-NULL, contains the expected version of the extension we're 312 // installing. Important for external sources, where claiming the wrong 313 // version could cause unnecessary unpacking of an extension at every 314 // restart. 315 scoped_ptr<Version> expected_version_; 316 317 // If true, the actual version should be same with the |expected_version_|, 318 // Otherwise the actual version should be equal to or newer than 319 // the |expected_version_|. 320 bool expected_version_strict_checking_; 321 322 // Whether manual extension installation is enabled. We can't just check this 323 // before trying to install because themes are special-cased to always be 324 // allowed. 325 bool extensions_enabled_; 326 327 // Whether we're supposed to delete the source file on destruction. Defaults 328 // to false. 329 bool delete_source_; 330 331 // Whether to create an app shortcut after successful installation. This is 332 // set based on the user's selection in the UI and can only ever be true for 333 // apps. 334 bool create_app_shortcut_; 335 336 // The ordinal of the NTP apps page |extension_| will be shown on. 337 syncer::StringOrdinal page_ordinal_; 338 339 // A parsed copy of the unmodified original manifest, before any 340 // transformations like localization have taken place. 341 scoped_ptr<Manifest> original_manifest_; 342 343 // If non-empty, contains the current version of the extension we're 344 // installing (for upgrades). 345 std::string current_version_; 346 347 // The icon we will display in the installation UI, if any. 348 scoped_ptr<SkBitmap> install_icon_; 349 350 // The temp directory extension resources were unpacked to. We own this and 351 // must delete it when we are done with it. 352 base::FilePath temp_dir_; 353 354 // The frontend we will report results back to. 355 base::WeakPtr<ExtensionService> service_weak_; 356 357 // The client we will work with to do the installation. This can be NULL, in 358 // which case the install is silent. 359 // NOTE: we may be deleted on the file thread. To ensure the UI is deleted on 360 // the main thread we don't use a scoped_ptr here. 361 ExtensionInstallPrompt* client_; 362 363 // The root of the unpacked extension directory. This is a subdirectory of 364 // temp_dir_, so we don't have to delete it explicitly. 365 base::FilePath unpacked_extension_root_; 366 367 // True when the CRX being installed was just downloaded. 368 // Used to trigger extra checks before installing. 369 bool apps_require_extension_mime_type_; 370 371 // Allows for the possibility of a normal install (one in which a |client| 372 // is provided in the ctor) to proceed without showing the permissions prompt 373 // dialog. 374 bool allow_silent_install_; 375 376 // Allows for the possibility of an installation without granting any 377 // permissions to the extension. 378 bool grant_permissions_; 379 380 // The value of the content type header sent with the CRX. 381 // Ignorred unless |require_extension_mime_type_| is true. 382 std::string original_mime_type_; 383 384 // What caused this install? Used only for histograms that report 385 // on failure rates, broken down by the cause of the install. 386 extension_misc::CrxInstallCause install_cause_; 387 388 // Creation flags to use for the extension. These flags will be used 389 // when calling Extenion::Create() by the crx installer. 390 int creation_flags_; 391 392 // Whether to allow off store installation. 393 OffStoreInstallAllowReason off_store_install_allow_reason_; 394 395 // Whether the installation was handled successfully. This is used to 396 // indicate to the client whether the file should be removed and any UI 397 // initiating the installation can be removed. This is different than whether 398 // there was an error; if there was an error that rejects installation we 399 // still consider the installation 'handled'. 400 bool did_handle_successfully_; 401 402 // Whether we should produce an error if the manifest declares requirements 403 // that are not met. If false and there is an unmet requirement, the install 404 // will continue but the extension will be distabled. 405 bool error_on_unsupported_requirements_; 406 407 // Sequenced task runner where file I/O operations will be performed. 408 scoped_refptr<base::SequencedTaskRunner> installer_task_runner_; 409 410 // Used to show the install dialog. 411 ExtensionInstallPrompt::ShowDialogCallback show_dialog_callback_; 412 413 // Whether the update is initiated by the user from the extension settings 414 // page. 415 bool update_from_settings_page_; 416 417 // The flags for ExtensionService::OnExtensionInstalled. 418 int install_flags_; 419 420 // Gives access to common methods and data of an extension installer. 421 ExtensionInstaller installer_; 422 423 DISALLOW_COPY_AND_ASSIGN(CrxInstaller); 424 }; 425 426 } // namespace extensions 427 428 #endif // CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_ 429