Upstream version 11.40.271.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / management / chrome_management_api_delegate.cc
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.
4
5 #include "chrome/browser/extensions/api/management/chrome_management_api_delegate.h"
6
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"
37
38 namespace {
39
40 // This class helps ManagementGetPermissionWarningsByManifestFunction manage
41 // sending manifest JSON strings to the utility process for parsing.
42 class SafeManifestJSONParser : public content::UtilityProcessHostClient {
43  public:
44   SafeManifestJSONParser(
45       extensions::ManagementGetPermissionWarningsByManifestFunction* client,
46       const std::string& manifest)
47       : client_(client), manifest_(manifest) {}
48
49   void Start() {
50     CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
51     content::BrowserThread::PostTask(
52         content::BrowserThread::IO, FROM_HERE,
53         base::Bind(&SafeManifestJSONParser::StartWorkOnIOThread, this));
54   }
55
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_));
61   }
62
63   bool OnMessageReceived(const IPC::Message& message) override {
64     bool handled = true;
65     IPC_BEGIN_MESSAGE_MAP(SafeManifestJSONParser, message)
66     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded,
67                         OnJSONParseSucceeded)
68     IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed,
69                         OnJSONParseFailed)
70     IPC_MESSAGE_UNHANDLED(handled = false)
71     IPC_END_MESSAGE_MAP()
72     return handled;
73   }
74
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());
82     else
83       error_ = extension_management_api_constants::kManifestParseError;
84
85     content::BrowserThread::PostTask(
86         content::BrowserThread::UI, FROM_HERE,
87         base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this));
88   }
89
90   void OnJSONParseFailed(const std::string& error) {
91     CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
92     error_ = error;
93     content::BrowserThread::PostTask(
94         content::BrowserThread::UI, FROM_HERE,
95         base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this));
96   }
97
98   void ReportResultFromUIThread() {
99     CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
100     if (error_.empty() && parsed_manifest_.get())
101       client_->OnParseSuccess(parsed_manifest_.Pass());
102     else
103       client_->OnParseFailure(error_);
104   }
105
106  private:
107   ~SafeManifestJSONParser() override {}
108
109   // The client who we'll report results back to.
110   extensions::ManagementGetPermissionWarningsByManifestFunction* client_;
111
112   // Data to parse.
113   std::string manifest_;
114
115   // Results of parsing.
116   scoped_ptr<base::DictionaryValue> parsed_manifest_;
117
118   std::string error_;
119 };
120
121 class ManagementSetEnabledFunctionInstallPromptDelegate
122     : public ExtensionInstallPrompt::Delegate,
123       public extensions::InstallPromptDelegate {
124  public:
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);
132   }
133   virtual ~ManagementSetEnabledFunctionInstallPromptDelegate() {}
134
135  protected:
136   // ExtensionInstallPrompt::Delegate.
137   void InstallUIProceed() override { function_->InstallUIProceed(); }
138   void InstallUIAbort(bool user_initiated) override {
139     function_->InstallUIAbort(user_initiated);
140   }
141
142  private:
143   extensions::ManagementSetEnabledFunction* function_;
144   ChromeExtensionFunctionDetails details_;
145
146   // Used for prompting to re-enable items with permissions escalation updates.
147   scoped_ptr<ExtensionInstallPrompt> install_prompt_;
148 };
149
150 class ManagementUninstallFunctionUninstallDialogDelegate
151     : public extensions::ExtensionUninstallDialog::Delegate,
152       public extensions::UninstallDialogDelegate {
153  public:
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,
167             this));
168     if (function->extension_id() != target_extension_id) {
169       extension_uninstall_dialog_->ConfirmProgrammaticUninstall(
170           target_extension, function->extension());
171     } else {
172       // If this is a self uninstall, show the generic uninstall dialog.
173       extension_uninstall_dialog_->ConfirmUninstall(target_extension);
174     }
175   }
176   ~ManagementUninstallFunctionUninstallDialogDelegate() override {}
177
178   // ExtensionUninstallDialog::Delegate implementation.
179   void ExtensionUninstallAccepted() override {
180     function_->ExtensionUninstallAccepted();
181   }
182   void ExtensionUninstallCanceled() override {
183     function_->ExtensionUninstallCanceled();
184   }
185
186  protected:
187   extensions::ManagementUninstallFunctionBase* function_;
188   scoped_ptr<extensions::ExtensionUninstallDialog> extension_uninstall_dialog_;
189 };
190
191 class ChromeAppForLinkDelegate : public extensions::AppForLinkDelegate {
192  public:
193   ChromeAppForLinkDelegate() {}
194   ~ChromeAppForLinkDelegate() override {}
195
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;
205
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);
212     }
213
214     bookmark_app_helper_.reset(new extensions::BookmarkAppHelper(
215         extensions::ExtensionSystem::Get(context)->extension_service(), web_app,
216         NULL));
217     bookmark_app_helper_->Create(
218         base::Bind(&extensions::ManagementGenerateAppForLinkFunction::
219                        FinishCreateBookmarkApp,
220                    function));
221   }
222
223   scoped_ptr<extensions::BookmarkAppHelper> bookmark_app_helper_;
224
225   // Used for favicon loading tasks.
226   base::CancelableTaskTracker cancelable_task_tracker_;
227 };
228
229 }  // namespace
230
231 ChromeManagementAPIDelegate::ChromeManagementAPIDelegate() {
232 }
233
234 ChromeManagementAPIDelegate::~ChromeManagementAPIDelegate() {
235 }
236
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
242   // returned.
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());
250
251   return true;
252 }
253
254 GURL ChromeManagementAPIDelegate::GetFullLaunchURL(
255     const extensions::Extension* extension) const {
256   return extensions::AppLaunchInfo::GetFullLaunchURL(extension);
257 }
258
259 extensions::LaunchType ChromeManagementAPIDelegate::GetLaunchType(
260     const extensions::ExtensionPrefs* prefs,
261     const extensions::Extension* extension) const {
262   return extensions::GetLaunchType(prefs, extension);
263 }
264
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);
271   parser->Start();
272 }
273
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,
280                                                             extension));
281 }
282
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));
290 }
291
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);
298   if (!browser) {
299     // Shouldn't happen if we have user gesture.
300     function->SetError(
301         extension_management_api_constants::kNoBrowserToCreateShortcut);
302     return false;
303   }
304
305   chrome::ShowCreateChromeAppShortcutsDialog(
306       browser->window()->GetNativeWindow(), browser->profile(), extension,
307       base::Bind(&extensions::ManagementCreateAppShortcutFunction::
308                      OnCloseShortcutPrompt,
309                  function));
310
311   return true;
312 }
313
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);
323
324   ChromeAppForLinkDelegate* delegate = new ChromeAppForLinkDelegate;
325
326   favicon_service->GetFaviconImageForPageURL(
327       launch_url,
328       base::Bind(
329           &ChromeAppForLinkDelegate::OnFaviconForApp,
330           base::Unretained(delegate),
331           scoped_refptr<extensions::ManagementGenerateAppForLinkFunction>(
332               function),
333           context, title, launch_url),
334       &delegate->cancelable_task_tracker_);
335
336   return scoped_ptr<extensions::AppForLinkDelegate>(delegate);
337 }
338
339 bool ChromeManagementAPIDelegate::IsStreamlinedHostedAppsEnabled() const {
340   return extensions::util::IsStreamlinedHostedAppsEnabled();
341 }
342
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);
349 }
350
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);
358 }
359
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);
370 }
371
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);
379 }
380
381 GURL ChromeManagementAPIDelegate::GetIconURL(
382     const extensions::Extension* extension,
383     int icon_size,
384     ExtensionIconSet::MatchType match,
385     bool grayscale,
386     bool* exists) const {
387   return extensions::ExtensionIconSource::GetIconURL(extension, icon_size,
388                                                      match, grayscale, exists);
389 }