• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
service()55 ExtensionService* ExtensionManagementFunction::service() {
56   return profile()->GetExtensionService();
57 }
58 
CreateExtensionInfo(const Extension & extension,bool enabled)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 
AddExtensionInfo(ListValue * list,const ExtensionList & extensions,bool enabled)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 
RunImpl()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 
RunImpl()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 
RunImpl()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 
RunImpl()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 
RunImpl()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
GetInstance()251 ExtensionManagementEventRouter* ExtensionManagementEventRouter::GetInstance() {
252   return Singleton<ExtensionManagementEventRouter>::get();
253 }
254 
ExtensionManagementEventRouter()255 ExtensionManagementEventRouter::ExtensionManagementEventRouter() {}
256 
~ExtensionManagementEventRouter()257 ExtensionManagementEventRouter::~ExtensionManagementEventRouter() {}
258 
Init()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 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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