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 #include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h" 6 7 #include "base/bind_helpers.h" 8 #include "base/command_line.h" 9 #include "base/lazy_instance.h" 10 #include "base/memory/scoped_vector.h" 11 #include "base/metrics/histogram.h" 12 #include "base/prefs/pref_service.h" 13 #include "base/strings/string_util.h" 14 #include "base/strings/utf_string_conversions.h" 15 #include "base/values.h" 16 #include "chrome/browser/about_flags.h" 17 #include "chrome/browser/browser_process.h" 18 #include "chrome/browser/chrome_notification_types.h" 19 #include "chrome/browser/extensions/crx_installer.h" 20 #include "chrome/browser/extensions/extension_service.h" 21 #include "chrome/browser/extensions/webstore_installer.h" 22 #include "chrome/browser/gpu/gpu_feature_checker.h" 23 #include "chrome/browser/profiles/profile_manager.h" 24 #include "chrome/browser/signin/signin_manager_factory.h" 25 #include "chrome/browser/signin/signin_promo.h" 26 #include "chrome/browser/signin/signin_tracker_factory.h" 27 #include "chrome/browser/sync/profile_sync_service.h" 28 #include "chrome/browser/sync/profile_sync_service_factory.h" 29 #include "chrome/browser/ui/app_list/app_list_service.h" 30 #include "chrome/browser/ui/app_list/app_list_util.h" 31 #include "chrome/browser/ui/browser.h" 32 #include "chrome/common/extensions/extension_constants.h" 33 #include "chrome/common/pref_names.h" 34 #include "components/signin/core/browser/signin_manager.h" 35 #include "components/signin/core/common/profile_management_switches.h" 36 #include "content/public/browser/gpu_data_manager.h" 37 #include "content/public/browser/notification_details.h" 38 #include "content/public/browser/notification_source.h" 39 #include "content/public/browser/web_contents.h" 40 #include "content/public/common/page_transition_types.h" 41 #include "content/public/common/referrer.h" 42 #include "extensions/browser/extension_function_dispatcher.h" 43 #include "extensions/browser/extension_prefs.h" 44 #include "extensions/browser/extension_registry.h" 45 #include "extensions/browser/extension_system.h" 46 #include "extensions/browser/extension_util.h" 47 #include "extensions/common/error_utils.h" 48 #include "extensions/common/extension.h" 49 #include "extensions/common/extension_l10n_util.h" 50 #include "google_apis/gaia/google_service_auth_error.h" 51 #include "grit/chromium_strings.h" 52 #include "grit/generated_resources.h" 53 #include "ui/base/l10n/l10n_util.h" 54 #include "url/gurl.h" 55 56 using content::GpuDataManager; 57 58 namespace extensions { 59 60 namespace BeginInstallWithManifest3 = 61 api::webstore_private::BeginInstallWithManifest3; 62 namespace CompleteInstall = api::webstore_private::CompleteInstall; 63 namespace GetBrowserLogin = api::webstore_private::GetBrowserLogin; 64 namespace GetIsLauncherEnabled = api::webstore_private::GetIsLauncherEnabled; 65 namespace GetStoreLogin = api::webstore_private::GetStoreLogin; 66 namespace GetWebGLStatus = api::webstore_private::GetWebGLStatus; 67 namespace InstallBundle = api::webstore_private::InstallBundle; 68 namespace IsInIncognitoMode = api::webstore_private::IsInIncognitoMode; 69 namespace SignIn = api::webstore_private::SignIn; 70 namespace SetStoreLogin = api::webstore_private::SetStoreLogin; 71 72 namespace { 73 74 // Holds the Approvals between the time we prompt and start the installs. 75 class PendingApprovals { 76 public: 77 PendingApprovals(); 78 ~PendingApprovals(); 79 80 void PushApproval(scoped_ptr<WebstoreInstaller::Approval> approval); 81 scoped_ptr<WebstoreInstaller::Approval> PopApproval( 82 Profile* profile, const std::string& id); 83 private: 84 typedef ScopedVector<WebstoreInstaller::Approval> ApprovalList; 85 86 ApprovalList approvals_; 87 88 DISALLOW_COPY_AND_ASSIGN(PendingApprovals); 89 }; 90 91 PendingApprovals::PendingApprovals() {} 92 PendingApprovals::~PendingApprovals() {} 93 94 void PendingApprovals::PushApproval( 95 scoped_ptr<WebstoreInstaller::Approval> approval) { 96 approvals_.push_back(approval.release()); 97 } 98 99 scoped_ptr<WebstoreInstaller::Approval> PendingApprovals::PopApproval( 100 Profile* profile, const std::string& id) { 101 for (size_t i = 0; i < approvals_.size(); ++i) { 102 WebstoreInstaller::Approval* approval = approvals_[i]; 103 if (approval->extension_id == id && 104 profile->IsSameProfile(approval->profile)) { 105 approvals_.weak_erase(approvals_.begin() + i); 106 return scoped_ptr<WebstoreInstaller::Approval>(approval); 107 } 108 } 109 return scoped_ptr<WebstoreInstaller::Approval>(); 110 } 111 112 // Uniquely holds the profile and extension id of an install between the time we 113 // prompt and complete the installs. 114 class PendingInstalls { 115 public: 116 PendingInstalls(); 117 ~PendingInstalls(); 118 119 bool InsertInstall(Profile* profile, const std::string& id); 120 void EraseInstall(Profile* profile, const std::string& id); 121 private: 122 typedef std::pair<Profile*, std::string> ProfileAndExtensionId; 123 typedef std::vector<ProfileAndExtensionId> InstallList; 124 125 InstallList::iterator FindInstall(Profile* profile, const std::string& id); 126 127 InstallList installs_; 128 129 DISALLOW_COPY_AND_ASSIGN(PendingInstalls); 130 }; 131 132 PendingInstalls::PendingInstalls() {} 133 PendingInstalls::~PendingInstalls() {} 134 135 // Returns true and inserts the profile/id pair if it is not present. Otherwise 136 // returns false. 137 bool PendingInstalls::InsertInstall(Profile* profile, const std::string& id) { 138 if (FindInstall(profile, id) != installs_.end()) 139 return false; 140 installs_.push_back(make_pair(profile, id)); 141 return true; 142 } 143 144 // Removes the given profile/id pair. 145 void PendingInstalls::EraseInstall(Profile* profile, const std::string& id) { 146 InstallList::iterator it = FindInstall(profile, id); 147 if (it != installs_.end()) 148 installs_.erase(it); 149 } 150 151 PendingInstalls::InstallList::iterator PendingInstalls::FindInstall( 152 Profile* profile, 153 const std::string& id) { 154 for (size_t i = 0; i < installs_.size(); ++i) { 155 ProfileAndExtensionId install = installs_[i]; 156 if (install.second == id && profile->IsSameProfile(install.first)) 157 return (installs_.begin() + i); 158 } 159 return installs_.end(); 160 } 161 162 static base::LazyInstance<PendingApprovals> g_pending_approvals = 163 LAZY_INSTANCE_INITIALIZER; 164 static base::LazyInstance<PendingInstalls> g_pending_installs = 165 LAZY_INSTANCE_INITIALIZER; 166 167 // A preference set by the web store to indicate login information for 168 // purchased apps. 169 const char kWebstoreLogin[] = "extensions.webstore_login"; 170 const char kAlreadyInstalledError[] = "This item is already installed"; 171 const char kCannotSpecifyIconDataAndUrlError[] = 172 "You cannot specify both icon data and an icon url"; 173 const char kInvalidIconUrlError[] = "Invalid icon url"; 174 const char kInvalidIdError[] = "Invalid id"; 175 const char kInvalidManifestError[] = "Invalid manifest"; 176 const char kNoPreviousBeginInstallWithManifestError[] = 177 "* does not match a previous call to beginInstallWithManifest3"; 178 const char kUserCancelledError[] = "User cancelled install"; 179 180 WebstoreInstaller::Delegate* test_webstore_installer_delegate = NULL; 181 182 // We allow the web store to set a string containing login information when a 183 // purchase is made, so that when a user logs into sync with a different 184 // account we can recognize the situation. The Get function returns the login if 185 // there was previously stored data, or an empty string otherwise. The Set will 186 // overwrite any previous login. 187 std::string GetWebstoreLogin(Profile* profile) { 188 if (profile->GetPrefs()->HasPrefPath(kWebstoreLogin)) 189 return profile->GetPrefs()->GetString(kWebstoreLogin); 190 return std::string(); 191 } 192 193 void SetWebstoreLogin(Profile* profile, const std::string& login) { 194 profile->GetPrefs()->SetString(kWebstoreLogin, login); 195 } 196 197 void RecordWebstoreExtensionInstallResult(bool success) { 198 UMA_HISTOGRAM_BOOLEAN("Webstore.ExtensionInstallResult", success); 199 } 200 201 } // namespace 202 203 // static 204 void WebstorePrivateApi::SetWebstoreInstallerDelegateForTesting( 205 WebstoreInstaller::Delegate* delegate) { 206 test_webstore_installer_delegate = delegate; 207 } 208 209 // static 210 scoped_ptr<WebstoreInstaller::Approval> 211 WebstorePrivateApi::PopApprovalForTesting( 212 Profile* profile, const std::string& extension_id) { 213 return g_pending_approvals.Get().PopApproval(profile, extension_id); 214 } 215 216 WebstorePrivateInstallBundleFunction::WebstorePrivateInstallBundleFunction() {} 217 WebstorePrivateInstallBundleFunction::~WebstorePrivateInstallBundleFunction() {} 218 219 bool WebstorePrivateInstallBundleFunction::RunAsync() { 220 scoped_ptr<InstallBundle::Params> params( 221 InstallBundle::Params::Create(*args_)); 222 EXTENSION_FUNCTION_VALIDATE(params); 223 224 BundleInstaller::ItemList items; 225 if (!ReadBundleInfo(*params, &items)) 226 return false; 227 228 bundle_ = new BundleInstaller(GetCurrentBrowser(), items); 229 230 AddRef(); // Balanced in OnBundleInstallCompleted / OnBundleInstallCanceled. 231 232 bundle_->PromptForApproval(this); 233 return true; 234 } 235 236 bool WebstorePrivateInstallBundleFunction:: 237 ReadBundleInfo(const InstallBundle::Params& params, 238 BundleInstaller::ItemList* items) { 239 for (size_t i = 0; i < params.details.size(); ++i) { 240 BundleInstaller::Item item; 241 item.id = params.details[i]->id; 242 item.manifest = params.details[i]->manifest; 243 item.localized_name = params.details[i]->localized_name; 244 items->push_back(item); 245 } 246 247 return true; 248 } 249 250 void WebstorePrivateInstallBundleFunction::OnBundleInstallApproved() { 251 bundle_->CompleteInstall( 252 dispatcher()->delegate()->GetAssociatedWebContents(), 253 this); 254 } 255 256 void WebstorePrivateInstallBundleFunction::OnBundleInstallCanceled( 257 bool user_initiated) { 258 if (user_initiated) 259 error_ = "user_canceled"; 260 else 261 error_ = "unknown_error"; 262 263 SendResponse(false); 264 265 Release(); // Balanced in RunAsync(). 266 } 267 268 void WebstorePrivateInstallBundleFunction::OnBundleInstallCompleted() { 269 SendResponse(true); 270 271 Release(); // Balanced in RunAsync(). 272 } 273 274 WebstorePrivateBeginInstallWithManifest3Function:: 275 WebstorePrivateBeginInstallWithManifest3Function() { 276 } 277 278 WebstorePrivateBeginInstallWithManifest3Function:: 279 ~WebstorePrivateBeginInstallWithManifest3Function() { 280 } 281 282 bool WebstorePrivateBeginInstallWithManifest3Function::RunAsync() { 283 params_ = BeginInstallWithManifest3::Params::Create(*args_); 284 EXTENSION_FUNCTION_VALIDATE(params_); 285 286 if (!extensions::Extension::IdIsValid(params_->details.id)) { 287 SetResultCode(INVALID_ID); 288 error_ = kInvalidIdError; 289 return false; 290 } 291 292 if (params_->details.icon_data && params_->details.icon_url) { 293 SetResultCode(ICON_ERROR); 294 error_ = kCannotSpecifyIconDataAndUrlError; 295 return false; 296 } 297 298 GURL icon_url; 299 if (params_->details.icon_url) { 300 std::string tmp_url; 301 icon_url = source_url().Resolve(*params_->details.icon_url); 302 if (!icon_url.is_valid()) { 303 SetResultCode(INVALID_ICON_URL); 304 error_ = kInvalidIconUrlError; 305 return false; 306 } 307 } 308 309 if (params_->details.authuser) { 310 authuser_ = *params_->details.authuser; 311 } 312 313 std::string icon_data = params_->details.icon_data ? 314 *params_->details.icon_data : std::string(); 315 316 Profile* profile = GetProfile(); 317 if (util::IsExtensionInstalledPermanently(params_->details.id, profile) || 318 !g_pending_installs.Get().InsertInstall(profile, params_->details.id)) { 319 SetResultCode(ALREADY_INSTALLED); 320 error_ = kAlreadyInstalledError; 321 return false; 322 } 323 324 net::URLRequestContextGetter* context_getter = NULL; 325 if (!icon_url.is_empty()) 326 context_getter = GetProfile()->GetRequestContext(); 327 328 scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper( 329 this, params_->details.id, params_->details.manifest, icon_data, icon_url, 330 context_getter); 331 332 // The helper will call us back via OnWebstoreParseSuccess or 333 // OnWebstoreParseFailure. 334 helper->Start(); 335 336 // Matched with a Release in OnWebstoreParseSuccess/OnWebstoreParseFailure. 337 AddRef(); 338 339 // The response is sent asynchronously in OnWebstoreParseSuccess/ 340 // OnWebstoreParseFailure. 341 return true; 342 } 343 344 const char* WebstorePrivateBeginInstallWithManifest3Function:: 345 ResultCodeToString(ResultCode code) { 346 switch (code) { 347 case ERROR_NONE: 348 return ""; 349 case UNKNOWN_ERROR: 350 return "unknown_error"; 351 case USER_CANCELLED: 352 return "user_cancelled"; 353 case MANIFEST_ERROR: 354 return "manifest_error"; 355 case ICON_ERROR: 356 return "icon_error"; 357 case INVALID_ID: 358 return "invalid_id"; 359 case PERMISSION_DENIED: 360 return "permission_denied"; 361 case INVALID_ICON_URL: 362 return "invalid_icon_url"; 363 case SIGNIN_FAILED: 364 return "signin_failed"; 365 case ALREADY_INSTALLED: 366 return "already_installed"; 367 } 368 NOTREACHED(); 369 return ""; 370 } 371 372 void WebstorePrivateBeginInstallWithManifest3Function::SetResultCode( 373 ResultCode code) { 374 results_ = BeginInstallWithManifest3::Results::Create( 375 ResultCodeToString(code)); 376 } 377 378 void WebstorePrivateBeginInstallWithManifest3Function::OnWebstoreParseSuccess( 379 const std::string& id, 380 const SkBitmap& icon, 381 base::DictionaryValue* parsed_manifest) { 382 CHECK_EQ(params_->details.id, id); 383 CHECK(parsed_manifest); 384 icon_ = icon; 385 parsed_manifest_.reset(parsed_manifest); 386 387 std::string localized_name = params_->details.localized_name ? 388 *params_->details.localized_name : std::string(); 389 390 std::string error; 391 dummy_extension_ = ExtensionInstallPrompt::GetLocalizedExtensionForDisplay( 392 parsed_manifest_.get(), 393 Extension::FROM_WEBSTORE, 394 id, 395 localized_name, 396 std::string(), 397 &error); 398 399 if (!dummy_extension_.get()) { 400 OnWebstoreParseFailure(params_->details.id, 401 WebstoreInstallHelper::Delegate::MANIFEST_ERROR, 402 kInvalidManifestError); 403 return; 404 } 405 406 SigninManagerBase* signin_manager = 407 SigninManagerFactory::GetForProfile(GetProfile()); 408 if (dummy_extension_->is_platform_app() && 409 signin_manager && 410 signin_manager->GetAuthenticatedUsername().empty() && 411 signin_manager->AuthInProgress()) { 412 signin_tracker_ = 413 SigninTrackerFactory::CreateForProfile(GetProfile(), this); 414 return; 415 } 416 417 SigninCompletedOrNotNeeded(); 418 } 419 420 void WebstorePrivateBeginInstallWithManifest3Function::OnWebstoreParseFailure( 421 const std::string& id, 422 WebstoreInstallHelper::Delegate::InstallHelperResultCode result_code, 423 const std::string& error_message) { 424 CHECK_EQ(params_->details.id, id); 425 426 // Map from WebstoreInstallHelper's result codes to ours. 427 switch (result_code) { 428 case WebstoreInstallHelper::Delegate::UNKNOWN_ERROR: 429 SetResultCode(UNKNOWN_ERROR); 430 break; 431 case WebstoreInstallHelper::Delegate::ICON_ERROR: 432 SetResultCode(ICON_ERROR); 433 break; 434 case WebstoreInstallHelper::Delegate::MANIFEST_ERROR: 435 SetResultCode(MANIFEST_ERROR); 436 break; 437 default: 438 CHECK(false); 439 } 440 error_ = error_message; 441 g_pending_installs.Get().EraseInstall(GetProfile(), id); 442 SendResponse(false); 443 444 // Matches the AddRef in RunAsync(). 445 Release(); 446 } 447 448 void WebstorePrivateBeginInstallWithManifest3Function::SigninFailed( 449 const GoogleServiceAuthError& error) { 450 signin_tracker_.reset(); 451 452 SetResultCode(SIGNIN_FAILED); 453 error_ = error.ToString(); 454 g_pending_installs.Get().EraseInstall(GetProfile(), params_->details.id); 455 SendResponse(false); 456 457 // Matches the AddRef in RunAsync(). 458 Release(); 459 } 460 461 void WebstorePrivateBeginInstallWithManifest3Function::SigninSuccess() { 462 signin_tracker_.reset(); 463 464 SigninCompletedOrNotNeeded(); 465 } 466 467 void WebstorePrivateBeginInstallWithManifest3Function::MergeSessionComplete( 468 const GoogleServiceAuthError& error) { 469 // TODO(rogerta): once the embeded inline flow is enabled, the code in 470 // WebstorePrivateBeginInstallWithManifest3Function::SigninSuccess() 471 // should move to here. 472 } 473 474 void WebstorePrivateBeginInstallWithManifest3Function:: 475 SigninCompletedOrNotNeeded() { 476 content::WebContents* web_contents = GetAssociatedWebContents(); 477 if (!web_contents) // The browser window has gone away. 478 return; 479 install_prompt_.reset(new ExtensionInstallPrompt(web_contents)); 480 install_prompt_->ConfirmWebstoreInstall( 481 this, 482 dummy_extension_.get(), 483 &icon_, 484 ExtensionInstallPrompt::GetDefaultShowDialogCallback()); 485 // Control flow finishes up in InstallUIProceed or InstallUIAbort. 486 } 487 488 void WebstorePrivateBeginInstallWithManifest3Function::InstallUIProceed() { 489 // This gets cleared in CrxInstaller::ConfirmInstall(). TODO(asargent) - in 490 // the future we may also want to add time-based expiration, where a whitelist 491 // entry is only valid for some number of minutes. 492 scoped_ptr<WebstoreInstaller::Approval> approval( 493 WebstoreInstaller::Approval::CreateWithNoInstallPrompt( 494 GetProfile(), params_->details.id, parsed_manifest_.Pass(), false)); 495 approval->use_app_installed_bubble = params_->details.app_install_bubble; 496 approval->enable_launcher = params_->details.enable_launcher; 497 // If we are enabling the launcher, we should not show the app list in order 498 // to train the user to open it themselves at least once. 499 approval->skip_post_install_ui = params_->details.enable_launcher; 500 approval->dummy_extension = dummy_extension_; 501 approval->installing_icon = gfx::ImageSkia::CreateFrom1xBitmap(icon_); 502 approval->authuser = authuser_; 503 g_pending_approvals.Get().PushApproval(approval.Pass()); 504 505 SetResultCode(ERROR_NONE); 506 SendResponse(true); 507 508 // The Permissions_Install histogram is recorded from the ExtensionService 509 // for all extension installs, so we only need to record the web store 510 // specific histogram here. 511 ExtensionService::RecordPermissionMessagesHistogram( 512 dummy_extension_.get(), "Extensions.Permissions_WebStoreInstall2"); 513 514 // Matches the AddRef in RunAsync(). 515 Release(); 516 } 517 518 void WebstorePrivateBeginInstallWithManifest3Function::InstallUIAbort( 519 bool user_initiated) { 520 error_ = kUserCancelledError; 521 SetResultCode(USER_CANCELLED); 522 g_pending_installs.Get().EraseInstall(GetProfile(), params_->details.id); 523 SendResponse(false); 524 525 // The web store install histograms are a subset of the install histograms. 526 // We need to record both histograms here since CrxInstaller::InstallUIAbort 527 // is never called for web store install cancellations. 528 std::string histogram_name = 529 user_initiated ? "Extensions.Permissions_WebStoreInstallCancel2" 530 : "Extensions.Permissions_WebStoreInstallAbort2"; 531 ExtensionService::RecordPermissionMessagesHistogram(dummy_extension_.get(), 532 histogram_name.c_str()); 533 534 histogram_name = user_initiated ? "Extensions.Permissions_InstallCancel2" 535 : "Extensions.Permissions_InstallAbort2"; 536 ExtensionService::RecordPermissionMessagesHistogram(dummy_extension_.get(), 537 histogram_name.c_str()); 538 539 // Matches the AddRef in RunAsync(). 540 Release(); 541 } 542 543 WebstorePrivateCompleteInstallFunction:: 544 WebstorePrivateCompleteInstallFunction() {} 545 546 WebstorePrivateCompleteInstallFunction:: 547 ~WebstorePrivateCompleteInstallFunction() {} 548 549 bool WebstorePrivateCompleteInstallFunction::RunAsync() { 550 scoped_ptr<CompleteInstall::Params> params( 551 CompleteInstall::Params::Create(*args_)); 552 EXTENSION_FUNCTION_VALIDATE(params); 553 if (!extensions::Extension::IdIsValid(params->expected_id)) { 554 error_ = kInvalidIdError; 555 return false; 556 } 557 558 approval_ = g_pending_approvals.Get() 559 .PopApproval(GetProfile(), params->expected_id) 560 .Pass(); 561 if (!approval_) { 562 error_ = ErrorUtils::FormatErrorMessage( 563 kNoPreviousBeginInstallWithManifestError, params->expected_id); 564 return false; 565 } 566 567 AppListService* app_list_service = 568 AppListService::Get(GetCurrentBrowser()->host_desktop_type()); 569 570 if (approval_->enable_launcher) { 571 app_list_service->EnableAppList(GetProfile(), 572 AppListService::ENABLE_FOR_APP_INSTALL); 573 } 574 575 if (IsAppLauncherEnabled() && approval_->manifest->is_app()) { 576 // Show the app list to show download is progressing. Don't show the app 577 // list on first app install so users can be trained to open it themselves. 578 if (approval_->enable_launcher) 579 app_list_service->CreateForProfile(GetProfile()); 580 else 581 app_list_service->AutoShowForProfile(GetProfile()); 582 } 583 584 // If the target extension has already been installed ephemerally, it can 585 // be promoted to a regular installed extension and downloading from the Web 586 // Store is not necessary. 587 const Extension* extension = ExtensionRegistry::Get(GetProfile())-> 588 GetExtensionById(params->expected_id, ExtensionRegistry::EVERYTHING); 589 if (extension && util::IsEphemeralApp(extension->id(), GetProfile())) { 590 ExtensionService* extension_service = 591 ExtensionSystem::Get(GetProfile())->extension_service(); 592 extension_service->PromoteEphemeralApp(extension, false); 593 OnInstallSuccess(extension->id()); 594 return true; 595 } 596 597 // Balanced in OnExtensionInstallSuccess() or OnExtensionInstallFailure(). 598 AddRef(); 599 600 // The extension will install through the normal extension install flow, but 601 // the whitelist entry will bypass the normal permissions install dialog. 602 scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller( 603 GetProfile(), 604 this, 605 dispatcher()->delegate()->GetAssociatedWebContents(), 606 params->expected_id, 607 approval_.Pass(), 608 WebstoreInstaller::INSTALL_SOURCE_OTHER); 609 installer->Start(); 610 611 return true; 612 } 613 614 void WebstorePrivateCompleteInstallFunction::OnExtensionInstallSuccess( 615 const std::string& id) { 616 OnInstallSuccess(id); 617 RecordWebstoreExtensionInstallResult(true); 618 619 // Matches the AddRef in RunAsync(). 620 Release(); 621 } 622 623 void WebstorePrivateCompleteInstallFunction::OnExtensionInstallFailure( 624 const std::string& id, 625 const std::string& error, 626 WebstoreInstaller::FailureReason reason) { 627 if (test_webstore_installer_delegate) { 628 test_webstore_installer_delegate->OnExtensionInstallFailure( 629 id, error, reason); 630 } 631 632 error_ = error; 633 VLOG(1) << "Install failed, sending response"; 634 g_pending_installs.Get().EraseInstall(GetProfile(), id); 635 SendResponse(false); 636 637 RecordWebstoreExtensionInstallResult(false); 638 639 // Matches the AddRef in RunAsync(). 640 Release(); 641 } 642 643 void WebstorePrivateCompleteInstallFunction::OnInstallSuccess( 644 const std::string& id) { 645 if (test_webstore_installer_delegate) 646 test_webstore_installer_delegate->OnExtensionInstallSuccess(id); 647 648 VLOG(1) << "Install success, sending response"; 649 g_pending_installs.Get().EraseInstall(GetProfile(), id); 650 SendResponse(true); 651 } 652 653 WebstorePrivateEnableAppLauncherFunction:: 654 WebstorePrivateEnableAppLauncherFunction() {} 655 656 WebstorePrivateEnableAppLauncherFunction:: 657 ~WebstorePrivateEnableAppLauncherFunction() {} 658 659 bool WebstorePrivateEnableAppLauncherFunction::RunSync() { 660 AppListService::Get(GetCurrentBrowser()->host_desktop_type()) 661 ->EnableAppList(GetProfile(), AppListService::ENABLE_VIA_WEBSTORE_LINK); 662 return true; 663 } 664 665 bool WebstorePrivateGetBrowserLoginFunction::RunSync() { 666 GetBrowserLogin::Results::Info info; 667 info.login = GetProfile()->GetOriginalProfile()->GetPrefs()->GetString( 668 prefs::kGoogleServicesUsername); 669 results_ = GetBrowserLogin::Results::Create(info); 670 return true; 671 } 672 673 bool WebstorePrivateGetStoreLoginFunction::RunSync() { 674 results_ = GetStoreLogin::Results::Create(GetWebstoreLogin(GetProfile())); 675 return true; 676 } 677 678 bool WebstorePrivateSetStoreLoginFunction::RunSync() { 679 scoped_ptr<SetStoreLogin::Params> params( 680 SetStoreLogin::Params::Create(*args_)); 681 EXTENSION_FUNCTION_VALIDATE(params); 682 SetWebstoreLogin(GetProfile(), params->login); 683 return true; 684 } 685 686 WebstorePrivateGetWebGLStatusFunction::WebstorePrivateGetWebGLStatusFunction() { 687 feature_checker_ = new GPUFeatureChecker( 688 gpu::GPU_FEATURE_TYPE_WEBGL, 689 base::Bind(&WebstorePrivateGetWebGLStatusFunction::OnFeatureCheck, 690 base::Unretained(this))); 691 } 692 693 WebstorePrivateGetWebGLStatusFunction:: 694 ~WebstorePrivateGetWebGLStatusFunction() {} 695 696 void WebstorePrivateGetWebGLStatusFunction::CreateResult(bool webgl_allowed) { 697 results_ = GetWebGLStatus::Results::Create(GetWebGLStatus::Results:: 698 ParseWebgl_status(webgl_allowed ? "webgl_allowed" : "webgl_blocked")); 699 } 700 701 bool WebstorePrivateGetWebGLStatusFunction::RunAsync() { 702 feature_checker_->CheckGPUFeatureAvailability(); 703 return true; 704 } 705 706 void WebstorePrivateGetWebGLStatusFunction:: 707 OnFeatureCheck(bool feature_allowed) { 708 CreateResult(feature_allowed); 709 SendResponse(true); 710 } 711 712 bool WebstorePrivateGetIsLauncherEnabledFunction::RunSync() { 713 results_ = GetIsLauncherEnabled::Results::Create(IsAppLauncherEnabled()); 714 return true; 715 } 716 717 bool WebstorePrivateIsInIncognitoModeFunction::RunSync() { 718 results_ = IsInIncognitoMode::Results::Create( 719 GetProfile() != GetProfile()->GetOriginalProfile()); 720 return true; 721 } 722 723 WebstorePrivateSignInFunction::WebstorePrivateSignInFunction() 724 : signin_manager_(NULL) {} 725 WebstorePrivateSignInFunction::~WebstorePrivateSignInFunction() {} 726 727 bool WebstorePrivateSignInFunction::RunAsync() { 728 scoped_ptr<SignIn::Params> params = SignIn::Params::Create(*args_); 729 EXTENSION_FUNCTION_VALIDATE(params); 730 731 // This API must be called only in response to a user gesture. 732 if (!user_gesture()) { 733 error_ = "user_gesture_required"; 734 SendResponse(false); 735 return false; 736 } 737 738 // The |continue_url| is required, and must be hosted on the same origin as 739 // the calling page. 740 GURL continue_url(params->continue_url); 741 content::WebContents* web_contents = GetAssociatedWebContents(); 742 if (!continue_url.is_valid() || 743 continue_url.GetOrigin() != 744 web_contents->GetLastCommittedURL().GetOrigin()) { 745 error_ = "invalid_continue_url"; 746 SendResponse(false); 747 return false; 748 } 749 750 // If sign-in is disallowed, give up. 751 signin_manager_ = SigninManagerFactory::GetForProfile(GetProfile()); 752 if (!signin_manager_ || !signin_manager_->IsSigninAllowed() || 753 switches::IsEnableWebBasedSignin()) { 754 error_ = "signin_is_disallowed"; 755 SendResponse(false); 756 return false; 757 } 758 759 // If the user is already signed in, there's nothing else to do. 760 if (!signin_manager_->GetAuthenticatedUsername().empty()) { 761 SendResponse(true); 762 return true; 763 } 764 765 // If an authentication is currently in progress, wait for it to complete. 766 if (signin_manager_->AuthInProgress()) { 767 SigninManagerFactory::GetInstance()->AddObserver(this); 768 signin_tracker_ = 769 SigninTrackerFactory::CreateForProfile(GetProfile(), this).Pass(); 770 AddRef(); // Balanced in the sign-in observer methods below. 771 return true; 772 } 773 774 GURL signin_url = 775 signin::GetPromoURLWithContinueURL(signin::SOURCE_WEBSTORE_INSTALL, 776 false /* auto_close */, 777 false /* is_constrained */, 778 continue_url); 779 web_contents->GetController().LoadURL(signin_url, 780 content::Referrer(), 781 content::PAGE_TRANSITION_AUTO_TOPLEVEL, 782 std::string()); 783 784 SendResponse(true); 785 return true; 786 } 787 788 void WebstorePrivateSignInFunction::SigninManagerShutdown( 789 SigninManagerBase* manager) { 790 if (manager == signin_manager_) 791 SigninFailed(GoogleServiceAuthError::AuthErrorNone()); 792 } 793 794 void WebstorePrivateSignInFunction::SigninFailed( 795 const GoogleServiceAuthError& error) { 796 error_ = "signin_failed"; 797 SendResponse(false); 798 799 SigninManagerFactory::GetInstance()->RemoveObserver(this); 800 Release(); // Balanced in RunAsync(). 801 } 802 803 void WebstorePrivateSignInFunction::SigninSuccess() { 804 // Nothing to do yet. Keep waiting until MergeSessionComplete() is called. 805 } 806 807 void WebstorePrivateSignInFunction::MergeSessionComplete( 808 const GoogleServiceAuthError& error) { 809 if (error.state() == GoogleServiceAuthError::NONE) { 810 SendResponse(true); 811 } else { 812 error_ = "merge_session_failed"; 813 SendResponse(false); 814 } 815 816 SigninManagerFactory::GetInstance()->RemoveObserver(this); 817 Release(); // Balanced in RunAsync(). 818 } 819 820 } // namespace extensions 821