• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PendingApprovals()91 PendingApprovals::PendingApprovals() {}
~PendingApprovals()92 PendingApprovals::~PendingApprovals() {}
93 
PushApproval(scoped_ptr<WebstoreInstaller::Approval> approval)94 void PendingApprovals::PushApproval(
95     scoped_ptr<WebstoreInstaller::Approval> approval) {
96   approvals_.push_back(approval.release());
97 }
98 
PopApproval(Profile * profile,const std::string & id)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 
PendingInstalls()132 PendingInstalls::PendingInstalls() {}
~PendingInstalls()133 PendingInstalls::~PendingInstalls() {}
134 
135 // Returns true and inserts the profile/id pair if it is not present. Otherwise
136 // returns false.
InsertInstall(Profile * profile,const std::string & id)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.
EraseInstall(Profile * profile,const std::string & id)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 
FindInstall(Profile * profile,const std::string & id)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.
GetWebstoreLogin(Profile * profile)187 std::string GetWebstoreLogin(Profile* profile) {
188   if (profile->GetPrefs()->HasPrefPath(kWebstoreLogin))
189     return profile->GetPrefs()->GetString(kWebstoreLogin);
190   return std::string();
191 }
192 
SetWebstoreLogin(Profile * profile,const std::string & login)193 void SetWebstoreLogin(Profile* profile, const std::string& login) {
194   profile->GetPrefs()->SetString(kWebstoreLogin, login);
195 }
196 
RecordWebstoreExtensionInstallResult(bool success)197 void RecordWebstoreExtensionInstallResult(bool success) {
198   UMA_HISTOGRAM_BOOLEAN("Webstore.ExtensionInstallResult", success);
199 }
200 
201 }  // namespace
202 
203 // static
SetWebstoreInstallerDelegateForTesting(WebstoreInstaller::Delegate * delegate)204 void WebstorePrivateApi::SetWebstoreInstallerDelegateForTesting(
205     WebstoreInstaller::Delegate* delegate) {
206   test_webstore_installer_delegate = delegate;
207 }
208 
209 // static
210 scoped_ptr<WebstoreInstaller::Approval>
PopApprovalForTesting(Profile * profile,const std::string & extension_id)211 WebstorePrivateApi::PopApprovalForTesting(
212     Profile* profile, const std::string& extension_id) {
213   return g_pending_approvals.Get().PopApproval(profile, extension_id);
214 }
215 
WebstorePrivateInstallBundleFunction()216 WebstorePrivateInstallBundleFunction::WebstorePrivateInstallBundleFunction() {}
~WebstorePrivateInstallBundleFunction()217 WebstorePrivateInstallBundleFunction::~WebstorePrivateInstallBundleFunction() {}
218 
RunAsync()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::
ReadBundleInfo(const InstallBundle::Params & params,BundleInstaller::ItemList * items)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 
OnBundleInstallApproved()250 void WebstorePrivateInstallBundleFunction::OnBundleInstallApproved() {
251   bundle_->CompleteInstall(
252       dispatcher()->delegate()->GetAssociatedWebContents(),
253       this);
254 }
255 
OnBundleInstallCanceled(bool user_initiated)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 
OnBundleInstallCompleted()268 void WebstorePrivateInstallBundleFunction::OnBundleInstallCompleted() {
269   SendResponse(true);
270 
271   Release();  // Balanced in RunAsync().
272 }
273 
274 WebstorePrivateBeginInstallWithManifest3Function::
WebstorePrivateBeginInstallWithManifest3Function()275     WebstorePrivateBeginInstallWithManifest3Function() {
276 }
277 
278 WebstorePrivateBeginInstallWithManifest3Function::
~WebstorePrivateBeginInstallWithManifest3Function()279     ~WebstorePrivateBeginInstallWithManifest3Function() {
280 }
281 
RunAsync()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::
ResultCodeToString(ResultCode code)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 
SetResultCode(ResultCode code)372 void WebstorePrivateBeginInstallWithManifest3Function::SetResultCode(
373     ResultCode code) {
374   results_ = BeginInstallWithManifest3::Results::Create(
375       ResultCodeToString(code));
376 }
377 
OnWebstoreParseSuccess(const std::string & id,const SkBitmap & icon,base::DictionaryValue * parsed_manifest)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 
OnWebstoreParseFailure(const std::string & id,WebstoreInstallHelper::Delegate::InstallHelperResultCode result_code,const std::string & error_message)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 
SigninFailed(const GoogleServiceAuthError & error)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 
SigninSuccess()461 void WebstorePrivateBeginInstallWithManifest3Function::SigninSuccess() {
462   signin_tracker_.reset();
463 
464   SigninCompletedOrNotNeeded();
465 }
466 
MergeSessionComplete(const GoogleServiceAuthError & error)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::
SigninCompletedOrNotNeeded()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 
InstallUIProceed()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 
InstallUIAbort(bool user_initiated)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::
WebstorePrivateCompleteInstallFunction()544     WebstorePrivateCompleteInstallFunction() {}
545 
546 WebstorePrivateCompleteInstallFunction::
~WebstorePrivateCompleteInstallFunction()547     ~WebstorePrivateCompleteInstallFunction() {}
548 
RunAsync()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 
OnExtensionInstallSuccess(const std::string & id)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 
OnExtensionInstallFailure(const std::string & id,const std::string & error,WebstoreInstaller::FailureReason reason)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 
OnInstallSuccess(const std::string & id)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::
WebstorePrivateEnableAppLauncherFunction()654     WebstorePrivateEnableAppLauncherFunction() {}
655 
656 WebstorePrivateEnableAppLauncherFunction::
~WebstorePrivateEnableAppLauncherFunction()657     ~WebstorePrivateEnableAppLauncherFunction() {}
658 
RunSync()659 bool WebstorePrivateEnableAppLauncherFunction::RunSync() {
660   AppListService::Get(GetCurrentBrowser()->host_desktop_type())
661       ->EnableAppList(GetProfile(), AppListService::ENABLE_VIA_WEBSTORE_LINK);
662   return true;
663 }
664 
RunSync()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 
RunSync()673 bool WebstorePrivateGetStoreLoginFunction::RunSync() {
674   results_ = GetStoreLogin::Results::Create(GetWebstoreLogin(GetProfile()));
675   return true;
676 }
677 
RunSync()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 
WebstorePrivateGetWebGLStatusFunction()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::
~WebstorePrivateGetWebGLStatusFunction()694     ~WebstorePrivateGetWebGLStatusFunction() {}
695 
CreateResult(bool webgl_allowed)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 
RunAsync()701 bool WebstorePrivateGetWebGLStatusFunction::RunAsync() {
702   feature_checker_->CheckGPUFeatureAvailability();
703   return true;
704 }
705 
706 void WebstorePrivateGetWebGLStatusFunction::
OnFeatureCheck(bool feature_allowed)707     OnFeatureCheck(bool feature_allowed) {
708   CreateResult(feature_allowed);
709   SendResponse(true);
710 }
711 
RunSync()712 bool WebstorePrivateGetIsLauncherEnabledFunction::RunSync() {
713   results_ = GetIsLauncherEnabled::Results::Create(IsAppLauncherEnabled());
714   return true;
715 }
716 
RunSync()717 bool WebstorePrivateIsInIncognitoModeFunction::RunSync() {
718   results_ = IsInIncognitoMode::Results::Create(
719       GetProfile() != GetProfile()->GetOriginalProfile());
720   return true;
721 }
722 
WebstorePrivateSignInFunction()723 WebstorePrivateSignInFunction::WebstorePrivateSignInFunction()
724     : signin_manager_(NULL) {}
~WebstorePrivateSignInFunction()725 WebstorePrivateSignInFunction::~WebstorePrivateSignInFunction() {}
726 
RunAsync()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 
SigninManagerShutdown(SigninManagerBase * manager)788 void WebstorePrivateSignInFunction::SigninManagerShutdown(
789     SigninManagerBase* manager) {
790   if (manager == signin_manager_)
791     SigninFailed(GoogleServiceAuthError::AuthErrorNone());
792 }
793 
SigninFailed(const GoogleServiceAuthError & error)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 
SigninSuccess()803 void WebstorePrivateSignInFunction::SigninSuccess() {
804   // Nothing to do yet. Keep waiting until MergeSessionComplete() is called.
805 }
806 
MergeSessionComplete(const GoogleServiceAuthError & error)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