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/lazy_instance.h"
9 #include "base/memory/scoped_vector.h"
10 #include "base/metrics/histogram.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/values.h"
15 #include "base/version.h"
16 #include "chrome/browser/apps/ephemeral_app_launcher.h"
17 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h"
18 #include "chrome/browser/extensions/crx_installer.h"
19 #include "chrome/browser/extensions/extension_install_ui_util.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/extensions/install_tracker.h"
22 #include "chrome/browser/gpu/gpu_feature_checker.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/signin/signin_manager_factory.h"
25 #include "chrome/browser/ui/app_list/app_list_service.h"
26 #include "chrome/browser/ui/app_list/app_list_util.h"
27 #include "chrome/common/extensions/extension_constants.h"
28 #include "chrome/common/pref_names.h"
29 #include "components/crx_file/id_util.h"
30 #include "components/signin/core/browser/signin_manager.h"
31 #include "content/public/browser/web_contents.h"
32 #include "extensions/browser/extension_registry.h"
33 #include "extensions/browser/extension_system.h"
34 #include "extensions/browser/extension_util.h"
35 #include "extensions/common/extension.h"
36 #include "net/base/load_flags.h"
37 #include "net/url_request/url_request.h"
40 namespace extensions
{
42 namespace BeginInstallWithManifest3
=
43 api::webstore_private::BeginInstallWithManifest3
;
44 namespace CompleteInstall
= api::webstore_private::CompleteInstall
;
45 namespace GetBrowserLogin
= api::webstore_private::GetBrowserLogin
;
46 namespace GetEphemeralAppsEnabled
=
47 api::webstore_private::GetEphemeralAppsEnabled
;
48 namespace GetIsLauncherEnabled
= api::webstore_private::GetIsLauncherEnabled
;
49 namespace GetStoreLogin
= api::webstore_private::GetStoreLogin
;
50 namespace GetWebGLStatus
= api::webstore_private::GetWebGLStatus
;
51 namespace InstallBundle
= api::webstore_private::InstallBundle
;
52 namespace IsInIncognitoMode
= api::webstore_private::IsInIncognitoMode
;
53 namespace LaunchEphemeralApp
= api::webstore_private::LaunchEphemeralApp
;
54 namespace SetStoreLogin
= api::webstore_private::SetStoreLogin
;
55 namespace ShowPermissionPromptForDelegatedInstall
=
56 api::webstore_private::ShowPermissionPromptForDelegatedInstall
;
57 namespace ShowPermissionPromptForDelegatedBundleInstall
=
58 api::webstore_private::ShowPermissionPromptForDelegatedBundleInstall
;
62 // Holds the Approvals between the time we prompt and start the installs.
63 class PendingApprovals
{
68 void PushApproval(scoped_ptr
<WebstoreInstaller::Approval
> approval
);
69 scoped_ptr
<WebstoreInstaller::Approval
> PopApproval(
70 Profile
* profile
, const std::string
& id
);
72 typedef ScopedVector
<WebstoreInstaller::Approval
> ApprovalList
;
74 ApprovalList approvals_
;
76 DISALLOW_COPY_AND_ASSIGN(PendingApprovals
);
79 PendingApprovals::PendingApprovals() {}
80 PendingApprovals::~PendingApprovals() {}
82 void PendingApprovals::PushApproval(
83 scoped_ptr
<WebstoreInstaller::Approval
> approval
) {
84 approvals_
.push_back(approval
.release());
87 scoped_ptr
<WebstoreInstaller::Approval
> PendingApprovals::PopApproval(
88 Profile
* profile
, const std::string
& id
) {
89 for (size_t i
= 0; i
< approvals_
.size(); ++i
) {
90 WebstoreInstaller::Approval
* approval
= approvals_
[i
];
91 if (approval
->extension_id
== id
&&
92 profile
->IsSameProfile(approval
->profile
)) {
93 approvals_
.weak_erase(approvals_
.begin() + i
);
94 return scoped_ptr
<WebstoreInstaller::Approval
>(approval
);
97 return scoped_ptr
<WebstoreInstaller::Approval
>();
100 chrome::HostDesktopType
GetHostDesktopTypeForWebContents(
101 content::WebContents
* contents
) {
102 return chrome::GetHostDesktopTypeForNativeWindow(
103 contents
->GetTopLevelNativeWindow());
106 api::webstore_private::Result
WebstoreInstallResultToApiResult(
107 webstore_install::Result result
) {
109 case webstore_install::SUCCESS
:
110 return api::webstore_private::RESULT_SUCCESS
;
111 case webstore_install::OTHER_ERROR
:
112 return api::webstore_private::RESULT_UNKNOWN_ERROR
;
113 case webstore_install::INVALID_ID
:
114 return api::webstore_private::RESULT_INVALID_ID
;
115 case webstore_install::NOT_PERMITTED
:
116 case webstore_install::WEBSTORE_REQUEST_ERROR
:
117 case webstore_install::INVALID_WEBSTORE_RESPONSE
:
118 return api::webstore_private::RESULT_INSTALL_ERROR
;
119 case webstore_install::INVALID_MANIFEST
:
120 return api::webstore_private::RESULT_MANIFEST_ERROR
;
121 case webstore_install::ICON_ERROR
:
122 return api::webstore_private::RESULT_ICON_ERROR
;
123 case webstore_install::ABORTED
:
124 case webstore_install::USER_CANCELLED
:
125 return api::webstore_private::RESULT_USER_CANCELLED
;
126 case webstore_install::BLACKLISTED
:
127 return api::webstore_private::RESULT_BLACKLISTED
;
128 case webstore_install::MISSING_DEPENDENCIES
:
129 case webstore_install::REQUIREMENT_VIOLATIONS
:
130 return api::webstore_private::RESULT_MISSING_DEPENDENCIES
;
131 case webstore_install::BLOCKED_BY_POLICY
:
132 return api::webstore_private::RESULT_BLOCKED_BY_POLICY
;
133 case webstore_install::LAUNCH_FEATURE_DISABLED
:
134 return api::webstore_private::RESULT_FEATURE_DISABLED
;
135 case webstore_install::LAUNCH_UNSUPPORTED_EXTENSION_TYPE
:
136 return api::webstore_private::RESULT_UNSUPPORTED_EXTENSION_TYPE
;
137 case webstore_install::INSTALL_IN_PROGRESS
:
138 return api::webstore_private::RESULT_INSTALL_IN_PROGRESS
;
139 case webstore_install::LAUNCH_IN_PROGRESS
:
140 return api::webstore_private::RESULT_LAUNCH_IN_PROGRESS
;
143 return api::webstore_private::RESULT_NONE
;
146 api::webstore_private::Result
WebstoreInstallHelperResultToApiResult(
147 WebstoreInstallHelper::Delegate::InstallHelperResultCode result
) {
149 case WebstoreInstallHelper::Delegate::UNKNOWN_ERROR
:
150 return api::webstore_private::RESULT_UNKNOWN_ERROR
;
151 case WebstoreInstallHelper::Delegate::ICON_ERROR
:
152 return api::webstore_private::RESULT_ICON_ERROR
;
153 case WebstoreInstallHelper::Delegate::MANIFEST_ERROR
:
154 return api::webstore_private::RESULT_MANIFEST_ERROR
;
157 return api::webstore_private::RESULT_NONE
;
160 static base::LazyInstance
<PendingApprovals
> g_pending_approvals
=
161 LAZY_INSTANCE_INITIALIZER
;
163 // A preference set by the web store to indicate login information for
165 const char kWebstoreLogin
[] = "extensions.webstore_login";
167 // Error messages that can be returned by the API.
168 const char kAlreadyInstalledError
[] = "This item is already installed";
169 const char kCannotSpecifyIconDataAndUrlError
[] =
170 "You cannot specify both icon data and an icon url";
171 const char kInvalidBundleError
[] = "Invalid bundle";
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
= nullptr;
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 template<typename Params
>
216 WebstorePrivateFunctionWithPermissionPrompt
<Params
>::
217 WebstorePrivateFunctionWithPermissionPrompt() {
220 template<typename Params
>
221 WebstorePrivateFunctionWithPermissionPrompt
<Params
>::
222 ~WebstorePrivateFunctionWithPermissionPrompt() {
225 template<typename Params
>
226 ExtensionFunction::ResponseValue
227 WebstorePrivateFunctionWithPermissionPrompt
<Params
>::RunExtraForResponse() {
228 return ExtensionFunction::ResponseValue();
231 template<typename Params
>
232 ExtensionFunction::ResponseValue
233 WebstorePrivateFunctionWithPermissionPrompt
<Params
>::BuildResponse(
234 api::webstore_private::Result result
, const std::string
& error
) {
235 if (result
!= api::webstore_private::RESULT_SUCCESS
)
236 return ErrorWithArguments(CreateResults(result
), error
);
238 // The web store expects an empty string on success, so don't use
239 // RESULT_SUCCESS here.
241 CreateResults(api::webstore_private::RESULT_EMPTY_STRING
));
244 template<typename Params
>
245 scoped_ptr
<base::DictionaryValue
>
246 WebstorePrivateFunctionWithPermissionPrompt
<Params
>::PassParsedManifest() {
247 return parsed_manifest_
.Pass();
250 template<typename Params
>
251 ExtensionFunction::ResponseAction
252 WebstorePrivateFunctionWithPermissionPrompt
<Params
>::Run() {
253 params_
= Params::Create(*args_
);
254 EXTENSION_FUNCTION_VALIDATE(params_
);
256 if (!crx_file::id_util::IdIsValid(params_
->details
.id
)) {
257 return RespondNow(BuildResponse(api::webstore_private::RESULT_INVALID_ID
,
261 if (params_
->details
.icon_data
&& params_
->details
.icon_url
) {
262 return RespondNow(BuildResponse(api::webstore_private::RESULT_ICON_ERROR
,
263 kCannotSpecifyIconDataAndUrlError
));
267 if (params_
->details
.icon_url
) {
268 icon_url
= source_url().Resolve(*params_
->details
.icon_url
);
269 if (!icon_url
.is_valid()) {
270 return RespondNow(BuildResponse(
271 api::webstore_private::RESULT_INVALID_ICON_URL
,
272 kInvalidIconUrlError
));
276 ExtensionFunction::ResponseValue response
= RunExtraForResponse();
278 return RespondNow(response
.Pass());
280 net::URLRequestContextGetter
* context_getter
= nullptr;
281 if (!icon_url
.is_empty())
282 context_getter
= browser_context()->GetRequestContext();
284 scoped_refptr
<WebstoreInstallHelper
> helper
= new WebstoreInstallHelper(
285 this, params_
->details
.id
, params_
->details
.manifest
, icon_url
,
288 // The helper will call us back via OnWebstoreParseSuccess or
289 // OnWebstoreParseFailure.
292 // Matched with a Release in OnWebstoreParseSuccess/OnWebstoreParseFailure.
295 // The response is sent asynchronously in OnWebstoreParseSuccess/
296 // OnWebstoreParseFailure.
297 return RespondLater();
300 template<typename Params
>
302 WebstorePrivateFunctionWithPermissionPrompt
<Params
>::OnWebstoreParseSuccess(
303 const std::string
& id
,
304 const SkBitmap
& icon
,
305 base::DictionaryValue
* parsed_manifest
) {
306 CHECK_EQ(params_
->details
.id
, id
);
307 CHECK(parsed_manifest
);
309 parsed_manifest_
.reset(parsed_manifest
);
311 std::string localized_name
= params_
->details
.localized_name
?
312 *params_
->details
.localized_name
: std::string();
315 dummy_extension_
= ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
316 parsed_manifest_
.get(),
317 Extension::FROM_WEBSTORE
,
323 if (!dummy_extension_
.get()) {
324 OnWebstoreParseFailure(params_
->details
.id
,
325 WebstoreInstallHelper::Delegate::MANIFEST_ERROR
,
326 kInvalidManifestError
);
330 content::WebContents
* web_contents
= GetAssociatedWebContents();
332 // The browser window has gone away.
333 Respond(BuildResponse(api::webstore_private::RESULT_USER_CANCELLED
,
334 kUserCancelledError
));
335 // Matches the AddRef in Run().
339 install_prompt_
.reset(new ExtensionInstallPrompt(web_contents
));
340 ShowPrompt(install_prompt_
.get());
341 // Control flow finishes up in InstallUIProceed or InstallUIAbort.
344 template<typename Params
>
346 WebstorePrivateFunctionWithPermissionPrompt
<Params
>::OnWebstoreParseFailure(
347 const std::string
& id
,
348 WebstoreInstallHelper::Delegate::InstallHelperResultCode result
,
349 const std::string
& error_message
) {
350 CHECK_EQ(params_
->details
.id
, id
);
352 Respond(BuildResponse(WebstoreInstallHelperResultToApiResult(result
),
355 // Matches the AddRef in Run().
359 template<typename Params
>
360 void WebstorePrivateFunctionWithPermissionPrompt
<Params
>::InstallUIProceed() {
361 InstallUIProceedHook();
363 Respond(BuildResponse(api::webstore_private::RESULT_SUCCESS
, std::string()));
365 // Matches the AddRef in Run().
369 template<typename Params
>
370 void WebstorePrivateFunctionWithPermissionPrompt
<Params
>::InstallUIAbort(
371 bool user_initiated
) {
372 InstallUIAbortHook(user_initiated
);
374 Respond(BuildResponse(api::webstore_private::RESULT_USER_CANCELLED
,
375 kUserCancelledError
));
377 // Matches the AddRef in Run().
381 WebstorePrivateBeginInstallWithManifest3Function::
382 WebstorePrivateBeginInstallWithManifest3Function() : chrome_details_(this) {
385 WebstorePrivateBeginInstallWithManifest3Function::
386 ~WebstorePrivateBeginInstallWithManifest3Function() {
389 ExtensionFunction::ResponseValue
390 WebstorePrivateBeginInstallWithManifest3Function::RunExtraForResponse() {
391 InstallTracker
* tracker
= InstallTracker::Get(browser_context());
393 if (util::IsExtensionInstalledPermanently(details().id
, browser_context()) ||
394 tracker
->GetActiveInstall(details().id
)) {
395 return BuildResponse(api::webstore_private::RESULT_ALREADY_INSTALLED
,
396 kAlreadyInstalledError
);
398 ActiveInstallData
install_data(details().id
);
399 scoped_active_install_
.reset(new ScopedActiveInstall(tracker
, install_data
));
400 return ExtensionFunction::ResponseValue();
403 void WebstorePrivateBeginInstallWithManifest3Function::InstallUIProceedHook() {
404 // This gets cleared in CrxInstaller::ConfirmInstall(). TODO(asargent) - in
405 // the future we may also want to add time-based expiration, where a whitelist
406 // entry is only valid for some number of minutes.
407 scoped_ptr
<WebstoreInstaller::Approval
> approval(
408 WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
409 chrome_details_
.GetProfile(),
411 PassParsedManifest(),
413 approval
->use_app_installed_bubble
= details().app_install_bubble
;
414 approval
->enable_launcher
= details().enable_launcher
;
415 // If we are enabling the launcher, we should not show the app list in order
416 // to train the user to open it themselves at least once.
417 approval
->skip_post_install_ui
= details().enable_launcher
;
418 approval
->dummy_extension
= dummy_extension();
419 approval
->installing_icon
= gfx::ImageSkia::CreateFrom1xBitmap(icon());
420 if (details().authuser
)
421 approval
->authuser
= *details().authuser
;
422 g_pending_approvals
.Get().PushApproval(approval
.Pass());
424 DCHECK(scoped_active_install_
.get());
425 scoped_active_install_
->CancelDeregister();
427 // The Permissions_Install histogram is recorded from the ExtensionService
428 // for all extension installs, so we only need to record the web store
429 // specific histogram here.
430 ExtensionService::RecordPermissionMessagesHistogram(
431 dummy_extension().get(), "WebStoreInstall");
434 void WebstorePrivateBeginInstallWithManifest3Function::InstallUIAbortHook(
435 bool user_initiated
) {
436 // The web store install histograms are a subset of the install histograms.
437 // We need to record both histograms here since CrxInstaller::InstallUIAbort
438 // is never called for web store install cancellations.
439 std::string histogram_name
= user_initiated
? "WebStoreInstallCancel"
440 : "WebStoreInstallAbort";
441 ExtensionService::RecordPermissionMessagesHistogram(dummy_extension().get(),
442 histogram_name
.c_str());
444 histogram_name
= user_initiated
? "InstallCancel" : "InstallAbort";
445 ExtensionService::RecordPermissionMessagesHistogram(dummy_extension().get(),
446 histogram_name
.c_str());
449 void WebstorePrivateBeginInstallWithManifest3Function::ShowPrompt(
450 ExtensionInstallPrompt
* install_prompt
) {
451 install_prompt
->ConfirmWebstoreInstall(
452 this, dummy_extension().get(), &icon(),
453 ExtensionInstallPrompt::GetDefaultShowDialogCallback());
456 scoped_ptr
<base::ListValue
>
457 WebstorePrivateBeginInstallWithManifest3Function::CreateResults(
458 api::webstore_private::Result result
) const {
459 return BeginInstallWithManifest3::Results::Create(result
);
462 WebstorePrivateCompleteInstallFunction::
463 WebstorePrivateCompleteInstallFunction() : chrome_details_(this) {}
465 WebstorePrivateCompleteInstallFunction::
466 ~WebstorePrivateCompleteInstallFunction() {}
468 ExtensionFunction::ResponseAction
469 WebstorePrivateCompleteInstallFunction::Run() {
470 scoped_ptr
<CompleteInstall::Params
> params(
471 CompleteInstall::Params::Create(*args_
));
472 EXTENSION_FUNCTION_VALIDATE(params
);
473 if (!crx_file::id_util::IdIsValid(params
->expected_id
))
474 return RespondNow(Error(kInvalidIdError
));
477 g_pending_approvals
.Get().PopApproval(chrome_details_
.GetProfile(),
478 params
->expected_id
).Pass();
480 return RespondNow(Error(kNoPreviousBeginInstallWithManifestError
,
481 params
->expected_id
));
484 scoped_active_install_
.reset(new ScopedActiveInstall(
485 InstallTracker::Get(browser_context()), params
->expected_id
));
487 AppListService
* app_list_service
= AppListService::Get(
488 GetHostDesktopTypeForWebContents(GetAssociatedWebContents()));
490 if (approval_
->enable_launcher
) {
491 app_list_service
->EnableAppList(chrome_details_
.GetProfile(),
492 AppListService::ENABLE_FOR_APP_INSTALL
);
495 if (IsAppLauncherEnabled() && approval_
->manifest
->is_app()) {
496 // Show the app list to show download is progressing. Don't show the app
497 // list on first app install so users can be trained to open it themselves.
498 app_list_service
->ShowForAppInstall(
499 chrome_details_
.GetProfile(),
501 approval_
->enable_launcher
);
504 // If the target extension has already been installed ephemerally and is
505 // up to date, it can be promoted to a regular installed extension and
506 // downloading from the Web Store is not necessary.
507 const Extension
* extension
= ExtensionRegistry::Get(browser_context())->
508 GetExtensionById(params
->expected_id
, ExtensionRegistry::EVERYTHING
);
509 if (extension
&& approval_
->dummy_extension
.get() &&
510 util::IsEphemeralApp(extension
->id(), browser_context()) &&
511 extension
->version()->CompareTo(*approval_
->dummy_extension
->version()) >=
513 install_ui::ShowPostInstallUIForApproval(
514 browser_context(), *approval_
, extension
);
516 ExtensionService
* extension_service
=
517 ExtensionSystem::Get(browser_context())->extension_service();
518 extension_service
->PromoteEphemeralApp(extension
, false);
519 OnInstallSuccess(extension
->id());
520 VLOG(1) << "Install success, sending response";
521 return RespondNow(NoArguments());
524 // Balanced in OnExtensionInstallSuccess() or OnExtensionInstallFailure().
527 // The extension will install through the normal extension install flow, but
528 // the whitelist entry will bypass the normal permissions install dialog.
529 scoped_refptr
<WebstoreInstaller
> installer
= new WebstoreInstaller(
530 chrome_details_
.GetProfile(),
532 chrome_details_
.GetAssociatedWebContents(),
535 WebstoreInstaller::INSTALL_SOURCE_OTHER
);
538 return RespondLater();
541 void WebstorePrivateCompleteInstallFunction::OnExtensionInstallSuccess(
542 const std::string
& id
) {
543 OnInstallSuccess(id
);
544 VLOG(1) << "Install success, sending response";
545 Respond(NoArguments());
547 RecordWebstoreExtensionInstallResult(true);
549 // Matches the AddRef in Run().
553 void WebstorePrivateCompleteInstallFunction::OnExtensionInstallFailure(
554 const std::string
& id
,
555 const std::string
& error
,
556 WebstoreInstaller::FailureReason reason
) {
557 if (test_webstore_installer_delegate
) {
558 test_webstore_installer_delegate
->OnExtensionInstallFailure(
562 VLOG(1) << "Install failed, sending response";
563 Respond(Error(error
));
565 RecordWebstoreExtensionInstallResult(false);
567 // Matches the AddRef in Run().
571 void WebstorePrivateCompleteInstallFunction::OnInstallSuccess(
572 const std::string
& id
) {
573 if (test_webstore_installer_delegate
)
574 test_webstore_installer_delegate
->OnExtensionInstallSuccess(id
);
577 WebstorePrivateShowPermissionPromptForDelegatedInstallFunction::
578 WebstorePrivateShowPermissionPromptForDelegatedInstallFunction() {
581 WebstorePrivateShowPermissionPromptForDelegatedInstallFunction::
582 ~WebstorePrivateShowPermissionPromptForDelegatedInstallFunction() {
585 void WebstorePrivateShowPermissionPromptForDelegatedInstallFunction::ShowPrompt(
586 ExtensionInstallPrompt
* install_prompt
) {
587 install_prompt
->ConfirmPermissionsForDelegatedInstall(
588 this, dummy_extension().get(), details().delegated_user
, &icon());
591 scoped_ptr
<base::ListValue
>
592 WebstorePrivateShowPermissionPromptForDelegatedInstallFunction::CreateResults(
593 api::webstore_private::Result result
) const {
594 return ShowPermissionPromptForDelegatedInstall::Results::Create(result
);
597 template<typename Params
>
598 WebstorePrivateFunctionWithBundle
<Params
>::WebstorePrivateFunctionWithBundle()
599 : chrome_details_(this) {
602 template<typename Params
>
603 WebstorePrivateFunctionWithBundle
<Params
>::
604 ~WebstorePrivateFunctionWithBundle() {
607 template<typename Params
>
608 ExtensionFunction::ResponseAction
609 WebstorePrivateFunctionWithBundle
<Params
>::Run() {
610 params_
= Params::Create(*args_
);
611 EXTENSION_FUNCTION_VALIDATE(params_
);
613 if (params_
->contents
.empty())
614 return RespondNow(Error(kInvalidBundleError
));
616 if (params_
->details
.icon_url
) {
617 GURL icon_url
= source_url().Resolve(*params_
->details
.icon_url
);
618 if (!icon_url
.is_valid())
619 return RespondNow(Error(kInvalidIconUrlError
));
621 // The bitmap fetcher will call us back via OnFetchComplete.
622 icon_fetcher_
.reset(new chrome::BitmapFetcher(icon_url
, this));
624 browser_context()->GetRequestContext(), std::string(),
625 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE
,
626 net::LOAD_DO_NOT_SAVE_COOKIES
| net::LOAD_DO_NOT_SEND_COOKIES
);
627 icon_fetcher_
->Start();
629 base::ThreadTaskRunnerHandle::Get()->PostTask(
631 base::Bind(&WebstorePrivateFunctionWithBundle::OnFetchComplete
,
632 this, GURL(), nullptr));
635 AddRef(); // Balanced in OnFetchComplete.
637 // The response is sent asynchronously in OnFetchComplete, OnInstallApproval,
638 // or OnInstallComplete.
639 return RespondLater();
642 template<typename Params
>
643 void WebstorePrivateFunctionWithBundle
<Params
>::OnFetchComplete(
644 const GURL
& url
, const SkBitmap
* bitmap
) {
645 BundleInstaller::ItemList items
;
646 for (const auto& entry
: params_
->contents
) {
647 if (ShouldSkipItem(entry
->id
))
649 BundleInstaller::Item item
;
651 item
.manifest
= entry
->manifest
;
652 item
.localized_name
= entry
->localized_name
;
654 item
.icon_url
= source_url().Resolve(*entry
->icon_url
);
655 items
.push_back(item
);
658 Respond(Error(kAlreadyInstalledError
));
659 Release(); // Matches the AddRef in Run.
663 bundle_
.reset(new BundleInstaller(chrome_details_
.GetCurrentBrowser(),
664 params_
->details
.localized_name
,
665 bitmap
? *bitmap
: SkBitmap(),
666 auth_user_
, delegated_user_
, items
));
668 bundle_
->PromptForApproval(
669 base::Bind(&WebstorePrivateFunctionWithBundle::OnInstallApproval
, this));
671 Release(); // Matches the AddRef in Run.
674 template<typename Params
>
675 void WebstorePrivateFunctionWithBundle
<Params
>::OnInstallApproval(
676 BundleInstaller::ApprovalState state
) {
677 if (state
!= BundleInstaller::APPROVED
) {
678 Respond(Error(state
== BundleInstaller::USER_CANCELED
679 ? kUserCancelledError
680 : kInvalidBundleError
));
684 OnInstallApprovalHook();
687 WebstorePrivateInstallBundleFunction::WebstorePrivateInstallBundleFunction() {
690 WebstorePrivateInstallBundleFunction::~WebstorePrivateInstallBundleFunction() {
693 void WebstorePrivateInstallBundleFunction::ProcessParams() {
694 if (details().authuser
)
695 set_auth_user(*details().authuser
);
698 bool WebstorePrivateInstallBundleFunction::ShouldSkipItem(
699 const std::string
& id
) const {
700 // Skip already-installed items.
701 return util::IsExtensionInstalledPermanently(id
, browser_context()) ||
702 InstallTracker::Get(browser_context())->GetActiveInstall(id
);
705 void WebstorePrivateInstallBundleFunction::OnInstallApprovalHook() {
706 // The bundle installer will call us back via OnInstallComplete.
707 bundle()->CompleteInstall(
708 GetSenderWebContents(),
709 base::Bind(&WebstorePrivateInstallBundleFunction::OnInstallComplete
,
713 void WebstorePrivateInstallBundleFunction::OnInstallComplete() {
714 Respond(NoArguments());
717 WebstorePrivateShowPermissionPromptForDelegatedBundleInstallFunction::
718 WebstorePrivateShowPermissionPromptForDelegatedBundleInstallFunction() {
721 WebstorePrivateShowPermissionPromptForDelegatedBundleInstallFunction::
722 ~WebstorePrivateShowPermissionPromptForDelegatedBundleInstallFunction() {
725 void WebstorePrivateShowPermissionPromptForDelegatedBundleInstallFunction::
727 set_delegated_user(details().delegated_user
);
730 bool WebstorePrivateShowPermissionPromptForDelegatedBundleInstallFunction::
731 ShouldSkipItem(const std::string
& id
) const {
732 // For delegated installs, don't skip any items (we don't know if any are
733 // installed already).
737 void WebstorePrivateShowPermissionPromptForDelegatedBundleInstallFunction::
738 OnInstallApprovalHook() {
739 Respond(NoArguments());
742 WebstorePrivateEnableAppLauncherFunction::
743 WebstorePrivateEnableAppLauncherFunction() : chrome_details_(this) {}
745 WebstorePrivateEnableAppLauncherFunction::
746 ~WebstorePrivateEnableAppLauncherFunction() {}
748 ExtensionFunction::ResponseAction
749 WebstorePrivateEnableAppLauncherFunction::Run() {
750 AppListService
* app_list_service
= AppListService::Get(
751 GetHostDesktopTypeForWebContents(
752 chrome_details_
.GetAssociatedWebContents()));
753 app_list_service
->EnableAppList(chrome_details_
.GetProfile(),
754 AppListService::ENABLE_VIA_WEBSTORE_LINK
);
755 return RespondNow(NoArguments());
758 WebstorePrivateGetBrowserLoginFunction::
759 WebstorePrivateGetBrowserLoginFunction() : chrome_details_(this) {}
761 WebstorePrivateGetBrowserLoginFunction::
762 ~WebstorePrivateGetBrowserLoginFunction() {}
764 ExtensionFunction::ResponseAction
765 WebstorePrivateGetBrowserLoginFunction::Run() {
766 GetBrowserLogin::Results::Info info
;
767 info
.login
= SigninManagerFactory::GetForProfile(
768 chrome_details_
.GetProfile()->GetOriginalProfile())
769 ->GetAuthenticatedUsername();
770 return RespondNow(ArgumentList(GetBrowserLogin::Results::Create(info
)));
773 WebstorePrivateGetStoreLoginFunction::
774 WebstorePrivateGetStoreLoginFunction() : chrome_details_(this) {}
776 WebstorePrivateGetStoreLoginFunction::
777 ~WebstorePrivateGetStoreLoginFunction() {}
779 ExtensionFunction::ResponseAction
WebstorePrivateGetStoreLoginFunction::Run() {
780 return RespondNow(ArgumentList(GetStoreLogin::Results::Create(
781 GetWebstoreLogin(chrome_details_
.GetProfile()))));
784 WebstorePrivateSetStoreLoginFunction::
785 WebstorePrivateSetStoreLoginFunction() : chrome_details_(this) {}
787 WebstorePrivateSetStoreLoginFunction::
788 ~WebstorePrivateSetStoreLoginFunction() {}
790 ExtensionFunction::ResponseAction
WebstorePrivateSetStoreLoginFunction::Run() {
791 scoped_ptr
<SetStoreLogin::Params
> params(
792 SetStoreLogin::Params::Create(*args_
));
793 EXTENSION_FUNCTION_VALIDATE(params
);
794 SetWebstoreLogin(chrome_details_
.GetProfile(), params
->login
);
795 return RespondNow(NoArguments());
798 WebstorePrivateGetWebGLStatusFunction::WebstorePrivateGetWebGLStatusFunction()
799 : feature_checker_(new GPUFeatureChecker(
800 gpu::GPU_FEATURE_TYPE_WEBGL
,
801 base::Bind(&WebstorePrivateGetWebGLStatusFunction::OnFeatureCheck
,
802 base::Unretained(this)))) {
805 WebstorePrivateGetWebGLStatusFunction::
806 ~WebstorePrivateGetWebGLStatusFunction() {}
808 ExtensionFunction::ResponseAction
WebstorePrivateGetWebGLStatusFunction::Run() {
809 feature_checker_
->CheckGPUFeatureAvailability();
810 return RespondLater();
813 void WebstorePrivateGetWebGLStatusFunction::OnFeatureCheck(
814 bool feature_allowed
) {
815 Respond(ArgumentList(
816 GetWebGLStatus::Results::Create(api::webstore_private::ParseWebGlStatus(
817 feature_allowed
? "webgl_allowed" : "webgl_blocked"))));
820 WebstorePrivateGetIsLauncherEnabledFunction::
821 WebstorePrivateGetIsLauncherEnabledFunction() {}
823 WebstorePrivateGetIsLauncherEnabledFunction::
824 ~WebstorePrivateGetIsLauncherEnabledFunction() {}
826 ExtensionFunction::ResponseAction
827 WebstorePrivateGetIsLauncherEnabledFunction::Run() {
828 return RespondNow(ArgumentList(
829 GetIsLauncherEnabled::Results::Create(IsAppLauncherEnabled())));
832 WebstorePrivateIsInIncognitoModeFunction::
833 WebstorePrivateIsInIncognitoModeFunction() : chrome_details_(this) {}
835 WebstorePrivateIsInIncognitoModeFunction::
836 ~WebstorePrivateIsInIncognitoModeFunction() {}
838 ExtensionFunction::ResponseAction
839 WebstorePrivateIsInIncognitoModeFunction::Run() {
840 Profile
* profile
= chrome_details_
.GetProfile();
841 return RespondNow(ArgumentList(IsInIncognitoMode::Results::Create(
842 profile
!= profile
->GetOriginalProfile())));
845 WebstorePrivateLaunchEphemeralAppFunction::
846 WebstorePrivateLaunchEphemeralAppFunction() : chrome_details_(this) {}
848 WebstorePrivateLaunchEphemeralAppFunction::
849 ~WebstorePrivateLaunchEphemeralAppFunction() {}
851 ExtensionFunction::ResponseAction
852 WebstorePrivateLaunchEphemeralAppFunction::Run() {
853 // Check whether the browser window still exists.
854 content::WebContents
* web_contents
=
855 chrome_details_
.GetAssociatedWebContents();
857 return RespondNow(Error("aborted"));
859 if (!user_gesture()) {
860 return RespondNow(BuildResponse(
861 api::webstore_private::RESULT_USER_GESTURE_REQUIRED
,
862 "User gesture is required"));
865 scoped_ptr
<LaunchEphemeralApp::Params
> params(
866 LaunchEphemeralApp::Params::Create(*args_
));
867 EXTENSION_FUNCTION_VALIDATE(params
);
869 AddRef(); // Balanced in OnLaunchComplete()
871 scoped_refptr
<EphemeralAppLauncher
> launcher
=
872 EphemeralAppLauncher::CreateForWebContents(
876 &WebstorePrivateLaunchEphemeralAppFunction::OnLaunchComplete
,
877 base::Unretained(this)));
880 return RespondLater();
883 void WebstorePrivateLaunchEphemeralAppFunction::OnLaunchComplete(
884 webstore_install::Result result
, const std::string
& error
) {
885 Respond(BuildResponse(WebstoreInstallResultToApiResult(result
), error
));
886 Release(); // Matches AddRef() in Run()
889 ExtensionFunction::ResponseValue
890 WebstorePrivateLaunchEphemeralAppFunction::BuildResponse(
891 api::webstore_private::Result result
, const std::string
& error
) {
892 if (result
!= api::webstore_private::RESULT_SUCCESS
) {
893 std::string error_message
;
895 error_message
= base::StringPrintf(
896 "[%s]", api::webstore_private::ToString(result
).c_str());
898 error_message
= base::StringPrintf(
900 api::webstore_private::ToString(result
).c_str(),
903 return ErrorWithArguments(LaunchEphemeralApp::Results::Create(result
),
906 return ArgumentList(LaunchEphemeralApp::Results::Create(result
));
909 WebstorePrivateGetEphemeralAppsEnabledFunction::
910 WebstorePrivateGetEphemeralAppsEnabledFunction() {}
912 WebstorePrivateGetEphemeralAppsEnabledFunction::
913 ~WebstorePrivateGetEphemeralAppsEnabledFunction() {}
915 ExtensionFunction::ResponseAction
916 WebstorePrivateGetEphemeralAppsEnabledFunction::Run() {
917 return RespondNow(ArgumentList(GetEphemeralAppsEnabled::Results::Create(
918 EphemeralAppLauncher::IsFeatureEnabled())));
921 } // namespace extensions