Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2011 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/extension_management_api.h"
      6 
      7 #include <map>
      8 #include <string>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/json/json_writer.h"
     12 #include "base/metrics/histogram.h"
     13 #include "base/string_number_conversions.h"
     14 #include "base/string_util.h"
     15 #include "chrome/browser/extensions/extension_event_names.h"
     16 #include "chrome/browser/extensions/extension_event_router.h"
     17 #include "chrome/browser/extensions/extension_service.h"
     18 #include "chrome/browser/extensions/extension_updater.h"
     19 #include "chrome/browser/profiles/profile.h"
     20 #include "chrome/browser/ui/browser.h"
     21 #include "chrome/browser/ui/webui/extension_icon_source.h"
     22 #include "chrome/common/extensions/extension.h"
     23 #include "chrome/common/extensions/extension_constants.h"
     24 #include "chrome/common/extensions/extension_error_utils.h"
     25 #include "chrome/common/extensions/extension_icon_set.h"
     26 #include "chrome/common/extensions/url_pattern.h"
     27 #include "content/common/notification_service.h"
     28 #include "content/common/notification_type.h"
     29 
     30 using base::IntToString;
     31 namespace events = extension_event_names;
     32 
     33 namespace {
     34 
     35 const char kAppLaunchUrlKey[] = "appLaunchUrl";
     36 const char kDescriptionKey[] = "description";
     37 const char kEnabledKey[] = "enabled";
     38 const char kHomepageURLKey[] = "homepageUrl";
     39 const char kIconsKey[] = "icons";
     40 const char kIdKey[] = "id";
     41 const char kIsAppKey[] = "isApp";
     42 const char kNameKey[] = "name";
     43 const char kOptionsUrlKey[] = "optionsUrl";
     44 const char kPermissionsKey[] = "permissions";
     45 const char kMayDisableKey[] = "mayDisable";
     46 const char kSizeKey[] = "size";
     47 const char kUrlKey[] = "url";
     48 const char kVersionKey[] = "version";
     49 
     50 const char kNoExtensionError[] = "No extension with id *";
     51 const char kNotAnAppError[] = "Extension * is not an App";
     52 const char kUserCantDisableError[] = "Extension * can not be disabled by user";
     53 }
     54 
     55 ExtensionService* ExtensionManagementFunction::service() {
     56   return profile()->GetExtensionService();
     57 }
     58 
     59 static DictionaryValue* CreateExtensionInfo(const Extension& extension,
     60                                             bool enabled) {
     61   DictionaryValue* info = new DictionaryValue();
     62   info->SetString(kIdKey, extension.id());
     63   info->SetBoolean(kIsAppKey, extension.is_app());
     64   info->SetString(kNameKey, extension.name());
     65   info->SetBoolean(kEnabledKey, enabled);
     66   info->SetBoolean(kMayDisableKey,
     67                    Extension::UserMayDisable(extension.location()));
     68   info->SetString(kVersionKey, extension.VersionString());
     69   info->SetString(kDescriptionKey, extension.description());
     70   info->SetString(kOptionsUrlKey,
     71                     extension.options_url().possibly_invalid_spec());
     72   info->SetString(kHomepageURLKey,
     73                     extension.GetHomepageURL().possibly_invalid_spec());
     74   if (extension.is_app())
     75     info->SetString(kAppLaunchUrlKey,
     76                     extension.GetFullLaunchURL().possibly_invalid_spec());
     77 
     78   const ExtensionIconSet::IconMap& icons = extension.icons().map();
     79   if (!icons.empty()) {
     80     ListValue* icon_list = new ListValue();
     81     std::map<int, std::string>::const_iterator icon_iter;
     82     for (icon_iter = icons.begin(); icon_iter != icons.end(); ++icon_iter) {
     83       DictionaryValue* icon_info = new DictionaryValue();
     84       Extension::Icons size = static_cast<Extension::Icons>(icon_iter->first);
     85       GURL url = ExtensionIconSource::GetIconURL(
     86           &extension, size, ExtensionIconSet::MATCH_EXACTLY, false);
     87       icon_info->SetInteger(kSizeKey, icon_iter->first);
     88       icon_info->SetString(kUrlKey, url.spec());
     89       icon_list->Append(icon_info);
     90     }
     91     info->Set("icons", icon_list);
     92   }
     93 
     94   const std::set<std::string> perms = extension.api_permissions();
     95   ListValue* permission_list = new ListValue();
     96   if (!perms.empty()) {
     97     std::set<std::string>::const_iterator perms_iter;
     98     for (perms_iter = perms.begin(); perms_iter != perms.end(); ++perms_iter) {
     99       StringValue* permission_name = new StringValue(*perms_iter);
    100       permission_list->Append(permission_name);
    101     }
    102   }
    103   info->Set("permissions", permission_list);
    104 
    105   ListValue* host_permission_list = new ListValue();
    106   if (!extension.is_hosted_app()) {
    107     // Skip host permissions for hosted apps.
    108     const URLPatternList host_perms = extension.host_permissions();
    109     if (!host_perms.empty()) {
    110       std::vector<URLPattern>::const_iterator host_perms_iter;
    111       for (host_perms_iter = host_perms.begin();
    112            host_perms_iter != host_perms.end();
    113            ++host_perms_iter) {
    114         StringValue* name = new StringValue(host_perms_iter->GetAsString());
    115         host_permission_list->Append(name);
    116       }
    117     }
    118   }
    119   info->Set("hostPermissions", host_permission_list);
    120 
    121   return info;
    122 }
    123 
    124 static void AddExtensionInfo(ListValue* list,
    125                              const ExtensionList& extensions,
    126                              bool enabled) {
    127   for (ExtensionList::const_iterator i = extensions.begin();
    128        i != extensions.end(); ++i) {
    129     const Extension& extension = **i;
    130 
    131     if (extension.location() == Extension::COMPONENT)
    132       continue;  // Skip built-in extensions.
    133 
    134     list->Append(CreateExtensionInfo(extension, enabled));
    135   }
    136 }
    137 
    138 bool GetAllExtensionsFunction::RunImpl() {
    139   ListValue* result = new ListValue();
    140   result_.reset(result);
    141 
    142   AddExtensionInfo(result, *service()->extensions(), true);
    143   AddExtensionInfo(result, *service()->disabled_extensions(), false);
    144 
    145   return true;
    146 }
    147 
    148 bool GetExtensionByIdFunction::RunImpl() {
    149   std::string extension_id;
    150   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id));
    151   const Extension* extension = service()->GetExtensionById(extension_id, true);
    152   if (!extension) {
    153     error_ = ExtensionErrorUtils::FormatErrorMessage(kNoExtensionError,
    154                                                      extension_id);
    155     return false;
    156   }
    157   bool enabled = service()->extension_prefs()->
    158       GetExtensionState(extension_id) == Extension::ENABLED;
    159 
    160   DictionaryValue* result = CreateExtensionInfo(*extension, enabled);
    161   result_.reset(result);
    162 
    163   return true;
    164 }
    165 
    166 bool LaunchAppFunction::RunImpl() {
    167   std::string extension_id;
    168   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id));
    169   const Extension* extension = service()->GetExtensionById(extension_id, true);
    170   if (!extension) {
    171     error_ = ExtensionErrorUtils::FormatErrorMessage(kNoExtensionError,
    172                                                      extension_id);
    173     return false;
    174   }
    175   if (!extension->is_app()) {
    176     error_ = ExtensionErrorUtils::FormatErrorMessage(kNotAnAppError,
    177                                                      extension_id);
    178     return false;
    179   }
    180 
    181   // Look at prefs to find the right launch container.
    182   // |default_pref_value| is set to LAUNCH_REGULAR so that if
    183   // the user has not set a preference, we open the app in a tab.
    184   extension_misc::LaunchContainer launch_container =
    185       service()->extension_prefs()->GetLaunchContainer(
    186           extension, ExtensionPrefs::LAUNCH_DEFAULT);
    187   Browser::OpenApplication(profile(), extension, launch_container, NULL);
    188   UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram,
    189                             extension_misc::APP_LAUNCH_EXTENSION_API,
    190                             extension_misc::APP_LAUNCH_BUCKET_BOUNDARY);
    191 
    192   return true;
    193 }
    194 
    195 bool SetEnabledFunction::RunImpl() {
    196   std::string extension_id;
    197   bool enable;
    198   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id));
    199   EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &enable));
    200 
    201   if (!service()->GetExtensionById(extension_id, true)) {
    202     error_ = ExtensionErrorUtils::FormatErrorMessage(
    203         kNoExtensionError, extension_id);
    204     return false;
    205   }
    206 
    207   ExtensionPrefs* prefs = service()->extension_prefs();
    208   Extension::State state = prefs->GetExtensionState(extension_id);
    209 
    210   if (!Extension::UserMayDisable(
    211       prefs->GetInstalledExtensionInfo(extension_id)->extension_location)) {
    212     error_ = ExtensionErrorUtils::FormatErrorMessage(
    213         kUserCantDisableError, extension_id);
    214     return false;
    215   }
    216 
    217   if (state == Extension::DISABLED && enable) {
    218     service()->EnableExtension(extension_id);
    219   } else if (state == Extension::ENABLED && !enable) {
    220     service()->DisableExtension(extension_id);
    221   }
    222 
    223   return true;
    224 }
    225 
    226 bool UninstallFunction::RunImpl() {
    227   std::string extension_id;
    228   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id));
    229 
    230   if (!service()->GetExtensionById(extension_id, true)) {
    231     error_ = ExtensionErrorUtils::FormatErrorMessage(
    232         kNoExtensionError, extension_id);
    233     return false;
    234   }
    235 
    236   ExtensionPrefs* prefs = service()->extension_prefs();
    237 
    238   if (!Extension::UserMayDisable(
    239       prefs->GetInstalledExtensionInfo(extension_id)->extension_location)) {
    240     error_ = ExtensionErrorUtils::FormatErrorMessage(
    241         kUserCantDisableError, extension_id);
    242     return false;
    243   }
    244 
    245   service()->UninstallExtension(extension_id, false /* external_uninstall */,
    246                                 NULL);
    247   return true;
    248 }
    249 
    250 // static
    251 ExtensionManagementEventRouter* ExtensionManagementEventRouter::GetInstance() {
    252   return Singleton<ExtensionManagementEventRouter>::get();
    253 }
    254 
    255 ExtensionManagementEventRouter::ExtensionManagementEventRouter() {}
    256 
    257 ExtensionManagementEventRouter::~ExtensionManagementEventRouter() {}
    258 
    259 void ExtensionManagementEventRouter::Init() {
    260   NotificationType::Type types[] = {
    261     NotificationType::EXTENSION_INSTALLED,
    262     NotificationType::EXTENSION_UNINSTALLED,
    263     NotificationType::EXTENSION_LOADED,
    264     NotificationType::EXTENSION_UNLOADED
    265   };
    266 
    267   // Don't re-init (eg in the case of multiple profiles).
    268   if (registrar_.IsEmpty()) {
    269     for (size_t i = 0; i < arraysize(types); i++) {
    270       registrar_.Add(this,
    271                      types[i],
    272                      NotificationService::AllSources());
    273     }
    274   }
    275 }
    276 
    277 void ExtensionManagementEventRouter::Observe(
    278     NotificationType type,
    279     const NotificationSource& source,
    280     const NotificationDetails& details) {
    281   const char* event_name = NULL;
    282   switch (type.value) {
    283     case NotificationType::EXTENSION_INSTALLED:
    284       event_name = events::kOnExtensionInstalled;
    285       break;
    286     case NotificationType::EXTENSION_UNINSTALLED:
    287       event_name = events::kOnExtensionUninstalled;
    288       break;
    289     case NotificationType::EXTENSION_LOADED:
    290       event_name = events::kOnExtensionEnabled;
    291       break;
    292     case NotificationType::EXTENSION_UNLOADED:
    293       event_name = events::kOnExtensionDisabled;
    294       break;
    295     default:
    296       NOTREACHED();
    297       return;
    298   }
    299 
    300   Profile* profile = Source<Profile>(source).ptr();
    301   CHECK(profile);
    302 
    303   ListValue args;
    304   if (event_name == events::kOnExtensionUninstalled) {
    305     const std::string& extension_id =
    306         Details<UninstalledExtensionInfo>(details).ptr()->extension_id;
    307     args.Append(Value::CreateStringValue(extension_id));
    308   } else {
    309     const Extension* extension = NULL;
    310     if (event_name == events::kOnExtensionDisabled) {
    311       extension = Details<UnloadedExtensionInfo>(details)->extension;
    312     } else {
    313       extension = Details<const Extension>(details).ptr();
    314     }
    315     CHECK(extension);
    316     ExtensionService* service = profile->GetExtensionService();
    317     bool enabled = service->GetExtensionById(extension->id(), false) != NULL;
    318     args.Append(CreateExtensionInfo(*extension, enabled));
    319   }
    320 
    321   std::string args_json;
    322   base::JSONWriter::Write(&args, false /* pretty_print */, &args_json);
    323 
    324   profile->GetExtensionEventRouter()->DispatchEventToRenderers(
    325       event_name, args_json, NULL, GURL());
    326 }
    327