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