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