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.
5 #include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h"
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/extension_util.h"
22 #include "chrome/browser/extensions/webstore_installer.h"
23 #include "chrome/browser/gpu/gpu_feature_checker.h"
24 #include "chrome/browser/profiles/profile_manager.h"
25 #include "chrome/browser/signin/signin_manager_factory.h"
26 #include "chrome/browser/signin/signin_promo.h"
27 #include "chrome/browser/signin/signin_tracker_factory.h"
28 #include "chrome/browser/sync/profile_sync_service.h"
29 #include "chrome/browser/sync/profile_sync_service_factory.h"
30 #include "chrome/browser/ui/app_list/app_list_service.h"
31 #include "chrome/browser/ui/app_list/app_list_util.h"
32 #include "chrome/browser/ui/browser.h"
33 #include "chrome/common/extensions/extension_constants.h"
34 #include "chrome/common/pref_names.h"
35 #include "components/signin/core/browser/signin_manager.h"
36 #include "components/signin/core/common/profile_management_switches.h"
37 #include "content/public/browser/gpu_data_manager.h"
38 #include "content/public/browser/notification_details.h"
39 #include "content/public/browser/notification_source.h"
40 #include "content/public/browser/web_contents.h"
41 #include "content/public/common/page_transition_types.h"
42 #include "content/public/common/referrer.h"
43 #include "extensions/browser/extension_function_dispatcher.h"
44 #include "extensions/browser/extension_prefs.h"
45 #include "extensions/browser/extension_system.h"
46 #include "extensions/common/error_utils.h"
47 #include "extensions/common/extension.h"
48 #include "extensions/common/extension_l10n_util.h"
49 #include "google_apis/gaia/google_service_auth_error.h"
50 #include "grit/chromium_strings.h"
51 #include "grit/generated_resources.h"
52 #include "ui/base/l10n/l10n_util.h"
55 using content::GpuDataManager;
57 namespace extensions {
59 namespace BeginInstallWithManifest3 =
60 api::webstore_private::BeginInstallWithManifest3;
61 namespace CompleteInstall = api::webstore_private::CompleteInstall;
62 namespace GetBrowserLogin = api::webstore_private::GetBrowserLogin;
63 namespace GetIsLauncherEnabled = api::webstore_private::GetIsLauncherEnabled;
64 namespace GetStoreLogin = api::webstore_private::GetStoreLogin;
65 namespace GetWebGLStatus = api::webstore_private::GetWebGLStatus;
66 namespace InstallBundle = api::webstore_private::InstallBundle;
67 namespace IsInIncognitoMode = api::webstore_private::IsInIncognitoMode;
68 namespace SignIn = api::webstore_private::SignIn;
69 namespace SetStoreLogin = api::webstore_private::SetStoreLogin;
73 // Holds the Approvals between the time we prompt and start the installs.
74 class PendingApprovals {
79 void PushApproval(scoped_ptr<WebstoreInstaller::Approval> approval);
80 scoped_ptr<WebstoreInstaller::Approval> PopApproval(
81 Profile* profile, const std::string& id);
83 typedef ScopedVector<WebstoreInstaller::Approval> ApprovalList;
85 ApprovalList approvals_;
87 DISALLOW_COPY_AND_ASSIGN(PendingApprovals);
90 PendingApprovals::PendingApprovals() {}
91 PendingApprovals::~PendingApprovals() {}
93 void PendingApprovals::PushApproval(
94 scoped_ptr<WebstoreInstaller::Approval> approval) {
95 approvals_.push_back(approval.release());
98 scoped_ptr<WebstoreInstaller::Approval> PendingApprovals::PopApproval(
99 Profile* profile, const std::string& id) {
100 for (size_t i = 0; i < approvals_.size(); ++i) {
101 WebstoreInstaller::Approval* approval = approvals_[i];
102 if (approval->extension_id == id &&
103 profile->IsSameProfile(approval->profile)) {
104 approvals_.weak_erase(approvals_.begin() + i);
105 return scoped_ptr<WebstoreInstaller::Approval>(approval);
108 return scoped_ptr<WebstoreInstaller::Approval>();
111 // Uniquely holds the profile and extension id of an install between the time we
112 // prompt and complete the installs.
113 class PendingInstalls {
118 bool InsertInstall(Profile* profile, const std::string& id);
119 void EraseInstall(Profile* profile, const std::string& id);
121 typedef std::pair<Profile*, std::string> ProfileAndExtensionId;
122 typedef std::vector<ProfileAndExtensionId> InstallList;
124 InstallList::iterator FindInstall(Profile* profile, const std::string& id);
126 InstallList installs_;
128 DISALLOW_COPY_AND_ASSIGN(PendingInstalls);
131 PendingInstalls::PendingInstalls() {}
132 PendingInstalls::~PendingInstalls() {}
134 // Returns true and inserts the profile/id pair if it is not present. Otherwise
136 bool PendingInstalls::InsertInstall(Profile* profile, const std::string& id) {
137 if (FindInstall(profile, id) != installs_.end())
139 installs_.push_back(make_pair(profile, id));
143 // Removes the given profile/id pair.
144 void PendingInstalls::EraseInstall(Profile* profile, const std::string& id) {
145 InstallList::iterator it = FindInstall(profile, id);
146 if (it != installs_.end())
150 PendingInstalls::InstallList::iterator PendingInstalls::FindInstall(
152 const std::string& id) {
153 for (size_t i = 0; i < installs_.size(); ++i) {
154 ProfileAndExtensionId install = installs_[i];
155 if (install.second == id && profile->IsSameProfile(install.first))
156 return (installs_.begin() + i);
158 return installs_.end();
161 static base::LazyInstance<PendingApprovals> g_pending_approvals =
162 LAZY_INSTANCE_INITIALIZER;
163 static base::LazyInstance<PendingInstalls> g_pending_installs =
164 LAZY_INSTANCE_INITIALIZER;
166 // A preference set by the web store to indicate login information for
168 const char kWebstoreLogin[] = "extensions.webstore_login";
169 const char kAlreadyInstalledError[] = "This item is already installed";
170 const char kCannotSpecifyIconDataAndUrlError[] =
171 "You cannot specify both icon data and an icon url";
172 const char kInvalidIconUrlError[] = "Invalid icon url";
173 const char kInvalidIdError[] = "Invalid id";
174 const char kInvalidManifestError[] = "Invalid manifest";
175 const char kNoPreviousBeginInstallWithManifestError[] =
176 "* does not match a previous call to beginInstallWithManifest3";
177 const char kUserCancelledError[] = "User cancelled install";
179 WebstoreInstaller::Delegate* test_webstore_installer_delegate = NULL;
181 // We allow the web store to set a string containing login information when a
182 // purchase is made, so that when a user logs into sync with a different
183 // account we can recognize the situation. The Get function returns the login if
184 // there was previously stored data, or an empty string otherwise. The Set will
185 // overwrite any previous login.
186 std::string GetWebstoreLogin(Profile* profile) {
187 if (profile->GetPrefs()->HasPrefPath(kWebstoreLogin))
188 return profile->GetPrefs()->GetString(kWebstoreLogin);
189 return std::string();
192 void SetWebstoreLogin(Profile* profile, const std::string& login) {
193 profile->GetPrefs()->SetString(kWebstoreLogin, login);
196 void RecordWebstoreExtensionInstallResult(bool success) {
197 UMA_HISTOGRAM_BOOLEAN("Webstore.ExtensionInstallResult", success);
203 void WebstorePrivateApi::SetWebstoreInstallerDelegateForTesting(
204 WebstoreInstaller::Delegate* delegate) {
205 test_webstore_installer_delegate = delegate;
209 scoped_ptr<WebstoreInstaller::Approval>
210 WebstorePrivateApi::PopApprovalForTesting(
211 Profile* profile, const std::string& extension_id) {
212 return g_pending_approvals.Get().PopApproval(profile, extension_id);
215 WebstorePrivateInstallBundleFunction::WebstorePrivateInstallBundleFunction() {}
216 WebstorePrivateInstallBundleFunction::~WebstorePrivateInstallBundleFunction() {}
218 bool WebstorePrivateInstallBundleFunction::RunAsync() {
219 scoped_ptr<InstallBundle::Params> params(
220 InstallBundle::Params::Create(*args_));
221 EXTENSION_FUNCTION_VALIDATE(params);
223 BundleInstaller::ItemList items;
224 if (!ReadBundleInfo(*params, &items))
227 bundle_ = new BundleInstaller(GetCurrentBrowser(), items);
229 AddRef(); // Balanced in OnBundleInstallCompleted / OnBundleInstallCanceled.
231 bundle_->PromptForApproval(this);
235 bool WebstorePrivateInstallBundleFunction::
236 ReadBundleInfo(const InstallBundle::Params& params,
237 BundleInstaller::ItemList* items) {
238 for (size_t i = 0; i < params.details.size(); ++i) {
239 BundleInstaller::Item item;
240 item.id = params.details[i]->id;
241 item.manifest = params.details[i]->manifest;
242 item.localized_name = params.details[i]->localized_name;
243 items->push_back(item);
249 void WebstorePrivateInstallBundleFunction::OnBundleInstallApproved() {
250 bundle_->CompleteInstall(
251 dispatcher()->delegate()->GetAssociatedWebContents(),
255 void WebstorePrivateInstallBundleFunction::OnBundleInstallCanceled(
256 bool user_initiated) {
258 error_ = "user_canceled";
260 error_ = "unknown_error";
264 Release(); // Balanced in RunAsync().
267 void WebstorePrivateInstallBundleFunction::OnBundleInstallCompleted() {
270 Release(); // Balanced in RunAsync().
273 WebstorePrivateBeginInstallWithManifest3Function::
274 WebstorePrivateBeginInstallWithManifest3Function() {
277 WebstorePrivateBeginInstallWithManifest3Function::
278 ~WebstorePrivateBeginInstallWithManifest3Function() {
281 bool WebstorePrivateBeginInstallWithManifest3Function::RunAsync() {
282 params_ = BeginInstallWithManifest3::Params::Create(*args_);
283 EXTENSION_FUNCTION_VALIDATE(params_);
285 if (!extensions::Extension::IdIsValid(params_->details.id)) {
286 SetResultCode(INVALID_ID);
287 error_ = kInvalidIdError;
291 if (params_->details.icon_data && params_->details.icon_url) {
292 SetResultCode(ICON_ERROR);
293 error_ = kCannotSpecifyIconDataAndUrlError;
298 if (params_->details.icon_url) {
300 icon_url = source_url().Resolve(*params_->details.icon_url);
301 if (!icon_url.is_valid()) {
302 SetResultCode(INVALID_ICON_URL);
303 error_ = kInvalidIconUrlError;
308 if (params_->details.authuser) {
309 authuser_ = *params_->details.authuser;
312 std::string icon_data = params_->details.icon_data ?
313 *params_->details.icon_data : std::string();
315 Profile* profile = GetProfile();
316 if (util::IsExtensionInstalledPermanently(params_->details.id, profile) ||
317 !g_pending_installs.Get().InsertInstall(profile, params_->details.id)) {
318 SetResultCode(ALREADY_INSTALLED);
319 error_ = kAlreadyInstalledError;
323 net::URLRequestContextGetter* context_getter = NULL;
324 if (!icon_url.is_empty())
325 context_getter = GetProfile()->GetRequestContext();
327 scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper(
328 this, params_->details.id, params_->details.manifest, icon_data, icon_url,
331 // The helper will call us back via OnWebstoreParseSuccess or
332 // OnWebstoreParseFailure.
335 // Matched with a Release in OnWebstoreParseSuccess/OnWebstoreParseFailure.
338 // The response is sent asynchronously in OnWebstoreParseSuccess/
339 // OnWebstoreParseFailure.
343 const char* WebstorePrivateBeginInstallWithManifest3Function::
344 ResultCodeToString(ResultCode code) {
349 return "unknown_error";
351 return "user_cancelled";
353 return "manifest_error";
358 case PERMISSION_DENIED:
359 return "permission_denied";
360 case INVALID_ICON_URL:
361 return "invalid_icon_url";
363 return "signin_failed";
364 case ALREADY_INSTALLED:
365 return "already_installed";
371 void WebstorePrivateBeginInstallWithManifest3Function::SetResultCode(
373 results_ = BeginInstallWithManifest3::Results::Create(
374 ResultCodeToString(code));
377 void WebstorePrivateBeginInstallWithManifest3Function::OnWebstoreParseSuccess(
378 const std::string& id,
379 const SkBitmap& icon,
380 base::DictionaryValue* parsed_manifest) {
381 CHECK_EQ(params_->details.id, id);
382 CHECK(parsed_manifest);
384 parsed_manifest_.reset(parsed_manifest);
386 std::string localized_name = params_->details.localized_name ?
387 *params_->details.localized_name : std::string();
390 dummy_extension_ = ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
391 parsed_manifest_.get(),
392 Extension::FROM_WEBSTORE,
398 if (!dummy_extension_.get()) {
399 OnWebstoreParseFailure(params_->details.id,
400 WebstoreInstallHelper::Delegate::MANIFEST_ERROR,
401 kInvalidManifestError);
405 SigninManagerBase* signin_manager =
406 SigninManagerFactory::GetForProfile(GetProfile());
407 if (dummy_extension_->is_platform_app() &&
409 signin_manager->GetAuthenticatedUsername().empty() &&
410 signin_manager->AuthInProgress()) {
412 SigninTrackerFactory::CreateForProfile(GetProfile(), this);
416 SigninCompletedOrNotNeeded();
419 void WebstorePrivateBeginInstallWithManifest3Function::OnWebstoreParseFailure(
420 const std::string& id,
421 WebstoreInstallHelper::Delegate::InstallHelperResultCode result_code,
422 const std::string& error_message) {
423 CHECK_EQ(params_->details.id, id);
425 // Map from WebstoreInstallHelper's result codes to ours.
426 switch (result_code) {
427 case WebstoreInstallHelper::Delegate::UNKNOWN_ERROR:
428 SetResultCode(UNKNOWN_ERROR);
430 case WebstoreInstallHelper::Delegate::ICON_ERROR:
431 SetResultCode(ICON_ERROR);
433 case WebstoreInstallHelper::Delegate::MANIFEST_ERROR:
434 SetResultCode(MANIFEST_ERROR);
439 error_ = error_message;
440 g_pending_installs.Get().EraseInstall(GetProfile(), id);
443 // Matches the AddRef in RunAsync().
447 void WebstorePrivateBeginInstallWithManifest3Function::SigninFailed(
448 const GoogleServiceAuthError& error) {
449 signin_tracker_.reset();
451 SetResultCode(SIGNIN_FAILED);
452 error_ = error.ToString();
453 g_pending_installs.Get().EraseInstall(GetProfile(), params_->details.id);
456 // Matches the AddRef in RunAsync().
460 void WebstorePrivateBeginInstallWithManifest3Function::SigninSuccess() {
461 signin_tracker_.reset();
463 SigninCompletedOrNotNeeded();
466 void WebstorePrivateBeginInstallWithManifest3Function::MergeSessionComplete(
467 const GoogleServiceAuthError& error) {
468 // TODO(rogerta): once the embeded inline flow is enabled, the code in
469 // WebstorePrivateBeginInstallWithManifest3Function::SigninSuccess()
470 // should move to here.
473 void WebstorePrivateBeginInstallWithManifest3Function::
474 SigninCompletedOrNotNeeded() {
475 content::WebContents* web_contents = GetAssociatedWebContents();
476 if (!web_contents) // The browser window has gone away.
478 install_prompt_.reset(new ExtensionInstallPrompt(web_contents));
479 install_prompt_->ConfirmWebstoreInstall(
481 dummy_extension_.get(),
483 ExtensionInstallPrompt::GetDefaultShowDialogCallback());
484 // Control flow finishes up in InstallUIProceed or InstallUIAbort.
487 void WebstorePrivateBeginInstallWithManifest3Function::InstallUIProceed() {
488 // This gets cleared in CrxInstaller::ConfirmInstall(). TODO(asargent) - in
489 // the future we may also want to add time-based expiration, where a whitelist
490 // entry is only valid for some number of minutes.
491 scoped_ptr<WebstoreInstaller::Approval> approval(
492 WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
493 GetProfile(), params_->details.id, parsed_manifest_.Pass(), false));
494 approval->use_app_installed_bubble = params_->details.app_install_bubble;
495 approval->enable_launcher = params_->details.enable_launcher;
496 // If we are enabling the launcher, we should not show the app list in order
497 // to train the user to open it themselves at least once.
498 approval->skip_post_install_ui = params_->details.enable_launcher;
499 approval->dummy_extension = dummy_extension_;
500 approval->installing_icon = gfx::ImageSkia::CreateFrom1xBitmap(icon_);
501 approval->authuser = authuser_;
502 g_pending_approvals.Get().PushApproval(approval.Pass());
504 SetResultCode(ERROR_NONE);
507 // The Permissions_Install histogram is recorded from the ExtensionService
508 // for all extension installs, so we only need to record the web store
509 // specific histogram here.
510 ExtensionService::RecordPermissionMessagesHistogram(
511 dummy_extension_.get(), "Extensions.Permissions_WebStoreInstall");
513 // Matches the AddRef in RunAsync().
517 void WebstorePrivateBeginInstallWithManifest3Function::InstallUIAbort(
518 bool user_initiated) {
519 error_ = kUserCancelledError;
520 SetResultCode(USER_CANCELLED);
521 g_pending_installs.Get().EraseInstall(GetProfile(), params_->details.id);
524 // The web store install histograms are a subset of the install histograms.
525 // We need to record both histograms here since CrxInstaller::InstallUIAbort
526 // is never called for web store install cancellations.
527 std::string histogram_name = user_initiated ?
528 "Extensions.Permissions_WebStoreInstallCancel" :
529 "Extensions.Permissions_WebStoreInstallAbort";
530 ExtensionService::RecordPermissionMessagesHistogram(dummy_extension_.get(),
531 histogram_name.c_str());
533 histogram_name = user_initiated ?
534 "Extensions.Permissions_InstallCancel" :
535 "Extensions.Permissions_InstallAbort";
536 ExtensionService::RecordPermissionMessagesHistogram(dummy_extension_.get(),
537 histogram_name.c_str());
539 // Matches the AddRef in RunAsync().
543 WebstorePrivateCompleteInstallFunction::
544 WebstorePrivateCompleteInstallFunction() {}
546 WebstorePrivateCompleteInstallFunction::
547 ~WebstorePrivateCompleteInstallFunction() {}
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;
558 approval_ = g_pending_approvals.Get()
559 .PopApproval(GetProfile(), params->expected_id)
562 error_ = ErrorUtils::FormatErrorMessage(
563 kNoPreviousBeginInstallWithManifestError, params->expected_id);
567 // Balanced in OnExtensionInstallSuccess() or OnExtensionInstallFailure().
569 AppListService* app_list_service =
570 AppListService::Get(GetCurrentBrowser()->host_desktop_type());
572 if (approval_->enable_launcher) {
573 app_list_service->EnableAppList(GetProfile(),
574 AppListService::ENABLE_FOR_APP_INSTALL);
577 if (IsAppLauncherEnabled() && approval_->manifest->is_app()) {
578 // Show the app list to show download is progressing. Don't show the app
579 // list on first app install so users can be trained to open it themselves.
580 if (approval_->enable_launcher)
581 app_list_service->CreateForProfile(GetProfile());
583 app_list_service->AutoShowForProfile(GetProfile());
586 // The extension will install through the normal extension install flow, but
587 // the whitelist entry will bypass the normal permissions install dialog.
588 scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller(
591 dispatcher()->delegate()->GetAssociatedWebContents(),
594 WebstoreInstaller::INSTALL_SOURCE_OTHER);
600 void WebstorePrivateCompleteInstallFunction::OnExtensionInstallSuccess(
601 const std::string& id) {
602 if (test_webstore_installer_delegate)
603 test_webstore_installer_delegate->OnExtensionInstallSuccess(id);
605 VLOG(1) << "Install success, sending response";
606 g_pending_installs.Get().EraseInstall(GetProfile(), id);
609 RecordWebstoreExtensionInstallResult(true);
611 // Matches the AddRef in RunAsync().
615 void WebstorePrivateCompleteInstallFunction::OnExtensionInstallFailure(
616 const std::string& id,
617 const std::string& error,
618 WebstoreInstaller::FailureReason reason) {
619 if (test_webstore_installer_delegate) {
620 test_webstore_installer_delegate->OnExtensionInstallFailure(
625 VLOG(1) << "Install failed, sending response";
626 g_pending_installs.Get().EraseInstall(GetProfile(), id);
629 RecordWebstoreExtensionInstallResult(false);
631 // Matches the AddRef in RunAsync().
635 WebstorePrivateEnableAppLauncherFunction::
636 WebstorePrivateEnableAppLauncherFunction() {}
638 WebstorePrivateEnableAppLauncherFunction::
639 ~WebstorePrivateEnableAppLauncherFunction() {}
641 bool WebstorePrivateEnableAppLauncherFunction::RunSync() {
642 AppListService::Get(GetCurrentBrowser()->host_desktop_type())
643 ->EnableAppList(GetProfile(), AppListService::ENABLE_VIA_WEBSTORE_LINK);
647 bool WebstorePrivateGetBrowserLoginFunction::RunSync() {
648 GetBrowserLogin::Results::Info info;
649 info.login = GetProfile()->GetOriginalProfile()->GetPrefs()->GetString(
650 prefs::kGoogleServicesUsername);
651 results_ = GetBrowserLogin::Results::Create(info);
655 bool WebstorePrivateGetStoreLoginFunction::RunSync() {
656 results_ = GetStoreLogin::Results::Create(GetWebstoreLogin(GetProfile()));
660 bool WebstorePrivateSetStoreLoginFunction::RunSync() {
661 scoped_ptr<SetStoreLogin::Params> params(
662 SetStoreLogin::Params::Create(*args_));
663 EXTENSION_FUNCTION_VALIDATE(params);
664 SetWebstoreLogin(GetProfile(), params->login);
668 WebstorePrivateGetWebGLStatusFunction::WebstorePrivateGetWebGLStatusFunction() {
669 feature_checker_ = new GPUFeatureChecker(
670 gpu::GPU_FEATURE_TYPE_WEBGL,
671 base::Bind(&WebstorePrivateGetWebGLStatusFunction::OnFeatureCheck,
672 base::Unretained(this)));
675 WebstorePrivateGetWebGLStatusFunction::
676 ~WebstorePrivateGetWebGLStatusFunction() {}
678 void WebstorePrivateGetWebGLStatusFunction::CreateResult(bool webgl_allowed) {
679 results_ = GetWebGLStatus::Results::Create(GetWebGLStatus::Results::
680 ParseWebgl_status(webgl_allowed ? "webgl_allowed" : "webgl_blocked"));
683 bool WebstorePrivateGetWebGLStatusFunction::RunAsync() {
684 feature_checker_->CheckGPUFeatureAvailability();
688 void WebstorePrivateGetWebGLStatusFunction::
689 OnFeatureCheck(bool feature_allowed) {
690 CreateResult(feature_allowed);
694 bool WebstorePrivateGetIsLauncherEnabledFunction::RunSync() {
695 results_ = GetIsLauncherEnabled::Results::Create(IsAppLauncherEnabled());
699 bool WebstorePrivateIsInIncognitoModeFunction::RunSync() {
700 results_ = IsInIncognitoMode::Results::Create(
701 GetProfile() != GetProfile()->GetOriginalProfile());
705 WebstorePrivateSignInFunction::WebstorePrivateSignInFunction()
706 : signin_manager_(NULL) {}
707 WebstorePrivateSignInFunction::~WebstorePrivateSignInFunction() {}
709 bool WebstorePrivateSignInFunction::RunAsync() {
710 scoped_ptr<SignIn::Params> params = SignIn::Params::Create(*args_);
711 EXTENSION_FUNCTION_VALIDATE(params);
713 // This API must be called only in response to a user gesture.
714 if (!user_gesture()) {
715 error_ = "user_gesture_required";
720 // The |continue_url| is required, and must be hosted on the same origin as
722 GURL continue_url(params->continue_url);
723 content::WebContents* web_contents = GetAssociatedWebContents();
724 if (!continue_url.is_valid() ||
725 continue_url.GetOrigin() !=
726 web_contents->GetLastCommittedURL().GetOrigin()) {
727 error_ = "invalid_continue_url";
732 // If sign-in is disallowed, give up.
733 signin_manager_ = SigninManagerFactory::GetForProfile(GetProfile());
734 if (!signin_manager_ || !signin_manager_->IsSigninAllowed() ||
735 switches::IsEnableWebBasedSignin()) {
736 error_ = "signin_is_disallowed";
741 // If the user is already signed in, there's nothing else to do.
742 if (!signin_manager_->GetAuthenticatedUsername().empty()) {
747 // If an authentication is currently in progress, wait for it to complete.
748 if (signin_manager_->AuthInProgress()) {
749 SigninManagerFactory::GetInstance()->AddObserver(this);
751 SigninTrackerFactory::CreateForProfile(GetProfile(), this).Pass();
752 AddRef(); // Balanced in the sign-in observer methods below.
757 signin::GetPromoURLWithContinueURL(signin::SOURCE_WEBSTORE_INSTALL,
758 false /* auto_close */,
759 false /* is_constrained */,
761 web_contents->GetController().LoadURL(signin_url,
763 content::PAGE_TRANSITION_AUTO_TOPLEVEL,
770 void WebstorePrivateSignInFunction::SigninManagerShutdown(
771 SigninManagerBase* manager) {
772 if (manager == signin_manager_)
773 SigninFailed(GoogleServiceAuthError::AuthErrorNone());
776 void WebstorePrivateSignInFunction::SigninFailed(
777 const GoogleServiceAuthError& error) {
778 error_ = "signin_failed";
781 SigninManagerFactory::GetInstance()->RemoveObserver(this);
782 Release(); // Balanced in RunAsync().
785 void WebstorePrivateSignInFunction::SigninSuccess() {
786 // Nothing to do yet. Keep waiting until MergeSessionComplete() is called.
789 void WebstorePrivateSignInFunction::MergeSessionComplete(
790 const GoogleServiceAuthError& error) {
791 if (error.state() == GoogleServiceAuthError::NONE) {
794 error_ = "merge_session_failed";
798 SigninManagerFactory::GetInstance()->RemoveObserver(this);
799 Release(); // Balanced in RunAsync().
802 } // namespace extensions