• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/management/management_api.h"
6 
7 #include <string>
8 #include <vector>
9 
10 #include "base/basictypes.h"
11 #include "base/bind.h"
12 #include "base/json/json_writer.h"
13 #include "base/lazy_instance.h"
14 #include "base/logging.h"
15 #include "base/memory/linked_ptr.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/metrics/histogram.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "chrome/browser/extensions/api/management/management_api_constants.h"
22 #include "chrome/browser/extensions/extension_service.h"
23 #include "chrome/browser/extensions/extension_ui_util.h"
24 #include "chrome/browser/extensions/extension_uninstall_dialog.h"
25 #include "chrome/browser/extensions/launch_util.h"
26 #include "chrome/browser/favicon/favicon_service_factory.h"
27 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/ui/browser_dialogs.h"
29 #include "chrome/browser/ui/browser_finder.h"
30 #include "chrome/browser/ui/browser_window.h"
31 #include "chrome/browser/ui/extensions/application_launch.h"
32 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
33 #include "chrome/common/chrome_switches.h"
34 #include "chrome/common/chrome_utility_messages.h"
35 #include "chrome/common/extensions/api/management.h"
36 #include "chrome/common/extensions/extension_constants.h"
37 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
38 #include "chrome/common/extensions/manifest_url_handler.h"
39 #include "content/public/browser/utility_process_host.h"
40 #include "content/public/browser/utility_process_host_client.h"
41 #include "extensions/browser/event_router.h"
42 #include "extensions/browser/extension_prefs.h"
43 #include "extensions/browser/extension_registry.h"
44 #include "extensions/browser/extension_system.h"
45 #include "extensions/browser/management_policy.h"
46 #include "extensions/common/constants.h"
47 #include "extensions/common/error_utils.h"
48 #include "extensions/common/extension.h"
49 #include "extensions/common/extension_icon_set.h"
50 #include "extensions/common/manifest_handlers/icons_handler.h"
51 #include "extensions/common/manifest_handlers/offline_enabled_info.h"
52 #include "extensions/common/permissions/permission_set.h"
53 #include "extensions/common/permissions/permissions_data.h"
54 #include "extensions/common/url_pattern.h"
55 #include "ui/gfx/favicon_size.h"
56 
57 #if !defined(OS_ANDROID)
58 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
59 #endif
60 
61 using base::IntToString;
62 using content::BrowserThread;
63 using content::UtilityProcessHost;
64 using content::UtilityProcessHostClient;
65 
66 namespace keys = extension_management_api_constants;
67 
68 namespace extensions {
69 
70 namespace management = api::management;
71 
72 namespace {
73 
74 typedef std::vector<linked_ptr<management::ExtensionInfo> > ExtensionInfoList;
75 typedef std::vector<linked_ptr<management::IconInfo> > IconInfoList;
76 
77 enum AutoConfirmForTest {
78   DO_NOT_SKIP = 0,
79   PROCEED,
80   ABORT
81 };
82 
83 AutoConfirmForTest auto_confirm_for_test = DO_NOT_SKIP;
84 
CreateWarningsList(const Extension * extension)85 std::vector<std::string> CreateWarningsList(const Extension* extension) {
86   std::vector<std::string> warnings_list;
87   PermissionMessages warnings =
88       extension->permissions_data()->GetPermissionMessages();
89   for (PermissionMessages::const_iterator iter = warnings.begin();
90        iter != warnings.end(); ++iter) {
91     warnings_list.push_back(base::UTF16ToUTF8(iter->message()));
92   }
93 
94   return warnings_list;
95 }
96 
GetAvailableLaunchTypes(const Extension & extension)97 std::vector<management::LaunchType> GetAvailableLaunchTypes(
98     const Extension& extension) {
99   std::vector<management::LaunchType> launch_type_list;
100   if (extension.is_platform_app()) {
101     launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_WINDOW);
102     return launch_type_list;
103   }
104 
105   launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB);
106 
107 #if !defined(OS_MACOSX)
108   launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_WINDOW);
109 #endif
110 
111   if (!CommandLine::ForCurrentProcess()->HasSwitch(
112           switches::kEnableStreamlinedHostedApps)) {
113     launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB);
114     launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_FULL_SCREEN);
115   }
116   return launch_type_list;
117 }
118 
CreateExtensionInfo(const Extension & extension,ExtensionSystem * system)119 scoped_ptr<management::ExtensionInfo> CreateExtensionInfo(
120     const Extension& extension,
121     ExtensionSystem* system) {
122   scoped_ptr<management::ExtensionInfo> info(new management::ExtensionInfo());
123   ExtensionService* service = system->extension_service();
124 
125   info->id = extension.id();
126   info->name = extension.name();
127   info->short_name = extension.short_name();
128   info->enabled = service->IsExtensionEnabled(info->id);
129   info->offline_enabled = OfflineEnabledInfo::IsOfflineEnabled(&extension);
130   info->version = extension.VersionString();
131   info->description = extension.description();
132   info->options_url = ManifestURL::GetOptionsPage(&extension).spec();
133   info->homepage_url.reset(new std::string(
134       ManifestURL::GetHomepageURL(&extension).spec()));
135   info->may_disable = system->management_policy()->
136       UserMayModifySettings(&extension, NULL);
137   info->is_app = extension.is_app();
138   if (info->is_app) {
139     if (extension.is_legacy_packaged_app())
140       info->type = management::ExtensionInfo::TYPE_LEGACY_PACKAGED_APP;
141     else if (extension.is_hosted_app())
142       info->type = management::ExtensionInfo::TYPE_HOSTED_APP;
143     else
144       info->type = management::ExtensionInfo::TYPE_PACKAGED_APP;
145   } else if (extension.is_theme()) {
146     info->type = management::ExtensionInfo::TYPE_THEME;
147   } else {
148     info->type = management::ExtensionInfo::TYPE_EXTENSION;
149   }
150 
151   if (info->enabled) {
152     info->disabled_reason = management::ExtensionInfo::DISABLED_REASON_NONE;
153   } else {
154     ExtensionPrefs* prefs = ExtensionPrefs::Get(service->profile());
155     if (prefs->DidExtensionEscalatePermissions(extension.id())) {
156       info->disabled_reason =
157           management::ExtensionInfo::DISABLED_REASON_PERMISSIONS_INCREASE;
158     } else {
159       info->disabled_reason =
160           management::ExtensionInfo::DISABLED_REASON_UNKNOWN;
161     }
162   }
163 
164   if (!ManifestURL::GetUpdateURL(&extension).is_empty()) {
165     info->update_url.reset(new std::string(
166         ManifestURL::GetUpdateURL(&extension).spec()));
167   }
168 
169   if (extension.is_app()) {
170     info->app_launch_url.reset(new std::string(
171         AppLaunchInfo::GetFullLaunchURL(&extension).spec()));
172   }
173 
174   const ExtensionIconSet::IconMap& icons =
175       IconsInfo::GetIcons(&extension).map();
176   if (!icons.empty()) {
177     info->icons.reset(new IconInfoList());
178     ExtensionIconSet::IconMap::const_iterator icon_iter;
179     for (icon_iter = icons.begin(); icon_iter != icons.end(); ++icon_iter) {
180       management::IconInfo* icon_info = new management::IconInfo();
181       icon_info->size = icon_iter->first;
182       GURL url = ExtensionIconSource::GetIconURL(
183           &extension, icon_info->size, ExtensionIconSet::MATCH_EXACTLY, false,
184           NULL);
185       icon_info->url = url.spec();
186       info->icons->push_back(make_linked_ptr<management::IconInfo>(icon_info));
187     }
188   }
189 
190   const std::set<std::string> perms =
191       extension.permissions_data()->active_permissions()->GetAPIsAsStrings();
192   if (!perms.empty()) {
193     std::set<std::string>::const_iterator perms_iter;
194     for (perms_iter = perms.begin(); perms_iter != perms.end(); ++perms_iter)
195       info->permissions.push_back(*perms_iter);
196   }
197 
198   if (!extension.is_hosted_app()) {
199     // Skip host permissions for hosted apps.
200     const URLPatternSet host_perms =
201         extension.permissions_data()->active_permissions()->explicit_hosts();
202     if (!host_perms.is_empty()) {
203       for (URLPatternSet::const_iterator iter = host_perms.begin();
204            iter != host_perms.end(); ++iter) {
205         info->host_permissions.push_back(iter->GetAsString());
206       }
207     }
208   }
209 
210   switch (extension.location()) {
211     case Manifest::INTERNAL:
212       info->install_type = management::ExtensionInfo::INSTALL_TYPE_NORMAL;
213       break;
214     case Manifest::UNPACKED:
215     case Manifest::COMMAND_LINE:
216       info->install_type = management::ExtensionInfo::INSTALL_TYPE_DEVELOPMENT;
217       break;
218     case Manifest::EXTERNAL_PREF:
219     case Manifest::EXTERNAL_REGISTRY:
220     case Manifest::EXTERNAL_PREF_DOWNLOAD:
221       info->install_type = management::ExtensionInfo::INSTALL_TYPE_SIDELOAD;
222       break;
223     case Manifest::EXTERNAL_POLICY:
224     case Manifest::EXTERNAL_POLICY_DOWNLOAD:
225       info->install_type = management::ExtensionInfo::INSTALL_TYPE_ADMIN;
226       break;
227     case Manifest::NUM_LOCATIONS:
228       NOTREACHED();
229     case Manifest::INVALID_LOCATION:
230     case Manifest::COMPONENT:
231     case Manifest::EXTERNAL_COMPONENT:
232       info->install_type = management::ExtensionInfo::INSTALL_TYPE_OTHER;
233       break;
234   }
235 
236   info->launch_type = management::LAUNCH_TYPE_NONE;
237   if (extension.is_app()) {
238     LaunchType launch_type;
239     if (extension.is_platform_app()) {
240       launch_type = LAUNCH_TYPE_WINDOW;
241     } else {
242       launch_type =
243           GetLaunchType(ExtensionPrefs::Get(service->profile()), &extension);
244     }
245 
246     switch (launch_type) {
247       case LAUNCH_TYPE_PINNED:
248         info->launch_type = management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB;
249         break;
250       case LAUNCH_TYPE_REGULAR:
251         info->launch_type = management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB;
252         break;
253       case LAUNCH_TYPE_FULLSCREEN:
254         info->launch_type = management::LAUNCH_TYPE_OPEN_FULL_SCREEN;
255         break;
256       case LAUNCH_TYPE_WINDOW:
257         info->launch_type = management::LAUNCH_TYPE_OPEN_AS_WINDOW;
258         break;
259       case LAUNCH_TYPE_INVALID:
260       case NUM_LAUNCH_TYPES:
261         NOTREACHED();
262     }
263 
264     info->available_launch_types.reset(new std::vector<management::LaunchType>(
265         GetAvailableLaunchTypes(extension)));
266   }
267 
268   return info.Pass();
269 }
270 
AddExtensionInfo(const ExtensionSet & extensions,ExtensionSystem * system,ExtensionInfoList * extension_list,content::BrowserContext * context)271 void AddExtensionInfo(const ExtensionSet& extensions,
272                             ExtensionSystem* system,
273                             ExtensionInfoList* extension_list,
274                             content::BrowserContext* context) {
275   for (ExtensionSet::const_iterator iter = extensions.begin();
276        iter != extensions.end(); ++iter) {
277     const Extension& extension = *iter->get();
278 
279     if (ui_util::ShouldNotBeVisible(&extension, context))
280       continue;  // Skip built-in extensions/apps.
281 
282     extension_list->push_back(make_linked_ptr<management::ExtensionInfo>(
283         CreateExtensionInfo(extension, system).release()));
284   }
285 }
286 
287 } // namespace
288 
service()289 ExtensionService* ManagementFunction::service() {
290   return GetProfile()->GetExtensionService();
291 }
292 
service()293 ExtensionService* AsyncManagementFunction::service() {
294   return GetProfile()->GetExtensionService();
295 }
296 
RunSync()297 bool ManagementGetAllFunction::RunSync() {
298   ExtensionInfoList extensions;
299   ExtensionRegistry* registry = ExtensionRegistry::Get(GetProfile());
300   ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
301 
302   AddExtensionInfo(registry->enabled_extensions(),
303                    system, &extensions, browser_context());
304   AddExtensionInfo(registry->disabled_extensions(),
305                    system, &extensions, browser_context());
306   AddExtensionInfo(registry->terminated_extensions(),
307                    system, &extensions, browser_context());
308 
309   results_ = management::GetAll::Results::Create(extensions);
310   return true;
311 }
312 
RunSync()313 bool ManagementGetFunction::RunSync() {
314   scoped_ptr<management::Get::Params> params(
315       management::Get::Params::Create(*args_));
316   EXTENSION_FUNCTION_VALIDATE(params.get());
317 
318   const Extension* extension = service()->GetExtensionById(params->id, true);
319   if (!extension) {
320     error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
321                                                      params->id);
322     return false;
323   }
324 
325   scoped_ptr<management::ExtensionInfo> info =
326       CreateExtensionInfo(*extension, ExtensionSystem::Get(GetProfile()));
327   results_ = management::Get::Results::Create(*info);
328 
329   return true;
330 }
331 
RunSync()332 bool ManagementGetPermissionWarningsByIdFunction::RunSync() {
333   scoped_ptr<management::GetPermissionWarningsById::Params> params(
334       management::GetPermissionWarningsById::Params::Create(*args_));
335   EXTENSION_FUNCTION_VALIDATE(params.get());
336 
337   const Extension* extension = service()->GetExtensionById(params->id, true);
338   if (!extension) {
339     error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
340                                                      params->id);
341     return false;
342   }
343 
344   std::vector<std::string> warnings = CreateWarningsList(extension);
345   results_ = management::GetPermissionWarningsById::Results::Create(warnings);
346   return true;
347 }
348 
349 namespace {
350 
351 // This class helps ManagementGetPermissionWarningsByManifestFunction manage
352 // sending manifest JSON strings to the utility process for parsing.
353 class SafeManifestJSONParser : public UtilityProcessHostClient {
354  public:
SafeManifestJSONParser(ManagementGetPermissionWarningsByManifestFunction * client,const std::string & manifest)355   SafeManifestJSONParser(
356       ManagementGetPermissionWarningsByManifestFunction* client,
357       const std::string& manifest)
358       : client_(client),
359         manifest_(manifest) {}
360 
Start()361   void Start() {
362     CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
363     BrowserThread::PostTask(
364         BrowserThread::IO,
365         FROM_HERE,
366         base::Bind(&SafeManifestJSONParser::StartWorkOnIOThread, this));
367   }
368 
StartWorkOnIOThread()369   void StartWorkOnIOThread() {
370     CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
371     UtilityProcessHost* host = UtilityProcessHost::Create(
372         this, base::MessageLoopProxy::current().get());
373     host->Send(new ChromeUtilityMsg_ParseJSON(manifest_));
374   }
375 
OnMessageReceived(const IPC::Message & message)376   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
377     bool handled = true;
378     IPC_BEGIN_MESSAGE_MAP(SafeManifestJSONParser, message)
379       IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded,
380                           OnJSONParseSucceeded)
381       IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed,
382                           OnJSONParseFailed)
383       IPC_MESSAGE_UNHANDLED(handled = false)
384     IPC_END_MESSAGE_MAP()
385     return handled;
386   }
387 
OnJSONParseSucceeded(const base::ListValue & wrapper)388   void OnJSONParseSucceeded(const base::ListValue& wrapper) {
389     CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
390     const base::Value* value = NULL;
391     CHECK(wrapper.Get(0, &value));
392     if (value->IsType(base::Value::TYPE_DICTIONARY))
393       parsed_manifest_.reset(
394           static_cast<const base::DictionaryValue*>(value)->DeepCopy());
395     else
396       error_ = keys::kManifestParseError;
397 
398     BrowserThread::PostTask(
399         BrowserThread::UI,
400         FROM_HERE,
401         base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this));
402   }
403 
OnJSONParseFailed(const std::string & error)404   void OnJSONParseFailed(const std::string& error) {
405     CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
406     error_ = error;
407     BrowserThread::PostTask(
408         BrowserThread::UI,
409         FROM_HERE,
410         base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this));
411   }
412 
ReportResultFromUIThread()413   void ReportResultFromUIThread() {
414     CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
415     if (error_.empty() && parsed_manifest_.get())
416       client_->OnParseSuccess(parsed_manifest_.Pass());
417     else
418       client_->OnParseFailure(error_);
419   }
420 
421  private:
~SafeManifestJSONParser()422   virtual ~SafeManifestJSONParser() {}
423 
424   // The client who we'll report results back to.
425   ManagementGetPermissionWarningsByManifestFunction* client_;
426 
427   // Data to parse.
428   std::string manifest_;
429 
430   // Results of parsing.
431   scoped_ptr<base::DictionaryValue> parsed_manifest_;
432 
433   std::string error_;
434 };
435 
436 }  // namespace
437 
RunAsync()438 bool ManagementGetPermissionWarningsByManifestFunction::RunAsync() {
439   scoped_ptr<management::GetPermissionWarningsByManifest::Params> params(
440       management::GetPermissionWarningsByManifest::Params::Create(*args_));
441   EXTENSION_FUNCTION_VALIDATE(params.get());
442 
443   scoped_refptr<SafeManifestJSONParser> parser =
444       new SafeManifestJSONParser(this, params->manifest_str);
445   parser->Start();
446 
447   // Matched with a Release() in OnParseSuccess/Failure().
448   AddRef();
449 
450   // Response is sent async in OnParseSuccess/Failure().
451   return true;
452 }
453 
OnParseSuccess(scoped_ptr<base::DictionaryValue> parsed_manifest)454 void ManagementGetPermissionWarningsByManifestFunction::OnParseSuccess(
455     scoped_ptr<base::DictionaryValue> parsed_manifest) {
456   CHECK(parsed_manifest.get());
457 
458   scoped_refptr<Extension> extension = Extension::Create(
459       base::FilePath(), Manifest::INVALID_LOCATION, *parsed_manifest,
460       Extension::NO_FLAGS, &error_);
461   if (!extension.get()) {
462     OnParseFailure(keys::kExtensionCreateError);
463     return;
464   }
465 
466   std::vector<std::string> warnings = CreateWarningsList(extension.get());
467   results_ =
468       management::GetPermissionWarningsByManifest::Results::Create(warnings);
469   SendResponse(true);
470 
471   // Matched with AddRef() in RunAsync().
472   Release();
473 }
474 
OnParseFailure(const std::string & error)475 void ManagementGetPermissionWarningsByManifestFunction::OnParseFailure(
476     const std::string& error) {
477   error_ = error;
478   SendResponse(false);
479 
480   // Matched with AddRef() in RunAsync().
481   Release();
482 }
483 
RunSync()484 bool ManagementLaunchAppFunction::RunSync() {
485   scoped_ptr<management::LaunchApp::Params> params(
486       management::LaunchApp::Params::Create(*args_));
487   EXTENSION_FUNCTION_VALIDATE(params.get());
488   const Extension* extension = service()->GetExtensionById(params->id, true);
489   if (!extension) {
490     error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
491                                                      params->id);
492     return false;
493   }
494   if (!extension->is_app()) {
495     error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError,
496                                                      params->id);
497     return false;
498   }
499 
500   // Look at prefs to find the right launch container.
501   // If the user has not set a preference, the default launch value will be
502   // returned.
503   LaunchContainer launch_container =
504       GetLaunchContainer(ExtensionPrefs::Get(GetProfile()), extension);
505   OpenApplication(AppLaunchParams(
506       GetProfile(), extension, launch_container, NEW_FOREGROUND_TAB));
507 #if !defined(OS_ANDROID)
508   CoreAppLauncherHandler::RecordAppLaunchType(
509       extension_misc::APP_LAUNCH_EXTENSION_API,
510       extension->GetType());
511 #endif
512 
513   return true;
514 }
515 
ManagementSetEnabledFunction()516 ManagementSetEnabledFunction::ManagementSetEnabledFunction() {
517 }
518 
~ManagementSetEnabledFunction()519 ManagementSetEnabledFunction::~ManagementSetEnabledFunction() {
520 }
521 
RunAsync()522 bool ManagementSetEnabledFunction::RunAsync() {
523   scoped_ptr<management::SetEnabled::Params> params(
524       management::SetEnabled::Params::Create(*args_));
525   EXTENSION_FUNCTION_VALIDATE(params.get());
526 
527   extension_id_ = params->id;
528 
529   const Extension* extension =
530       ExtensionRegistry::Get(GetProfile())
531           ->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
532   if (!extension || ui_util::ShouldNotBeVisible(extension, browser_context())) {
533     error_ = ErrorUtils::FormatErrorMessage(
534         keys::kNoExtensionError, extension_id_);
535     return false;
536   }
537 
538   const ManagementPolicy* policy =
539       ExtensionSystem::Get(GetProfile())->management_policy();
540   if (!policy->UserMayModifySettings(extension, NULL) ||
541       (!params->enabled && policy->MustRemainEnabled(extension, NULL)) ||
542       (params->enabled && policy->MustRemainDisabled(extension, NULL, NULL))) {
543     error_ = ErrorUtils::FormatErrorMessage(
544         keys::kUserCantModifyError, extension_id_);
545     return false;
546   }
547 
548   bool currently_enabled = service()->IsExtensionEnabled(extension_id_);
549 
550   if (!currently_enabled && params->enabled) {
551     ExtensionPrefs* prefs = ExtensionPrefs::Get(GetProfile());
552     if (prefs->DidExtensionEscalatePermissions(extension_id_)) {
553       if (!user_gesture()) {
554         error_ = keys::kGestureNeededForEscalationError;
555         return false;
556       }
557       AddRef(); // Matched in InstallUIProceed/InstallUIAbort
558       install_prompt_.reset(
559           new ExtensionInstallPrompt(GetAssociatedWebContents()));
560       install_prompt_->ConfirmReEnable(this, extension);
561       return true;
562     }
563     service()->EnableExtension(extension_id_);
564   } else if (currently_enabled && !params->enabled) {
565     service()->DisableExtension(extension_id_, Extension::DISABLE_USER_ACTION);
566   }
567 
568   BrowserThread::PostTask(
569       BrowserThread::UI,
570       FROM_HERE,
571       base::Bind(&ManagementSetEnabledFunction::SendResponse, this, true));
572 
573   return true;
574 }
575 
InstallUIProceed()576 void ManagementSetEnabledFunction::InstallUIProceed() {
577   service()->EnableExtension(extension_id_);
578   SendResponse(true);
579   Release();
580 }
581 
InstallUIAbort(bool user_initiated)582 void ManagementSetEnabledFunction::InstallUIAbort(bool user_initiated) {
583   error_ = keys::kUserDidNotReEnableError;
584   SendResponse(false);
585   Release();
586 }
587 
ManagementUninstallFunctionBase()588 ManagementUninstallFunctionBase::ManagementUninstallFunctionBase() {
589 }
590 
~ManagementUninstallFunctionBase()591 ManagementUninstallFunctionBase::~ManagementUninstallFunctionBase() {
592 }
593 
Uninstall(const std::string & target_extension_id,bool show_confirm_dialog)594 bool ManagementUninstallFunctionBase::Uninstall(
595     const std::string& target_extension_id,
596     bool show_confirm_dialog) {
597   extension_id_ = target_extension_id;
598   const Extension* target_extension =
599       service()->GetExtensionById(extension_id_, true);
600   if (!target_extension ||
601       ui_util::ShouldNotBeVisible(target_extension, browser_context())) {
602     error_ = ErrorUtils::FormatErrorMessage(
603         keys::kNoExtensionError, extension_id_);
604     return false;
605   }
606 
607   if (!ExtensionSystem::Get(GetProfile())
608            ->management_policy()
609            ->UserMayModifySettings(target_extension, NULL)) {
610     error_ = ErrorUtils::FormatErrorMessage(
611         keys::kUserCantModifyError, extension_id_);
612     return false;
613   }
614 
615   if (auto_confirm_for_test == DO_NOT_SKIP) {
616     if (show_confirm_dialog) {
617       AddRef(); // Balanced in ExtensionUninstallAccepted/Canceled
618       extension_uninstall_dialog_.reset(ExtensionUninstallDialog::Create(
619           GetProfile(), GetCurrentBrowser(), this));
620       if (extension_id() != target_extension_id) {
621         extension_uninstall_dialog_->ConfirmProgrammaticUninstall(
622             target_extension, GetExtension());
623       } else {
624         // If this is a self uninstall, show the generic uninstall dialog.
625         extension_uninstall_dialog_->ConfirmUninstall(target_extension);
626       }
627     } else {
628       Finish(true);
629     }
630   } else {
631     Finish(auto_confirm_for_test == PROCEED);
632   }
633 
634   return true;
635 }
636 
637 // static
SetAutoConfirmForTest(bool should_proceed)638 void ManagementUninstallFunctionBase::SetAutoConfirmForTest(
639     bool should_proceed) {
640   auto_confirm_for_test = should_proceed ? PROCEED : ABORT;
641 }
642 
Finish(bool should_uninstall)643 void ManagementUninstallFunctionBase::Finish(bool should_uninstall) {
644   if (should_uninstall) {
645     // The extension can be uninstalled in another window while the UI was
646     // showing. Do nothing in that case.
647     ExtensionRegistry* registry = ExtensionRegistry::Get(GetProfile());
648     const Extension* extension = registry->GetExtensionById(
649         extension_id_, ExtensionRegistry::EVERYTHING);
650     if (!extension) {
651       error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
652                                               extension_id_);
653       SendResponse(false);
654     } else {
655       bool success =
656           service()->UninstallExtension(extension_id_,
657                                         false, /* external uninstall */
658                                         NULL);
659 
660       // TODO set error_ if !success
661       SendResponse(success);
662     }
663   } else {
664     error_ = ErrorUtils::FormatErrorMessage(
665         keys::kUninstallCanceledError, extension_id_);
666     SendResponse(false);
667   }
668 
669 }
670 
ExtensionUninstallAccepted()671 void ManagementUninstallFunctionBase::ExtensionUninstallAccepted() {
672   Finish(true);
673   Release();
674 }
675 
ExtensionUninstallCanceled()676 void ManagementUninstallFunctionBase::ExtensionUninstallCanceled() {
677   Finish(false);
678   Release();
679 }
680 
ManagementUninstallFunction()681 ManagementUninstallFunction::ManagementUninstallFunction() {
682 }
683 
~ManagementUninstallFunction()684 ManagementUninstallFunction::~ManagementUninstallFunction() {
685 }
686 
RunAsync()687 bool ManagementUninstallFunction::RunAsync() {
688   scoped_ptr<management::Uninstall::Params> params(
689       management::Uninstall::Params::Create(*args_));
690   EXTENSION_FUNCTION_VALIDATE(extension_);
691   EXTENSION_FUNCTION_VALIDATE(params.get());
692 
693   bool show_confirm_dialog = true;
694   // By default confirmation dialog isn't shown when uninstalling self, but this
695   // can be overridden with showConfirmDialog.
696   if (params->id == extension_->id()) {
697     show_confirm_dialog = params->options.get() &&
698                           params->options->show_confirm_dialog.get() &&
699                           *params->options->show_confirm_dialog;
700   }
701   if (show_confirm_dialog && !user_gesture()) {
702     error_ = keys::kGestureNeededForUninstallError;
703     return false;
704   }
705   return Uninstall(params->id, show_confirm_dialog);
706 }
707 
ManagementUninstallSelfFunction()708 ManagementUninstallSelfFunction::ManagementUninstallSelfFunction() {
709 }
710 
~ManagementUninstallSelfFunction()711 ManagementUninstallSelfFunction::~ManagementUninstallSelfFunction() {
712 }
713 
RunAsync()714 bool ManagementUninstallSelfFunction::RunAsync() {
715   scoped_ptr<management::UninstallSelf::Params> params(
716       management::UninstallSelf::Params::Create(*args_));
717   EXTENSION_FUNCTION_VALIDATE(params.get());
718 
719   bool show_confirm_dialog = false;
720   if (params->options.get() && params->options->show_confirm_dialog.get())
721     show_confirm_dialog = *params->options->show_confirm_dialog;
722   return Uninstall(extension_->id(), show_confirm_dialog);
723 }
724 
ManagementCreateAppShortcutFunction()725 ManagementCreateAppShortcutFunction::ManagementCreateAppShortcutFunction() {
726 }
727 
~ManagementCreateAppShortcutFunction()728 ManagementCreateAppShortcutFunction::~ManagementCreateAppShortcutFunction() {
729 }
730 
731 // static
SetAutoConfirmForTest(bool should_proceed)732 void ManagementCreateAppShortcutFunction::SetAutoConfirmForTest(
733     bool should_proceed) {
734   auto_confirm_for_test = should_proceed ? PROCEED : ABORT;
735 }
736 
OnCloseShortcutPrompt(bool created)737 void ManagementCreateAppShortcutFunction::OnCloseShortcutPrompt(bool created) {
738   if (!created)
739     error_ = keys::kCreateShortcutCanceledError;
740   SendResponse(created);
741   Release();
742 }
743 
RunAsync()744 bool ManagementCreateAppShortcutFunction::RunAsync() {
745   if (!user_gesture()) {
746     error_ = keys::kGestureNeededForCreateAppShortcutError;
747     return false;
748   }
749 
750   scoped_ptr<management::CreateAppShortcut::Params> params(
751       management::CreateAppShortcut::Params::Create(*args_));
752   EXTENSION_FUNCTION_VALIDATE(params.get());
753   const Extension* extension = service()->GetExtensionById(params->id, true);
754   if (!extension) {
755     error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
756                                             params->id);
757     return false;
758   }
759 
760   if (!extension->is_app()) {
761     error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError, params->id);
762     return false;
763   }
764 
765 #if defined(OS_MACOSX)
766   if (!extension->is_platform_app()) {
767     error_ = keys::kCreateOnlyPackagedAppShortcutMac;
768     return false;
769   }
770 #endif
771 
772   Browser* browser = chrome::FindBrowserWithProfile(
773       GetProfile(), chrome::HOST_DESKTOP_TYPE_NATIVE);
774   if (!browser) {
775     // Shouldn't happen if we have user gesture.
776     error_ = keys::kNoBrowserToCreateShortcut;
777     return false;
778   }
779 
780   // Matched with a Release() in OnCloseShortcutPrompt().
781   AddRef();
782 
783   if (auto_confirm_for_test == DO_NOT_SKIP) {
784     chrome::ShowCreateChromeAppShortcutsDialog(
785         browser->window()->GetNativeWindow(), browser->profile(), extension,
786         base::Bind(&ManagementCreateAppShortcutFunction::OnCloseShortcutPrompt,
787            this));
788   } else {
789     OnCloseShortcutPrompt(auto_confirm_for_test == PROCEED);
790   }
791 
792   // Response is sent async in OnCloseShortcutPrompt().
793   return true;
794 }
795 
RunSync()796 bool ManagementSetLaunchTypeFunction::RunSync() {
797   if (!user_gesture()) {
798     error_ = keys::kGestureNeededForSetLaunchTypeError;
799     return false;
800   }
801 
802   scoped_ptr<management::SetLaunchType::Params> params(
803       management::SetLaunchType::Params::Create(*args_));
804   EXTENSION_FUNCTION_VALIDATE(params.get());
805   const Extension* extension = service()->GetExtensionById(params->id, true);
806   if (!extension) {
807     error_ =
808         ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, params->id);
809     return false;
810   }
811 
812   if (!extension->is_app()) {
813     error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError, params->id);
814     return false;
815   }
816 
817   std::vector<management::LaunchType> available_launch_types =
818       GetAvailableLaunchTypes(*extension);
819 
820   management::LaunchType app_launch_type = params->launch_type;
821   if (std::find(available_launch_types.begin(),
822                 available_launch_types.end(),
823                 app_launch_type) == available_launch_types.end()) {
824     error_ = keys::kLaunchTypeNotAvailableError;
825     return false;
826   }
827 
828   LaunchType launch_type = LAUNCH_TYPE_DEFAULT;
829   switch (app_launch_type) {
830     case management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB:
831       launch_type = LAUNCH_TYPE_PINNED;
832       break;
833     case management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB:
834       launch_type = LAUNCH_TYPE_REGULAR;
835       break;
836     case management::LAUNCH_TYPE_OPEN_FULL_SCREEN:
837       launch_type = LAUNCH_TYPE_FULLSCREEN;
838       break;
839     case management::LAUNCH_TYPE_OPEN_AS_WINDOW:
840       launch_type = LAUNCH_TYPE_WINDOW;
841       break;
842     case management::LAUNCH_TYPE_NONE:
843       NOTREACHED();
844   }
845 
846   SetLaunchType(service(), params->id, launch_type);
847 
848   return true;
849 }
850 
ManagementGenerateAppForLinkFunction()851 ManagementGenerateAppForLinkFunction::ManagementGenerateAppForLinkFunction() {
852 }
853 
~ManagementGenerateAppForLinkFunction()854 ManagementGenerateAppForLinkFunction::~ManagementGenerateAppForLinkFunction() {
855 }
856 
FinishCreateBookmarkApp(const Extension * extension,const WebApplicationInfo & web_app_info)857 void ManagementGenerateAppForLinkFunction::FinishCreateBookmarkApp(
858     const Extension* extension,
859     const WebApplicationInfo& web_app_info) {
860   if (extension) {
861     scoped_ptr<management::ExtensionInfo> info =
862         CreateExtensionInfo(*extension, ExtensionSystem::Get(GetProfile()));
863     results_ = management::GenerateAppForLink::Results::Create(*info);
864 
865     SendResponse(true);
866     Release();
867   } else {
868     error_ = keys::kGenerateAppForLinkInstallError;
869     SendResponse(false);
870     Release();
871   }
872 }
873 
OnFaviconForApp(const favicon_base::FaviconImageResult & image_result)874 void ManagementGenerateAppForLinkFunction::OnFaviconForApp(
875     const favicon_base::FaviconImageResult& image_result) {
876   WebApplicationInfo web_app;
877   web_app.title = base::UTF8ToUTF16(title_);
878   web_app.app_url = launch_url_;
879 
880   if (!image_result.image.IsEmpty()) {
881     WebApplicationInfo::IconInfo icon;
882     icon.data = image_result.image.AsBitmap();
883     icon.width = icon.data.width();
884     icon.height = icon.data.height();
885     web_app.icons.push_back(icon);
886   }
887 
888   bookmark_app_helper_.reset(new BookmarkAppHelper(service(), web_app, NULL));
889   bookmark_app_helper_->Create(base::Bind(
890       &ManagementGenerateAppForLinkFunction::FinishCreateBookmarkApp, this));
891 }
892 
RunAsync()893 bool ManagementGenerateAppForLinkFunction::RunAsync() {
894   if (!user_gesture()) {
895     error_ = keys::kGestureNeededForGenerateAppForLinkError;
896     return false;
897   }
898 
899   scoped_ptr<management::GenerateAppForLink::Params> params(
900       management::GenerateAppForLink::Params::Create(*args_));
901   EXTENSION_FUNCTION_VALIDATE(params.get());
902 
903   GURL launch_url(params->url);
904   if (!launch_url.is_valid() || !launch_url.SchemeIsHTTPOrHTTPS()) {
905     error_ = ErrorUtils::FormatErrorMessage(keys::kInvalidURLError,
906                                             params->url);
907     return false;
908   }
909 
910   if (params->title.empty()) {
911     error_ = keys::kEmptyTitleError;
912     return false;
913   }
914 
915   FaviconService* favicon_service =
916       FaviconServiceFactory::GetForProfile(GetProfile(),
917                                            Profile::EXPLICIT_ACCESS);
918   DCHECK(favicon_service);
919 
920   title_ = params->title;
921   launch_url_ = launch_url;
922 
923   favicon_service->GetFaviconImageForPageURL(
924       FaviconService::FaviconForPageURLParams(
925           launch_url, favicon_base::FAVICON, gfx::kFaviconSize),
926       base::Bind(&ManagementGenerateAppForLinkFunction::OnFaviconForApp, this),
927       &cancelable_task_tracker_);
928 
929   // Matched with a Release() in OnExtensionLoaded().
930   AddRef();
931 
932   // Response is sent async in OnExtensionLoaded().
933   return true;
934 }
935 
ManagementEventRouter(content::BrowserContext * context)936 ManagementEventRouter::ManagementEventRouter(content::BrowserContext* context)
937     : browser_context_(context), extension_registry_observer_(this) {
938   extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
939 }
940 
~ManagementEventRouter()941 ManagementEventRouter::~ManagementEventRouter() {}
942 
OnExtensionLoaded(content::BrowserContext * browser_context,const Extension * extension)943 void ManagementEventRouter::OnExtensionLoaded(
944     content::BrowserContext* browser_context,
945     const Extension* extension) {
946   BroadcastEvent(extension, management::OnEnabled::kEventName);
947 }
948 
OnExtensionUnloaded(content::BrowserContext * browser_context,const Extension * extension,UnloadedExtensionInfo::Reason reason)949 void ManagementEventRouter::OnExtensionUnloaded(
950     content::BrowserContext* browser_context,
951     const Extension* extension,
952     UnloadedExtensionInfo::Reason reason) {
953   BroadcastEvent(extension, management::OnDisabled::kEventName);
954 }
955 
OnExtensionInstalled(content::BrowserContext * browser_context,const Extension * extension)956 void ManagementEventRouter::OnExtensionInstalled(
957     content::BrowserContext* browser_context,
958     const Extension* extension) {
959   BroadcastEvent(extension, management::OnInstalled::kEventName);
960 }
961 
OnExtensionUninstalled(content::BrowserContext * browser_context,const Extension * extension)962 void ManagementEventRouter::OnExtensionUninstalled(
963     content::BrowserContext* browser_context,
964     const Extension* extension) {
965   BroadcastEvent(extension, management::OnUninstalled::kEventName);
966 }
967 
BroadcastEvent(const Extension * extension,const char * event_name)968 void ManagementEventRouter::BroadcastEvent(const Extension* extension,
969                                            const char* event_name) {
970   if (ui_util::ShouldNotBeVisible(extension, browser_context_))
971     return;  // Don't dispatch events for built-in extenions.
972   scoped_ptr<base::ListValue> args(new base::ListValue());
973   if (event_name == management::OnUninstalled::kEventName) {
974     args->Append(new base::StringValue(extension->id()));
975   } else {
976     scoped_ptr<management::ExtensionInfo> info =
977         CreateExtensionInfo(*extension, ExtensionSystem::Get(browser_context_));
978     args->Append(info->ToValue().release());
979   }
980 
981   EventRouter::Get(browser_context_)
982       ->BroadcastEvent(scoped_ptr<Event>(new Event(event_name, args.Pass())));
983 }
984 
ManagementAPI(content::BrowserContext * context)985 ManagementAPI::ManagementAPI(content::BrowserContext* context)
986     : browser_context_(context) {
987   EventRouter* event_router = EventRouter::Get(browser_context_);
988   event_router->RegisterObserver(this, management::OnInstalled::kEventName);
989   event_router->RegisterObserver(this, management::OnUninstalled::kEventName);
990   event_router->RegisterObserver(this, management::OnEnabled::kEventName);
991   event_router->RegisterObserver(this, management::OnDisabled::kEventName);
992 }
993 
~ManagementAPI()994 ManagementAPI::~ManagementAPI() {
995 }
996 
Shutdown()997 void ManagementAPI::Shutdown() {
998   EventRouter::Get(browser_context_)->UnregisterObserver(this);
999 }
1000 
1001 static base::LazyInstance<BrowserContextKeyedAPIFactory<ManagementAPI> >
1002     g_factory = LAZY_INSTANCE_INITIALIZER;
1003 
1004 // static
1005 BrowserContextKeyedAPIFactory<ManagementAPI>*
GetFactoryInstance()1006 ManagementAPI::GetFactoryInstance() {
1007   return g_factory.Pointer();
1008 }
1009 
OnListenerAdded(const EventListenerInfo & details)1010 void ManagementAPI::OnListenerAdded(const EventListenerInfo& details) {
1011   management_event_router_.reset(new ManagementEventRouter(browser_context_));
1012   EventRouter::Get(browser_context_)->UnregisterObserver(this);
1013 }
1014 
1015 }  // namespace extensions
1016