1 // Copyright 2014 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/management/chrome_management_api_delegate.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/browser/extensions/bookmark_app_helper.h"
9 #include "chrome/browser/extensions/chrome_extension_function_details.h"
10 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/browser/extensions/extension_util.h"
12 #include "chrome/browser/extensions/launch_util.h"
13 #include "chrome/browser/favicon/favicon_service.h"
14 #include "chrome/browser/favicon/favicon_service_factory.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/ui/browser_dialogs.h"
17 #include "chrome/browser/ui/browser_finder.h"
18 #include "chrome/browser/ui/browser_window.h"
19 #include "chrome/browser/ui/extensions/app_launch_params.h"
20 #include "chrome/browser/ui/extensions/application_launch.h"
21 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
22 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
23 #include "chrome/common/extensions/chrome_utility_extensions_messages.h"
24 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
25 #include "chrome/common/web_application_info.h"
26 #include "content/public/browser/browser_context.h"
27 #include "content/public/browser/utility_process_host.h"
28 #include "content/public/browser/utility_process_host_client.h"
29 #include "content/public/browser/web_contents.h"
30 #include "extensions/browser/api/management/management_api.h"
31 #include "extensions/browser/api/management/management_api_constants.h"
32 #include "extensions/browser/extension_prefs.h"
33 #include "extensions/browser/extension_registry.h"
34 #include "extensions/browser/extension_system.h"
35 #include "extensions/common/constants.h"
36 #include "extensions/common/extension.h"
40 // This class helps ManagementGetPermissionWarningsByManifestFunction manage
41 // sending manifest JSON strings to the utility process for parsing.
42 class SafeManifestJSONParser : public content::UtilityProcessHostClient {
44 SafeManifestJSONParser(
45 extensions::ManagementGetPermissionWarningsByManifestFunction* client,
46 const std::string& manifest)
47 : client_(client), manifest_(manifest) {}
50 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
51 content::BrowserThread::PostTask(
52 content::BrowserThread::IO, FROM_HERE,
53 base::Bind(&SafeManifestJSONParser::StartWorkOnIOThread, this));
56 void StartWorkOnIOThread() {
57 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
58 content::UtilityProcessHost* host = content::UtilityProcessHost::Create(
59 this, base::MessageLoopProxy::current().get());
60 host->Send(new ChromeUtilityMsg_ParseJSON(manifest_));
63 bool OnMessageReceived(const IPC::Message& message) override {
65 IPC_BEGIN_MESSAGE_MAP(SafeManifestJSONParser, message)
66 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded,
68 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed,
70 IPC_MESSAGE_UNHANDLED(handled = false)
75 void OnJSONParseSucceeded(const base::ListValue& wrapper) {
76 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
77 const base::Value* value = NULL;
78 CHECK(wrapper.Get(0, &value));
79 if (value->IsType(base::Value::TYPE_DICTIONARY))
80 parsed_manifest_.reset(
81 static_cast<const base::DictionaryValue*>(value)->DeepCopy());
83 error_ = extension_management_api_constants::kManifestParseError;
85 content::BrowserThread::PostTask(
86 content::BrowserThread::UI, FROM_HERE,
87 base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this));
90 void OnJSONParseFailed(const std::string& error) {
91 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
93 content::BrowserThread::PostTask(
94 content::BrowserThread::UI, FROM_HERE,
95 base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this));
98 void ReportResultFromUIThread() {
99 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
100 if (error_.empty() && parsed_manifest_.get())
101 client_->OnParseSuccess(parsed_manifest_.Pass());
103 client_->OnParseFailure(error_);
107 ~SafeManifestJSONParser() override {}
109 // The client who we'll report results back to.
110 extensions::ManagementGetPermissionWarningsByManifestFunction* client_;
113 std::string manifest_;
115 // Results of parsing.
116 scoped_ptr<base::DictionaryValue> parsed_manifest_;
121 class ManagementSetEnabledFunctionInstallPromptDelegate
122 : public ExtensionInstallPrompt::Delegate,
123 public extensions::InstallPromptDelegate {
125 ManagementSetEnabledFunctionInstallPromptDelegate(
126 extensions::ManagementSetEnabledFunction* function,
127 const extensions::Extension* extension)
128 : function_(function), details_(function) {
129 install_prompt_.reset(
130 new ExtensionInstallPrompt(details_.GetAssociatedWebContents()));
131 install_prompt_->ConfirmReEnable(this, extension);
133 virtual ~ManagementSetEnabledFunctionInstallPromptDelegate() {}
136 // ExtensionInstallPrompt::Delegate.
137 void InstallUIProceed() override { function_->InstallUIProceed(); }
138 void InstallUIAbort(bool user_initiated) override {
139 function_->InstallUIAbort(user_initiated);
143 extensions::ManagementSetEnabledFunction* function_;
144 ChromeExtensionFunctionDetails details_;
146 // Used for prompting to re-enable items with permissions escalation updates.
147 scoped_ptr<ExtensionInstallPrompt> install_prompt_;
150 class ManagementUninstallFunctionUninstallDialogDelegate
151 : public extensions::ExtensionUninstallDialog::Delegate,
152 public extensions::UninstallDialogDelegate {
154 ManagementUninstallFunctionUninstallDialogDelegate(
155 extensions::ManagementUninstallFunctionBase* function,
156 const std::string& target_extension_id)
157 : function_(function) {
158 const extensions::Extension* target_extension =
159 extensions::ExtensionRegistry::Get(function->browser_context())
160 ->GetExtensionById(target_extension_id,
161 extensions::ExtensionRegistry::EVERYTHING);
162 content::WebContents* web_contents = function->GetAssociatedWebContents();
163 extension_uninstall_dialog_.reset(
164 extensions::ExtensionUninstallDialog::Create(
165 Profile::FromBrowserContext(function->browser_context()),
166 web_contents ? web_contents->GetTopLevelNativeWindow() : NULL,
168 if (function->extension_id() != target_extension_id) {
169 extension_uninstall_dialog_->ConfirmProgrammaticUninstall(
170 target_extension, function->extension());
172 // If this is a self uninstall, show the generic uninstall dialog.
173 extension_uninstall_dialog_->ConfirmUninstall(target_extension);
176 ~ManagementUninstallFunctionUninstallDialogDelegate() override {}
178 // ExtensionUninstallDialog::Delegate implementation.
179 void ExtensionUninstallAccepted() override {
180 function_->ExtensionUninstallAccepted();
182 void ExtensionUninstallCanceled() override {
183 function_->ExtensionUninstallCanceled();
187 extensions::ManagementUninstallFunctionBase* function_;
188 scoped_ptr<extensions::ExtensionUninstallDialog> extension_uninstall_dialog_;
191 class ChromeAppForLinkDelegate : public extensions::AppForLinkDelegate {
193 ChromeAppForLinkDelegate() {}
194 ~ChromeAppForLinkDelegate() override {}
196 void OnFaviconForApp(
197 extensions::ManagementGenerateAppForLinkFunction* function,
198 content::BrowserContext* context,
199 const std::string& title,
200 const GURL& launch_url,
201 const favicon_base::FaviconImageResult& image_result) {
202 WebApplicationInfo web_app;
203 web_app.title = base::UTF8ToUTF16(std::string(title));
204 web_app.app_url = launch_url;
206 if (!image_result.image.IsEmpty()) {
207 WebApplicationInfo::IconInfo icon;
208 icon.data = image_result.image.AsBitmap();
209 icon.width = icon.data.width();
210 icon.height = icon.data.height();
211 web_app.icons.push_back(icon);
214 bookmark_app_helper_.reset(new extensions::BookmarkAppHelper(
215 extensions::ExtensionSystem::Get(context)->extension_service(), web_app,
217 bookmark_app_helper_->Create(
218 base::Bind(&extensions::ManagementGenerateAppForLinkFunction::
219 FinishCreateBookmarkApp,
223 scoped_ptr<extensions::BookmarkAppHelper> bookmark_app_helper_;
225 // Used for favicon loading tasks.
226 base::CancelableTaskTracker cancelable_task_tracker_;
231 ChromeManagementAPIDelegate::ChromeManagementAPIDelegate() {
234 ChromeManagementAPIDelegate::~ChromeManagementAPIDelegate() {
237 bool ChromeManagementAPIDelegate::LaunchAppFunctionDelegate(
238 const extensions::Extension* extension,
239 content::BrowserContext* context) const {
240 // Look at prefs to find the right launch container.
241 // If the user has not set a preference, the default launch value will be
243 extensions::LaunchContainer launch_container =
244 GetLaunchContainer(extensions::ExtensionPrefs::Get(context), extension);
245 OpenApplication(AppLaunchParams(Profile::FromBrowserContext(context),
246 extension, launch_container,
247 NEW_FOREGROUND_TAB));
248 CoreAppLauncherHandler::RecordAppLaunchType(
249 extension_misc::APP_LAUNCH_EXTENSION_API, extension->GetType());
254 GURL ChromeManagementAPIDelegate::GetFullLaunchURL(
255 const extensions::Extension* extension) const {
256 return extensions::AppLaunchInfo::GetFullLaunchURL(extension);
259 extensions::LaunchType ChromeManagementAPIDelegate::GetLaunchType(
260 const extensions::ExtensionPrefs* prefs,
261 const extensions::Extension* extension) const {
262 return extensions::GetLaunchType(prefs, extension);
265 void ChromeManagementAPIDelegate::
266 GetPermissionWarningsByManifestFunctionDelegate(
267 extensions::ManagementGetPermissionWarningsByManifestFunction* function,
268 const std::string& manifest_str) const {
269 scoped_refptr<SafeManifestJSONParser> parser =
270 new SafeManifestJSONParser(function, manifest_str);
274 scoped_ptr<extensions::InstallPromptDelegate>
275 ChromeManagementAPIDelegate::SetEnabledFunctionDelegate(
276 extensions::ManagementSetEnabledFunction* function,
277 const extensions::Extension* extension) const {
278 return scoped_ptr<ManagementSetEnabledFunctionInstallPromptDelegate>(
279 new ManagementSetEnabledFunctionInstallPromptDelegate(function,
283 scoped_ptr<extensions::UninstallDialogDelegate>
284 ChromeManagementAPIDelegate::UninstallFunctionDelegate(
285 extensions::ManagementUninstallFunctionBase* function,
286 const std::string& target_extension_id) const {
287 return scoped_ptr<extensions::UninstallDialogDelegate>(
288 new ManagementUninstallFunctionUninstallDialogDelegate(
289 function, target_extension_id));
292 bool ChromeManagementAPIDelegate::CreateAppShortcutFunctionDelegate(
293 extensions::ManagementCreateAppShortcutFunction* function,
294 const extensions::Extension* extension) const {
295 Browser* browser = chrome::FindBrowserWithProfile(
296 Profile::FromBrowserContext(function->browser_context()),
297 chrome::HOST_DESKTOP_TYPE_NATIVE);
299 // Shouldn't happen if we have user gesture.
301 extension_management_api_constants::kNoBrowserToCreateShortcut);
305 chrome::ShowCreateChromeAppShortcutsDialog(
306 browser->window()->GetNativeWindow(), browser->profile(), extension,
307 base::Bind(&extensions::ManagementCreateAppShortcutFunction::
308 OnCloseShortcutPrompt,
314 scoped_ptr<extensions::AppForLinkDelegate>
315 ChromeManagementAPIDelegate::GenerateAppForLinkFunctionDelegate(
316 extensions::ManagementGenerateAppForLinkFunction* function,
317 content::BrowserContext* context,
318 const std::string& title,
319 const GURL& launch_url) const {
320 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile(
321 Profile::FromBrowserContext(context), Profile::EXPLICIT_ACCESS);
322 DCHECK(favicon_service);
324 ChromeAppForLinkDelegate* delegate = new ChromeAppForLinkDelegate;
326 favicon_service->GetFaviconImageForPageURL(
329 &ChromeAppForLinkDelegate::OnFaviconForApp,
330 base::Unretained(delegate),
331 scoped_refptr<extensions::ManagementGenerateAppForLinkFunction>(
333 context, title, launch_url),
334 &delegate->cancelable_task_tracker_);
336 return scoped_ptr<extensions::AppForLinkDelegate>(delegate);
339 bool ChromeManagementAPIDelegate::IsStreamlinedHostedAppsEnabled() const {
340 return extensions::util::IsStreamlinedHostedAppsEnabled();
343 void ChromeManagementAPIDelegate::EnableExtension(
344 content::BrowserContext* context,
345 const std::string& extension_id) const {
346 extensions::ExtensionSystem::Get(context)
347 ->extension_service()
348 ->EnableExtension(extension_id);
351 void ChromeManagementAPIDelegate::DisableExtension(
352 content::BrowserContext* context,
353 const std::string& extension_id,
354 extensions::Extension::DisableReason disable_reason) const {
355 extensions::ExtensionSystem::Get(context)
356 ->extension_service()
357 ->DisableExtension(extension_id, disable_reason);
360 bool ChromeManagementAPIDelegate::UninstallExtension(
361 content::BrowserContext* context,
362 const std::string& transient_extension_id,
363 extensions::UninstallReason reason,
364 const base::Closure& deletion_done_callback,
365 base::string16* error) const {
366 return extensions::ExtensionSystem::Get(context)
367 ->extension_service()
368 ->UninstallExtension(transient_extension_id, reason,
369 deletion_done_callback, error);
372 void ChromeManagementAPIDelegate::SetLaunchType(
373 content::BrowserContext* context,
374 const std::string& extension_id,
375 extensions::LaunchType launch_type) const {
376 extensions::SetLaunchType(
377 extensions::ExtensionSystem::Get(context)->extension_service(),
378 extension_id, launch_type);
381 GURL ChromeManagementAPIDelegate::GetIconURL(
382 const extensions::Extension* extension,
384 ExtensionIconSet::MatchType match,
386 bool* exists) const {
387 return extensions::ExtensionIconSource::GetIconURL(extension, icon_size,
388 match, grayscale, exists);