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