Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(155)

Side by Side Diff: chrome/browser/extensions/extension_permissions_api.cc

Issue 7432006: Add an experimental permissions API for extensions. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: missed a scoped_refptr Created 9 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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_permissions_api.h"
6
7 #include "base/json/json_writer.h"
8 #include "base/stringprintf.h"
9 #include "base/values.h"
10 #include "chrome/browser/extensions/extension_event_router.h"
11 #include "chrome/browser/extensions/extension_permissions_api_constants.h"
12 #include "chrome/browser/extensions/extension_prefs.h"
13 #include "chrome/browser/extensions/extension_service.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/common/chrome_notification_types.h"
16 #include "chrome/common/extensions/extension.h"
17 #include "chrome/common/extensions/extension_messages.h"
18 #include "chrome/common/extensions/extension_permission_set.h"
19 #include "chrome/common/extensions/url_pattern_set.h"
20 #include "content/common/notification_service.h"
21 #include "googleurl/src/gurl.h"
22
23
24 namespace keys = extension_permissions_module_constants;
25
26 namespace {
27
28 enum AutoConfirmForTest {
29 DO_NOT_SKIP = 0,
30 PROCEED,
31 ABORT
32 };
33 AutoConfirmForTest auto_confirm_for_tests = DO_NOT_SKIP;
34
35 DictionaryValue* PackPermissionsToValue(const ExtensionPermissionSet* set) {
36 DictionaryValue* value = new DictionaryValue();
37
38 // Generate the list of API permissions.
39 ListValue* apis = new ListValue();
40 ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
41 for (ExtensionAPIPermissionSet::const_iterator i = set->apis().begin();
42 i != set->apis().end(); ++i)
43 apis->Append(Value::CreateStringValue(info->GetByID(*i)->name()));
44
45 // TODO(jstritar): Include hosts once the API supports them. At that point,
46 // we could also shared this code with ExtensionPermissionSet methods in
47 // ExtensionPrefs.
48
49 value->Set(keys::kApisKey, apis);
50 return value;
51 }
52
53 // Creates a new ExtensionPermissionSet from its |value| and passes ownership to
54 // the caller through |ptr|. Sets |bad_message| to true if the message is badly
55 // formed. Returns false if the method fails to unpack a permission set.
56 bool UnpackPermissionsFromValue(DictionaryValue* value,
57 scoped_ptr<ExtensionPermissionSet>* ptr,
58 bool* bad_message,
59 std::string* error) {
60 ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
61 ExtensionAPIPermissionSet apis;
62 if (value->HasKey(keys::kApisKey)) {
63 ListValue* api_list = NULL;
64 if (!value->GetList(keys::kApisKey, &api_list)) {
65 *bad_message = true;
66 return false;
67 }
68 for (size_t i = 0; i < api_list->GetSize(); ++i) {
69 std::string api_name;
70 if (!api_list->GetString(i, &api_name)) {
71 *bad_message = true;
72 return false;
73 }
74
75 ExtensionAPIPermission* permission = info->GetByName(api_name);
76 if (!permission) {
77 *error = base::StringPrintf(
78 keys::kUnknownPermissionError, api_name.c_str());
79 return false;
80 }
81 apis.insert(permission->id());
82 }
83 }
84
85 // Ignore host permissions for now.
86 URLPatternSet empty_set;
87 ptr->reset(new ExtensionPermissionSet(apis, empty_set, empty_set));
88 return true;
89 }
90
91 } // namespace
92
93 ExtensionPermissionsManager::ExtensionPermissionsManager(
94 ExtensionService* extension_service)
95 : extension_service_(extension_service) {
96 RegisterWhitelist();
97 }
98
99 ExtensionPermissionsManager::~ExtensionPermissionsManager() {
100 }
101
102 void ExtensionPermissionsManager::AddPermissions(
103 const Extension* extension, const ExtensionPermissionSet* permissions) {
104 scoped_refptr<const ExtensionPermissionSet> existing(
105 extension->GetActivePermissions());
106 scoped_refptr<ExtensionPermissionSet> total(
107 ExtensionPermissionSet::CreateUnion(existing, permissions));
108 scoped_ptr<ExtensionPermissionSet> added(
109 ExtensionPermissionSet::CreateDifference(total.get(), existing));
110
111 extension_service_->UpdateActivePermissions(extension, total.get());
112
113 // Update the granted permissions so we don't auto-disable the extension.
114 extension_service_->GrantPermissions(extension);
115
116 NotifyPermissionsUpdated(extension, total.get(), added.get(), ADDED);
117 }
118
119 void ExtensionPermissionsManager::RemovePermissions(
120 const Extension* extension, const ExtensionPermissionSet* permissions) {
121 scoped_refptr<const ExtensionPermissionSet> existing(
122 extension->GetActivePermissions());
123 scoped_refptr<ExtensionPermissionSet> total(
124 ExtensionPermissionSet::CreateDifference(existing, permissions));
125 scoped_ptr<ExtensionPermissionSet> removed(
126 ExtensionPermissionSet::CreateDifference(existing, total.get()));
127
128 // We update the active permissions, and not the granted permissions, because
129 // the extension, not the user, removed the permissions. This allows the
130 // extension to add them again without prompting the user.
131 extension_service_->UpdateActivePermissions(extension, total.get());
132
133 NotifyPermissionsUpdated(extension, total.get(), removed.get(), REMOVED);
134 }
135
136 void ExtensionPermissionsManager::DispatchEvent(
137 const std::string& extension_id,
138 const char* event_name,
139 const ExtensionPermissionSet* changed_permissions) {
140 Profile* profile = extension_service_->profile();
141 if (profile && profile->GetExtensionEventRouter()) {
142 ListValue value;
143 value.Append(PackPermissionsToValue(changed_permissions));
144 std::string json_value;
145 base::JSONWriter::Write(&value, false, &json_value);
146 profile->GetExtensionEventRouter()->DispatchEventToExtension(
147 extension_id, event_name, json_value, profile, GURL());
148 }
149 }
150
151 void ExtensionPermissionsManager::NotifyPermissionsUpdated(
152 const Extension* extension,
153 const ExtensionPermissionSet* active,
154 const ExtensionPermissionSet* changed,
155 EventType event_type) {
156 if (!changed || changed->IsEmpty())
157 return;
158
159 UpdatedExtensionPermissionsInfo::Reason reason;
160 const char* event_name = NULL;
161
162 if (event_type == REMOVED) {
163 reason = UpdatedExtensionPermissionsInfo::REMOVED;
164 event_name = keys::kOnRemoved;
165 } else {
166 CHECK_EQ(ADDED, event_type);
167 reason = UpdatedExtensionPermissionsInfo::ADDED;
168 event_name = keys::kOnAdded;
169 }
170
171 // Notify other APIs or interested parties.
172 UpdatedExtensionPermissionsInfo info = UpdatedExtensionPermissionsInfo(
173 extension, changed, reason);
174 NotificationService::current()->Notify(
175 chrome::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
176 Source<Profile>(extension_service_->profile()),
177 Details<UpdatedExtensionPermissionsInfo>(&info));
178
179 // Trigger the onAdded and onRemoved events in the extension.
180 DispatchEvent(extension->id(), event_name, changed);
181
182 // Send the new permissions to the renderers.
183 for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
184 !i.IsAtEnd(); i.Advance()) {
185 RenderProcessHost* host = i.GetCurrentValue();
186 if (extension_service_->profile()->IsSameProfile(host->profile()))
187 host->Send(new ExtensionMsg_UpdatePermissions(
188 extension->id(),
189 active->apis(),
190 active->explicit_hosts(),
191 active->scriptable_hosts()));
192 }
193 }
194
195 void ExtensionPermissionsManager::RegisterWhitelist() {
196 // TODO(jstritar): This could be a field on ExtensionAPIPermission.
197 ExtensionAPIPermissionSet api_whitelist;
198 api_whitelist.insert(ExtensionAPIPermission::kClipboardRead);
199 api_whitelist.insert(ExtensionAPIPermission::kClipboardWrite);
200 api_whitelist.insert(ExtensionAPIPermission::kNotification);
201 api_whitelist.insert(ExtensionAPIPermission::kBookmark);
202 api_whitelist.insert(ExtensionAPIPermission::kContextMenus);
203 api_whitelist.insert(ExtensionAPIPermission::kCookie);
204 api_whitelist.insert(ExtensionAPIPermission::kDebugger);
205 api_whitelist.insert(ExtensionAPIPermission::kHistory);
206 api_whitelist.insert(ExtensionAPIPermission::kIdle);
207 api_whitelist.insert(ExtensionAPIPermission::kTab);
208 api_whitelist.insert(ExtensionAPIPermission::kManagement);
209 api_whitelist.insert(ExtensionAPIPermission::kBackground);
210 whitelist_.reset(new ExtensionPermissionSet(
211 api_whitelist, URLPatternSet(), URLPatternSet()));
212 }
213
214 bool ContainsPermissionsFunction::RunImpl() {
215 DictionaryValue* args = NULL;
216 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
217 std::string error;
218 if (!args)
219 return false;
220
221 scoped_ptr<ExtensionPermissionSet> permissions;
222 if (!UnpackPermissionsFromValue(args, &permissions, &bad_message_, &error_))
223 return false;
224 CHECK(permissions.get());
225
226 result_.reset(Value::CreateBooleanValue(
227 GetExtension()->GetActivePermissions()->Contains(*permissions)));
228 return true;
229 }
230
231 bool GetAllPermissionsFunction::RunImpl() {
232 result_.reset(PackPermissionsToValue(
233 GetExtension()->GetActivePermissions()));
234 return true;
235 }
236
237 bool RemovePermissionsFunction::RunImpl() {
238 DictionaryValue* args = NULL;
239 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
240 if (!args)
241 return false;
242
243 scoped_ptr<ExtensionPermissionSet> permissions;
244 if (!UnpackPermissionsFromValue(args, &permissions, &bad_message_, &error_))
245 return false;
246 CHECK(permissions.get());
247
248 const Extension* extension = GetExtension();
249 ExtensionPermissionsManager* perms_manager =
250 profile()->GetExtensionService()->permissions_manager();
251 ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
252
253 // Make sure they're only trying to remove permissions supported by this API.
254 scoped_ptr<ExtensionPermissionSet> unsupported(
255 ExtensionPermissionSet::CreateDifference(
256 permissions.get(), &perms_manager->whitelist()));
257 if (unsupported->apis().size()) {
258 std::string api_name = info->GetByID(*unsupported->apis().begin())->name();
259 error_ = base::StringPrintf(keys::kNotWhitelistedError, api_name.c_str());
260 return false;
261 }
262
263 // Make sure we don't remove any required pemissions.
264 const ExtensionPermissionSet* required = extension->required_permission_set();
265 scoped_ptr<ExtensionPermissionSet> intersection(
266 ExtensionPermissionSet::CreateIntersection(permissions.get(), required));
267 if (!intersection->IsEmpty()) {
268 error_ = keys::kCantRemoveRequiredPermissionsError;
269 result_.reset(Value::CreateBooleanValue(false));
270 return false;
271 }
272
273 perms_manager->RemovePermissions(extension, permissions.get());
274 result_.reset(Value::CreateBooleanValue(true));
275 return true;
276 }
277
278 void RequestPermissionsFunction::SetAutoConfirmForTests(bool should_proceed) {
279 auto_confirm_for_tests = should_proceed ? PROCEED : ABORT;
280 }
281
282 bool RequestPermissionsFunction::RunImpl() {
283 DictionaryValue* args = NULL;
284 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
285 if (!args)
286 return false;
287
288 if (!UnpackPermissionsFromValue(
289 args, &requested_permissions_, &bad_message_, &error_))
290 return false;
291 CHECK(requested_permissions_.get());
292
293 extension_ = GetExtension();
294 ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
295 ExtensionPermissionsManager* perms_manager =
296 profile()->GetExtensionService()->permissions_manager();
297 ExtensionPrefs* prefs = profile()->GetExtensionService()->extension_prefs();
298
299 // Make sure only white listed permissions have been requested.
300 scoped_ptr<ExtensionPermissionSet> unsupported(
301 ExtensionPermissionSet::CreateDifference(
302 requested_permissions_.get(), &perms_manager->whitelist()));
303 if (unsupported->apis().size()) {
304 std::string api_name = info->GetByID(*unsupported->apis().begin())->name();
305 error_ = base::StringPrintf(keys::kNotWhitelistedError, api_name.c_str());
306 return false;
307 }
308
309 // The requested permissions must be defined as optional in the manifest.
310 if (!extension_->optional_permission_set()->Contains(
311 *requested_permissions_)) {
312 error_ = keys::kNotInOptionalPermissionsError;
313 result_.reset(Value::CreateBooleanValue(false));
314 return false;
315 }
316
317 // We don't need to prompt the user if the requested permissions are a subset
318 // of the granted permissions set.
319 const ExtensionPermissionSet* granted =
320 prefs->GetGrantedPermissions(extension_->id());
321 if (granted && granted->Contains(*requested_permissions_)) {
322 perms_manager->AddPermissions(extension_, requested_permissions_.get());
323 result_.reset(Value::CreateBooleanValue(true));
324 SendResponse(true);
325 return true;
326 }
327
328 // Filter out the granted permissions so we only prompt for new ones.
329 requested_permissions_.reset(ExtensionPermissionSet::CreateDifference(
330 requested_permissions_.get(), granted));
331
332 // Balanced with Release() in InstallUIProceed() and InstallUIAbort().
333 AddRef();
334
335 // We don't need to show the prompt if there are no new warnings, or if
336 // we're skipping the confirmation UI. All extension types but INTERNAL
337 // are allowed to silently increase their permission level.
338 if (auto_confirm_for_tests == PROCEED ||
339 requested_permissions_->GetWarningMessages().size() == 0) {
340 InstallUIProceed();
341 } else if (auto_confirm_for_tests == ABORT) {
342 // Pretend the user clicked cancel.
343 InstallUIAbort(true);
344 } else {
345 CHECK_EQ(DO_NOT_SKIP, auto_confirm_for_tests);
346 install_ui_.reset(new ExtensionInstallUI(profile()));
347 install_ui_->ConfirmPermissions(
348 this, extension_, requested_permissions_.get());
349 }
350
351 return true;
352 }
353
354 void RequestPermissionsFunction::InstallUIProceed() {
355 ExtensionPermissionsManager* perms_manager =
356 profile()->GetExtensionService()->permissions_manager();
357
358 install_ui_.reset();
359 result_.reset(Value::CreateBooleanValue(true));
360 perms_manager->AddPermissions(extension_, requested_permissions_.get());
361
362 SendResponse(true);
363
364 Release();
365 }
366
367 void RequestPermissionsFunction::InstallUIAbort(bool user_initiated) {
368 install_ui_.reset();
369 result_.reset(Value::CreateBooleanValue(false));
370 requested_permissions_.reset();
371
372 SendResponse(true);
373 Release();
374 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698