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

Side by Side Diff: chrome/common/extensions/api/extension_api.cc

Issue 9460002: Convert app_bindings.js to the schema_generated_bindings.js infrastructure. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix koz bool thing Created 8 years, 9 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
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/common/extensions/api/extension_api.h" 5 #include "chrome/common/extensions/api/extension_api.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/json/json_reader.h" 11 #include "base/json/json_reader.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/string_split.h" 13 #include "base/string_split.h"
14 #include "base/string_util.h" 14 #include "base/string_util.h"
15 #include "base/values.h" 15 #include "base/values.h"
16 #include "chrome/common/extensions/extension.h" 16 #include "chrome/common/extensions/extension.h"
17 #include "chrome/common/extensions/extension_permission_set.h" 17 #include "chrome/common/extensions/extension_permission_set.h"
18 #include "googleurl/src/gurl.h"
18 #include "grit/common_resources.h" 19 #include "grit/common_resources.h"
19 #include "ui/base/resource/resource_bundle.h" 20 #include "ui/base/resource/resource_bundle.h"
20 21
21 namespace extensions { 22 namespace extensions {
22 23
23 namespace { 24 namespace {
24 25
25 // Adds any APIs listed in "dependencies" found in |schema| but not in
26 // |reference| to |out|.
27 void GetMissingDependencies(
28 const DictionaryValue& schema,
29 const ExtensionAPI::SchemaMap& reference,
30 std::set<std::string>* out) {
31 ListValue* dependencies = NULL;
32 if (!schema.GetList("dependencies", &dependencies))
33 return;
34 for (size_t i = 0; i < dependencies->GetSize(); ++i) {
35 std::string api_name;
36 if (dependencies->GetString(i, &api_name) && !reference.count(api_name))
37 out->insert(api_name);
38 }
39 }
40
41 // Returns whether the list at |name_space_node|.|child_kind| contains any 26 // Returns whether the list at |name_space_node|.|child_kind| contains any
42 // children with an { "unprivileged": true } property. 27 // children with an { "unprivileged": true } property.
43 bool HasUnprivilegedChild(const DictionaryValue* name_space_node, 28 bool HasUnprivilegedChild(const DictionaryValue* name_space_node,
44 const std::string& child_kind) { 29 const std::string& child_kind) {
45 ListValue* child_list = NULL; 30 ListValue* child_list = NULL;
46 name_space_node->GetList(child_kind, &child_list); 31 name_space_node->GetList(child_kind, &child_list);
47 if (!child_list) 32 if (!child_list)
48 return false; 33 return false;
49 34
50 for (size_t i = 0; i < child_list->GetSize(); ++i) { 35 for (size_t i = 0; i < child_list->GetSize(); ++i) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 loaded->Remove(loaded->GetSize() - 1, &value); 73 loaded->Remove(loaded->GetSize() - 1, &value);
89 CHECK(value->IsType(Value::TYPE_DICTIONARY)); 74 CHECK(value->IsType(Value::TYPE_DICTIONARY));
90 const DictionaryValue* schema = static_cast<const DictionaryValue*>(value); 75 const DictionaryValue* schema = static_cast<const DictionaryValue*>(value);
91 CHECK(schema->GetString("namespace", &schema_namespace)); 76 CHECK(schema->GetString("namespace", &schema_namespace));
92 schemas_[schema_namespace] = linked_ptr<const DictionaryValue>(schema); 77 schemas_[schema_namespace] = linked_ptr<const DictionaryValue>(schema);
93 } 78 }
94 } 79 }
95 80
96 ExtensionAPI::ExtensionAPI() { 81 ExtensionAPI::ExtensionAPI() {
97 static int kJsonApiResourceIds[] = { 82 static int kJsonApiResourceIds[] = {
83 IDR_EXTENSION_API_JSON_APP,
98 IDR_EXTENSION_API_JSON_BOOKMARKS, 84 IDR_EXTENSION_API_JSON_BOOKMARKS,
99 IDR_EXTENSION_API_JSON_BROWSERACTION, 85 IDR_EXTENSION_API_JSON_BROWSERACTION,
100 IDR_EXTENSION_API_JSON_BROWSING_DATA, 86 IDR_EXTENSION_API_JSON_BROWSING_DATA,
101 IDR_EXTENSION_API_JSON_CHROMEAUTHPRIVATE, 87 IDR_EXTENSION_API_JSON_CHROMEAUTHPRIVATE,
102 IDR_EXTENSION_API_JSON_CHROMEOSINFOPRIVATE, 88 IDR_EXTENSION_API_JSON_CHROMEOSINFOPRIVATE,
103 IDR_EXTENSION_API_JSON_CHROMEPRIVATE, 89 IDR_EXTENSION_API_JSON_CHROMEPRIVATE,
104 IDR_EXTENSION_API_JSON_CONTENTSETTINGS, 90 IDR_EXTENSION_API_JSON_CONTENTSETTINGS,
105 IDR_EXTENSION_API_JSON_CONTEXTMENUS, 91 IDR_EXTENSION_API_JSON_CONTEXTMENUS,
106 IDR_EXTENSION_API_JSON_COOKIES, 92 IDR_EXTENSION_API_JSON_COOKIES,
107 IDR_EXTENSION_API_JSON_DEBUGGER, 93 IDR_EXTENSION_API_JSON_DEBUGGER,
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 continue; 156 continue;
171 } 157 }
172 158
173 // Only need to look at functions/events; even though there are unprivileged 159 // Only need to look at functions/events; even though there are unprivileged
174 // properties (e.g. in extensions), access to those never reaches C++ land. 160 // properties (e.g. in extensions), access to those never reaches C++ land.
175 if (HasUnprivilegedChild(it->second.get(), "functions") || 161 if (HasUnprivilegedChild(it->second.get(), "functions") ||
176 HasUnprivilegedChild(it->second.get(), "events")) { 162 HasUnprivilegedChild(it->second.get(), "events")) {
177 partially_unprivileged_apis_.insert(it->first); 163 partially_unprivileged_apis_.insert(it->first);
178 } 164 }
179 } 165 }
166
167 // Populate |url_matching_apis_|.
168 for (SchemaMap::const_iterator it = schemas_.begin();
169 it != schemas_.end(); ++it) {
170 ListValue* matches = NULL;
171 {
172 Value* matches_value = NULL;
173 if (!it->second->Get("matches", &matches_value))
174 continue;
175 CHECK_EQ(Value::TYPE_LIST, matches_value->GetType());
176 matches = static_cast<ListValue*>(matches_value);
177 }
178 URLPatternSet pattern_set;
179 for (size_t i = 0; i < matches->GetSize(); ++i) {
180 std::string pattern;
181 CHECK(matches->GetString(i, &pattern));
182 pattern_set.AddPattern(
183 URLPattern(UserScript::kValidUserScriptSchemes, pattern));
184 }
185 url_matching_apis_[it->first] = pattern_set;
186 }
180 } 187 }
181 188
182 ExtensionAPI::~ExtensionAPI() { 189 ExtensionAPI::~ExtensionAPI() {
183 } 190 }
184 191
185 bool ExtensionAPI::IsPrivileged(const std::string& full_name) const { 192 bool ExtensionAPI::IsPrivileged(const std::string& full_name) const {
186 std::string api_name; 193 std::string api_name;
187 std::string child_name; 194 std::string child_name;
188 195
189 { 196 {
(...skipping 21 matching lines...) Expand all
211 218
212 if (partially_unprivileged_apis_.count(api_name)) { 219 if (partially_unprivileged_apis_.count(api_name)) {
213 const DictionaryValue* schema = GetSchema(api_name); 220 const DictionaryValue* schema = GetSchema(api_name);
214 return IsChildNamePrivileged(schema, "functions", child_name) && 221 return IsChildNamePrivileged(schema, "functions", child_name) &&
215 IsChildNamePrivileged(schema, "events", child_name); 222 IsChildNamePrivileged(schema, "events", child_name);
216 } 223 }
217 224
218 return true; 225 return true;
219 } 226 }
220 227
221 DictionaryValue* ExtensionAPI::FindListItem(
222 const base::ListValue* list,
223 const std::string& property_name,
224 const std::string& property_value) const {
225 for (size_t i = 0; i < list->GetSize(); ++i) {
226 DictionaryValue* item = NULL;
227 CHECK(list->GetDictionary(i, &item))
228 << property_value << "/" << property_name;
229 std::string value;
230 if (item->GetString(property_name, &value) && value == property_value)
231 return item;
232 }
233
234 return NULL;
235 }
236
237 bool ExtensionAPI::IsChildNamePrivileged(const DictionaryValue* name_space_node, 228 bool ExtensionAPI::IsChildNamePrivileged(const DictionaryValue* name_space_node,
238 const std::string& child_kind, 229 const std::string& child_kind,
239 const std::string& child_name) const { 230 const std::string& child_name) const {
240 ListValue* child_list = NULL; 231 ListValue* child_list = NULL;
241 name_space_node->GetList(child_kind, &child_list); 232 name_space_node->GetList(child_kind, &child_list);
242 if (!child_list) 233 if (!child_list)
243 return true; 234 return true;
244 235
245 bool unprivileged = false; 236 bool unprivileged = false;
246 DictionaryValue* child = FindListItem(child_list, "name", child_name); 237 DictionaryValue* child = FindListItem(child_list, "name", child_name);
247 if (!child || !child->GetBoolean("unprivileged", &unprivileged)) 238 if (!child || !child->GetBoolean("unprivileged", &unprivileged))
248 return true; 239 return true;
249 240
250 return !unprivileged; 241 return !unprivileged;
251 } 242 }
252 243
244 DictionaryValue* ExtensionAPI::FindListItem(
245 const base::ListValue* list,
Aaron Boodman 2012/03/06 01:17:21 Why move? Just makes things hard to review.
not at google - send to devlin 2012/03/06 03:53:00 Dunno. Moved back. Oh, because I have a thing abo
246 const std::string& property_name,
247 const std::string& property_value) const {
248 for (size_t i = 0; i < list->GetSize(); ++i) {
249 DictionaryValue* item = NULL;
250 CHECK(list->GetDictionary(i, &item))
251 << property_value << "/" << property_name;
252 std::string value;
253 if (item->GetString(property_name, &value) && value == property_value)
254 return item;
255 }
256
257 return NULL;
258 }
259
253 const base::DictionaryValue* ExtensionAPI::GetSchema( 260 const base::DictionaryValue* ExtensionAPI::GetSchema(
254 const std::string& api_name) const { 261 const std::string& api_name) const {
255 SchemaMap::const_iterator maybe_schema = schemas_.find(api_name); 262 SchemaMap::const_iterator maybe_schema = schemas_.find(api_name);
256 return maybe_schema != schemas_.end() ? maybe_schema->second.get() : NULL; 263 return maybe_schema != schemas_.end() ? maybe_schema->second.get() : NULL;
257 } 264 }
258 265
259 void ExtensionAPI::GetSchemasForExtension(const Extension& extension, 266 scoped_ptr<std::set<std::string> > ExtensionAPI::GetAPIsForContext(
260 GetSchemasFilter filter, 267 Feature::Context context,
261 SchemaMap* out) const { 268 const Extension* extension,
262 // Check both required_permissions and optional_permissions since we need 269 const GURL& url) const {
263 // to return all schemas that might be needed. 270 scoped_ptr<std::set<std::string> > result(new std::set<std::string>());
264 GetSchemasForPermissions(*extension.required_permission_set(), filter, out);
265 GetSchemasForPermissions(*extension.optional_permission_set(), filter, out);
266 271
267 // Note that dependency resolution might introduce APIs outside of the filter 272 switch (context) {
268 // (for example, "extensions" has unprivileged componenents but relies on 273 case Feature::UNSPECIFIED_CONTEXT:
269 // "tabs" which doesn't). It doesn't matter because schema_generated_bindings 274 break;
270 // does individual function/event based checking anyway, but it's a shame. 275
271 ResolveDependencies(out); 276 case Feature::PRIVILEGED_CONTEXT:
277 // Availability is determined by the permissions of the extension.
278 CHECK(extension);
279 InsertAllowedAPIs(extension, result.get());
280 ResolveDependencies(result.get());
281 break;
282
283 case Feature::UNPRIVILEGED_CONTEXT:
284 case Feature::CONTENT_SCRIPT_CONTEXT:
285 // Availability is determined by the permissions of the extension
286 // (but only those APIs that are unprivileged).
287 CHECK(extension);
288 InsertAllowedAPIs(extension, result.get());
289 // Resolving dependencies before removing unprivileged APIs means that
290 // some unprivilged APIs may have unrealised dependencies. Too bad!
291 ResolveDependencies(result.get());
292 RemovePrivilegedAPIs(result.get());
koz (OOO until 15th September) 2012/03/06 04:06:58 This logic is beautiful ;_;
not at google - send to devlin 2012/03/06 11:36:46 Cheers ;_;
293 break;
294
295 case Feature::WEB_PAGE_CONTEXT:
296 // Availablility is determined by the url.
297 CHECK(url.is_valid());
298 for (std::map<std::string, URLPatternSet>::const_iterator i =
koz (OOO until 15th September) 2012/03/06 04:06:58 tiny nit: I feel like this part should be lifted i
not at google - send to devlin 2012/03/06 11:36:46 Cool, looks better.
299 url_matching_apis_.begin(); i != url_matching_apis_.end(); ++i) {
300 if (i->second.MatchesURL(url))
301 result->insert(i->first);
302 }
303 break;
304 }
305
306 return result.Pass();
272 } 307 }
273 308
274 void ExtensionAPI::ResolveDependencies(SchemaMap* out) const { 309 void ExtensionAPI::InsertAllowedAPIs(
275 std::set<std::string> missing_dependencies; 310 const Extension* extension, std::set<std::string>* out) const {
276 for (SchemaMap::const_iterator i = out->begin(); i != out->end(); ++i) 311 for (SchemaMap::const_iterator i = schemas_.begin(); i != schemas_.end();
277 GetMissingDependencies(*i->second, *out, &missing_dependencies); 312 ++i) {
278 313 if (extension->required_permission_set()->HasAnyAccessToAPI(i->first) ||
279 while (missing_dependencies.size()) { 314 extension->optional_permission_set()->HasAnyAccessToAPI(i->first)) {
280 std::string api_name = *missing_dependencies.begin(); 315 out->insert(i->first);
281 missing_dependencies.erase(api_name); 316 }
282 linked_ptr<const DictionaryValue> schema = schemas_.find(api_name)->second;
283 (*out)[api_name] = schema;
284 GetMissingDependencies(*schema, *out, &missing_dependencies);
285 } 317 }
286 } 318 }
287 319
288 void ExtensionAPI::GetDefaultSchemas(GetSchemasFilter filter, 320 void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) const {
289 SchemaMap* out) const { 321 std::set<std::string> missing_dependencies;
290 scoped_refptr<ExtensionPermissionSet> default_permissions( 322 for (std::set<std::string>::iterator i = out->begin(); i != out->end(); ++i)
291 new ExtensionPermissionSet()); 323 GetMissingDependencies(*i, *out, &missing_dependencies);
292 GetSchemasForPermissions(*default_permissions, filter, out);
293 ResolveDependencies(out);
294 }
295 324
296 void ExtensionAPI::GetSchemasForPermissions( 325 while (missing_dependencies.size()) {
297 const ExtensionPermissionSet& permissions, 326 std::string next = *missing_dependencies.begin();
298 GetSchemasFilter filter, 327 missing_dependencies.erase(next);
299 SchemaMap* out) const { 328 out->insert(next);
300 for (SchemaMap::const_iterator it = schemas_.begin(); it != schemas_.end(); 329 GetMissingDependencies(next, *out, &missing_dependencies);
301 ++it) {
302 if (filter == ONLY_UNPRIVILEGED && IsWholeAPIPrivileged(it->first))
303 continue;
304 if (permissions.HasAnyAccessToAPI(it->first))
305 (*out)[it->first] = it->second;
306 } 330 }
307 } 331 }
308 332
309 bool ExtensionAPI::IsWholeAPIPrivileged(const std::string& api_name) const { 333 void ExtensionAPI::GetMissingDependencies(
310 return !completely_unprivileged_apis_.count(api_name) && 334 const std::string& api_name,
311 !partially_unprivileged_apis_.count(api_name); 335 const std::set<std::string>& reference,
336 std::set<std::string>* out) const {
337 const base::DictionaryValue* schema = GetSchema(api_name);
338 CHECK(schema) << "Schema for " << api_name << " not found";
339
340 ListValue* dependencies = NULL;
341 if (!schema->GetList("dependencies", &dependencies))
342 return;
343
344 for (size_t i = 0; i < dependencies->GetSize(); ++i) {
345 std::string api_name;
346 if (dependencies->GetString(i, &api_name) && !reference.count(api_name))
347 out->insert(api_name);
348 }
349 }
350
351 void ExtensionAPI::RemovePrivilegedAPIs(std::set<std::string>* apis) const {
352 std::set<std::string> privileged_apis;
353 for (std::set<std::string>::iterator i = apis->begin(); i != apis->end();
354 ++i) {
355 if (!completely_unprivileged_apis_.count(*i) &&
356 !partially_unprivileged_apis_.count(*i)) {
357 privileged_apis.insert(*i);
358 }
359 }
360 for (std::set<std::string>::iterator i = privileged_apis.begin();
361 i != privileged_apis.end(); ++i) {
362 apis->erase(*i);
363 }
312 } 364 }
313 365
314 } // namespace extensions 366 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698