1 // Copyright 2015 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/dashboard_private/dashboard_private_api.h"
8 #include "base/thread_task_runner_handle.h"
9 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "components/crx_file/id_util.h"
12 #include "extensions/common/extension.h"
13 #include "net/base/load_flags.h"
14 #include "net/url_request/url_request.h"
17 namespace extensions
{
19 namespace ShowPermissionPromptForDelegatedInstall
=
20 api::dashboard_private::ShowPermissionPromptForDelegatedInstall
;
21 namespace ShowPermissionPromptForDelegatedBundleInstall
=
22 api::dashboard_private::ShowPermissionPromptForDelegatedBundleInstall
;
26 // Error messages that can be returned by the API.
27 const char kAlreadyInstalledError
[] = "This item is already installed";
28 const char kCannotSpecifyIconDataAndUrlError
[] =
29 "You cannot specify both icon data and an icon url";
30 const char kInvalidBundleError
[] = "Invalid bundle";
31 const char kInvalidIconUrlError
[] = "Invalid icon url";
32 const char kInvalidIdError
[] = "Invalid id";
33 const char kInvalidManifestError
[] = "Invalid manifest";
34 const char kUserCancelledError
[] = "User cancelled install";
36 api::dashboard_private::Result
WebstoreInstallHelperResultToApiResult(
37 WebstoreInstallHelper::Delegate::InstallHelperResultCode result
) {
39 case WebstoreInstallHelper::Delegate::UNKNOWN_ERROR
:
40 return api::dashboard_private::RESULT_UNKNOWN_ERROR
;
41 case WebstoreInstallHelper::Delegate::ICON_ERROR
:
42 return api::dashboard_private::RESULT_ICON_ERROR
;
43 case WebstoreInstallHelper::Delegate::MANIFEST_ERROR
:
44 return api::dashboard_private::RESULT_MANIFEST_ERROR
;
47 return api::dashboard_private::RESULT_NONE
;
52 DashboardPrivateShowPermissionPromptForDelegatedInstallFunction::
53 DashboardPrivateShowPermissionPromptForDelegatedInstallFunction() {
56 DashboardPrivateShowPermissionPromptForDelegatedInstallFunction::
57 ~DashboardPrivateShowPermissionPromptForDelegatedInstallFunction() {
60 ExtensionFunction::ResponseAction
61 DashboardPrivateShowPermissionPromptForDelegatedInstallFunction::Run() {
62 params_
= Params::Create(*args_
);
63 EXTENSION_FUNCTION_VALIDATE(params_
);
65 if (!crx_file::id_util::IdIsValid(params_
->details
.id
)) {
66 return RespondNow(BuildResponse(api::dashboard_private::RESULT_INVALID_ID
,
70 if (params_
->details
.icon_data
&& params_
->details
.icon_url
) {
71 return RespondNow(BuildResponse(api::dashboard_private::RESULT_ICON_ERROR
,
72 kCannotSpecifyIconDataAndUrlError
));
76 if (params_
->details
.icon_url
) {
77 icon_url
= source_url().Resolve(*params_
->details
.icon_url
);
78 if (!icon_url
.is_valid()) {
79 return RespondNow(BuildResponse(
80 api::dashboard_private::RESULT_INVALID_ICON_URL
,
81 kInvalidIconUrlError
));
85 net::URLRequestContextGetter
* context_getter
= nullptr;
86 if (!icon_url
.is_empty())
87 context_getter
= browser_context()->GetRequestContext();
89 scoped_refptr
<WebstoreInstallHelper
> helper
= new WebstoreInstallHelper(
90 this, params_
->details
.id
, params_
->details
.manifest
, icon_url
,
93 // The helper will call us back via OnWebstoreParseSuccess or
94 // OnWebstoreParseFailure.
97 // Matched with a Release in OnWebstoreParseSuccess/OnWebstoreParseFailure.
100 // The response is sent asynchronously in OnWebstoreParseSuccess/
101 // OnWebstoreParseFailure.
102 return RespondLater();
105 void DashboardPrivateShowPermissionPromptForDelegatedInstallFunction::
106 OnWebstoreParseSuccess(
107 const std::string
& id
,
108 const SkBitmap
& icon
,
109 base::DictionaryValue
* parsed_manifest
) {
110 CHECK_EQ(params_
->details
.id
, id
);
111 CHECK(parsed_manifest
);
113 std::string localized_name
= params_
->details
.localized_name
?
114 *params_
->details
.localized_name
: std::string();
117 dummy_extension_
= ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
119 Extension::FROM_WEBSTORE
,
125 if (!dummy_extension_
.get()) {
126 OnWebstoreParseFailure(params_
->details
.id
,
127 WebstoreInstallHelper::Delegate::MANIFEST_ERROR
,
128 kInvalidManifestError
);
132 content::WebContents
* web_contents
= GetAssociatedWebContents();
134 // The browser window has gone away.
135 Respond(BuildResponse(api::dashboard_private::RESULT_USER_CANCELLED
,
136 kUserCancelledError
));
137 // Matches the AddRef in Run().
141 install_prompt_
.reset(new ExtensionInstallPrompt(web_contents
));
142 install_prompt_
->ConfirmPermissionsForDelegatedInstall(
143 this, dummy_extension_
.get(), details().delegated_user
, &icon
);
144 // Control flow finishes up in InstallUIProceed or InstallUIAbort.
147 void DashboardPrivateShowPermissionPromptForDelegatedInstallFunction::
148 OnWebstoreParseFailure(
149 const std::string
& id
,
150 WebstoreInstallHelper::Delegate::InstallHelperResultCode result
,
151 const std::string
& error_message
) {
152 CHECK_EQ(params_
->details
.id
, id
);
154 Respond(BuildResponse(WebstoreInstallHelperResultToApiResult(result
),
157 // Matches the AddRef in Run().
161 void DashboardPrivateShowPermissionPromptForDelegatedInstallFunction::
163 Respond(BuildResponse(api::dashboard_private::RESULT_SUCCESS
, std::string()));
165 // Matches the AddRef in Run().
169 void DashboardPrivateShowPermissionPromptForDelegatedInstallFunction::
170 InstallUIAbort(bool user_initiated
) {
171 Respond(BuildResponse(api::dashboard_private::RESULT_USER_CANCELLED
,
172 kUserCancelledError
));
174 // Matches the AddRef in Run().
178 ExtensionFunction::ResponseValue
179 DashboardPrivateShowPermissionPromptForDelegatedInstallFunction::BuildResponse(
180 api::dashboard_private::Result result
, const std::string
& error
) {
181 if (result
!= api::dashboard_private::RESULT_SUCCESS
)
182 return ErrorWithArguments(CreateResults(result
), error
);
184 // The web store expects an empty string on success, so don't use
185 // RESULT_SUCCESS here.
187 CreateResults(api::dashboard_private::RESULT_EMPTY_STRING
));
190 scoped_ptr
<base::ListValue
>
191 DashboardPrivateShowPermissionPromptForDelegatedInstallFunction::CreateResults(
192 api::dashboard_private::Result result
) const {
193 return ShowPermissionPromptForDelegatedInstall::Results::Create(result
);
196 DashboardPrivateShowPermissionPromptForDelegatedBundleInstallFunction::
197 DashboardPrivateShowPermissionPromptForDelegatedBundleInstallFunction()
198 : chrome_details_(this) {
201 DashboardPrivateShowPermissionPromptForDelegatedBundleInstallFunction::
202 ~DashboardPrivateShowPermissionPromptForDelegatedBundleInstallFunction() {
205 ExtensionFunction::ResponseAction
206 DashboardPrivateShowPermissionPromptForDelegatedBundleInstallFunction::Run() {
207 params_
= Params::Create(*args_
);
208 EXTENSION_FUNCTION_VALIDATE(params_
);
210 if (params_
->contents
.empty())
211 return RespondNow(Error(kInvalidBundleError
));
213 if (params_
->details
.icon_url
) {
214 GURL icon_url
= source_url().Resolve(*params_
->details
.icon_url
);
215 if (!icon_url
.is_valid())
216 return RespondNow(Error(kInvalidIconUrlError
));
218 // The bitmap fetcher will call us back via OnFetchComplete.
219 icon_fetcher_
.reset(new chrome::BitmapFetcher(icon_url
, this));
221 browser_context()->GetRequestContext(), std::string(),
222 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE
,
223 net::LOAD_DO_NOT_SAVE_COOKIES
| net::LOAD_DO_NOT_SEND_COOKIES
);
224 icon_fetcher_
->Start();
226 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, base::Bind(
227 &DashboardPrivateShowPermissionPromptForDelegatedBundleInstallFunction::
229 this, GURL(), nullptr));
232 AddRef(); // Balanced in OnFetchComplete.
234 // The response is sent in OnFetchComplete or OnInstallApproval.
235 return RespondLater();
238 void DashboardPrivateShowPermissionPromptForDelegatedBundleInstallFunction::
239 OnFetchComplete(const GURL
& url
, const SkBitmap
* bitmap
) {
240 BundleInstaller::ItemList items
;
241 for (const auto& entry
: params_
->contents
) {
242 BundleInstaller::Item item
;
244 item
.manifest
= entry
->manifest
;
245 item
.localized_name
= entry
->localized_name
;
247 item
.icon_url
= source_url().Resolve(*entry
->icon_url
);
248 items
.push_back(item
);
251 Respond(Error(kAlreadyInstalledError
));
252 Release(); // Matches the AddRef in Run.
256 bundle_
.reset(new BundleInstaller(chrome_details_
.GetCurrentBrowser(),
257 params_
->details
.localized_name
,
258 bitmap
? *bitmap
: SkBitmap(),
259 std::string(), details().delegated_user
,
262 bundle_
->PromptForApproval(base::Bind(
263 &DashboardPrivateShowPermissionPromptForDelegatedBundleInstallFunction::
267 Release(); // Matches the AddRef in Run.
270 void DashboardPrivateShowPermissionPromptForDelegatedBundleInstallFunction::
271 OnInstallApproval(BundleInstaller::ApprovalState state
) {
272 if (state
!= BundleInstaller::APPROVED
) {
273 Respond(Error(state
== BundleInstaller::USER_CANCELED
274 ? kUserCancelledError
275 : kInvalidBundleError
));
279 Respond(NoArguments());
282 } // namespace extensions