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

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: fix clang Created 9 years, 4 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_refptr<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 = 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_refptr<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_refptr<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_ = 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_refptr<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_refptr<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_refptr<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_refptr<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 // static
279 void RequestPermissionsFunction::SetAutoConfirmForTests(bool should_proceed) {
280 auto_confirm_for_tests = should_proceed ? PROCEED : ABORT;
281 }
282
283 RequestPermissionsFunction::RequestPermissionsFunction() {}
284 RequestPermissionsFunction::~RequestPermissionsFunction() {}
285
286 bool RequestPermissionsFunction::RunImpl() {
287 DictionaryValue* args = NULL;
288 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
289 if (!args)
290 return false;
291
292 if (!UnpackPermissionsFromValue(
293 args, &requested_permissions_, &bad_message_, &error_))
294 return false;
295 CHECK(requested_permissions_.get());
296
297 extension_ = GetExtension();
298 ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
299 ExtensionPermissionsManager* perms_manager =
300 profile()->GetExtensionService()->permissions_manager();
301 ExtensionPrefs* prefs = profile()->GetExtensionService()->extension_prefs();
302
303 // Make sure only white listed permissions have been requested.
304 scoped_refptr<ExtensionPermissionSet> unsupported(
305 ExtensionPermissionSet::CreateDifference(
306 requested_permissions_.get(), &perms_manager->whitelist()));
307 if (unsupported->apis().size()) {
308 std::string api_name = info->GetByID(*unsupported->apis().begin())->name();
309 error_ = base::StringPrintf(keys::kNotWhitelistedError, api_name.c_str());
310 return false;
311 }
312
313 // The requested permissions must be defined as optional in the manifest.
314 if (!extension_->optional_permission_set()->Contains(
315 *requested_permissions_)) {
316 error_ = keys::kNotInOptionalPermissionsError;
317 result_.reset(Value::CreateBooleanValue(false));
318 return false;
319 }
320
321 // We don't need to prompt the user if the requested permissions are a subset
322 // of the granted permissions set.
323 const ExtensionPermissionSet* granted =
324 prefs->GetGrantedPermissions(extension_->id());
325 if (granted && granted->Contains(*requested_permissions_)) {
326 perms_manager->AddPermissions(extension_, requested_permissions_.get());
327 result_.reset(Value::CreateBooleanValue(true));
328 SendResponse(true);
329 return true;
330 }
331
332 // Filter out the granted permissions so we only prompt for new ones.
333 requested_permissions_ = ExtensionPermissionSet::CreateDifference(
334 requested_permissions_.get(), granted);
335
336 // Balanced with Release() in InstallUIProceed() and InstallUIAbort().
337 AddRef();
338
339 // We don't need to show the prompt if there are no new warnings, or if
340 // we're skipping the confirmation UI. All extension types but INTERNAL
341 // are allowed to silently increase their permission level.
342 if (auto_confirm_for_tests == PROCEED ||
343 requested_permissions_->GetWarningMessages().size() == 0) {
344 InstallUIProceed();
345 } else if (auto_confirm_for_tests == ABORT) {
346 // Pretend the user clicked cancel.
347 InstallUIAbort(true);
348 } else {
349 CHECK_EQ(DO_NOT_SKIP, auto_confirm_for_tests);
350 install_ui_.reset(new ExtensionInstallUI(profile()));
351 install_ui_->ConfirmPermissions(
352 this, extension_, requested_permissions_.get());
353 }
354
355 return true;
356 }
357
358 void RequestPermissionsFunction::InstallUIProceed() {
359 ExtensionPermissionsManager* perms_manager =
360 profile()->GetExtensionService()->permissions_manager();
361
362 install_ui_.reset();
363 result_.reset(Value::CreateBooleanValue(true));
364 perms_manager->AddPermissions(extension_, requested_permissions_.get());
365
366 SendResponse(true);
367
368 Release();
369 }
370
371 void RequestPermissionsFunction::InstallUIAbort(bool user_initiated) {
372 install_ui_.reset();
373 result_.reset(Value::CreateBooleanValue(false));
374 requested_permissions_ = NULL;
375
376 SendResponse(true);
377 Release();
378 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension_permissions_api.h ('k') | chrome/browser/extensions/extension_permissions_api_constants.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698