| OLD | NEW |
| 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 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 30 using base::DictionaryValue; | 30 using base::DictionaryValue; |
| 31 using base::ListValue; | 31 using base::ListValue; |
| 32 using base::Value; | 32 using base::Value; |
| 33 | 33 |
| 34 namespace extensions { | 34 namespace extensions { |
| 35 | 35 |
| 36 using api::GeneratedSchemas; | 36 using api::GeneratedSchemas; |
| 37 | 37 |
| 38 namespace { | 38 namespace { |
| 39 | 39 |
| 40 const char kUnavailableMessage[] = "You do not have permission to access this " | |
| 41 "API. Ensure that the required permission " | |
| 42 "or manifest property is included in your " | |
| 43 "manifest.json."; | |
| 44 const char* kChildKinds[] = { | 40 const char* kChildKinds[] = { |
| 45 "functions", | 41 "functions", |
| 46 "events" | 42 "events" |
| 47 }; | 43 }; |
| 48 | 44 |
| 49 // Returns true if |dict| has an unprivileged "true" property. | |
| 50 bool IsUnprivileged(const DictionaryValue* dict) { | |
| 51 bool unprivileged = false; | |
| 52 return dict->GetBoolean("unprivileged", &unprivileged) && unprivileged; | |
| 53 } | |
| 54 | |
| 55 // Returns whether the list at |name_space_node|.|child_kind| contains any | |
| 56 // children with an { "unprivileged": true } property. | |
| 57 bool HasUnprivilegedChild(const DictionaryValue* name_space_node, | |
| 58 const std::string& child_kind) { | |
| 59 const ListValue* child_list = NULL; | |
| 60 const DictionaryValue* child_dict = NULL; | |
| 61 | |
| 62 if (name_space_node->GetList(child_kind, &child_list)) { | |
| 63 for (size_t i = 0; i < child_list->GetSize(); ++i) { | |
| 64 const DictionaryValue* item = NULL; | |
| 65 CHECK(child_list->GetDictionary(i, &item)); | |
| 66 if (IsUnprivileged(item)) | |
| 67 return true; | |
| 68 } | |
| 69 } else if (name_space_node->GetDictionary(child_kind, &child_dict)) { | |
| 70 for (DictionaryValue::Iterator it(*child_dict); !it.IsAtEnd(); | |
| 71 it.Advance()) { | |
| 72 const DictionaryValue* item = NULL; | |
| 73 CHECK(it.value().GetAsDictionary(&item)); | |
| 74 if (IsUnprivileged(item)) | |
| 75 return true; | |
| 76 } | |
| 77 } | |
| 78 | |
| 79 return false; | |
| 80 } | |
| 81 | |
| 82 base::StringPiece ReadFromResource(int resource_id) { | 45 base::StringPiece ReadFromResource(int resource_id) { |
| 83 return ResourceBundle::GetSharedInstance().GetRawDataResource( | 46 return ResourceBundle::GetSharedInstance().GetRawDataResource( |
| 84 resource_id); | 47 resource_id); |
| 85 } | 48 } |
| 86 | 49 |
| 87 scoped_ptr<ListValue> LoadSchemaList(const std::string& name, | 50 scoped_ptr<ListValue> LoadSchemaList(const std::string& name, |
| 88 const base::StringPiece& schema) { | 51 const base::StringPiece& schema) { |
| 89 std::string error_message; | 52 std::string error_message; |
| 90 scoped_ptr<Value> result( | 53 scoped_ptr<Value> result( |
| 91 base::JSONReader::ReadAndReturnError( | 54 base::JSONReader::ReadAndReturnError( |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 { | 208 { |
| 246 Value* value = NULL; | 209 Value* value = NULL; |
| 247 schema_list->Remove(schema_list->GetSize() - 1, &value); | 210 schema_list->Remove(schema_list->GetSize() - 1, &value); |
| 248 CHECK(value->IsType(Value::TYPE_DICTIONARY)); | 211 CHECK(value->IsType(Value::TYPE_DICTIONARY)); |
| 249 schema = static_cast<DictionaryValue*>(value); | 212 schema = static_cast<DictionaryValue*>(value); |
| 250 } | 213 } |
| 251 | 214 |
| 252 CHECK(schema->GetString("namespace", &schema_namespace)); | 215 CHECK(schema->GetString("namespace", &schema_namespace)); |
| 253 PrefixWithNamespace(schema_namespace, schema); | 216 PrefixWithNamespace(schema_namespace, schema); |
| 254 schemas_[schema_namespace] = make_linked_ptr(schema); | 217 schemas_[schema_namespace] = make_linked_ptr(schema); |
| 255 CHECK_EQ(1u, unloaded_schemas_.erase(schema_namespace)); | 218 if (!GeneratedSchemas::IsGenerated(schema_namespace)) |
| 256 | 219 CHECK_EQ(1u, unloaded_schemas_.erase(schema_namespace)); |
| 257 // Populate |{completely,partially}_unprivileged_apis_|. | |
| 258 | |
| 259 // For "partially", only need to look at functions/events; even though | |
| 260 // there are unprivileged properties (e.g. in extensions), access to those | |
| 261 // never reaches C++ land. | |
| 262 bool unprivileged = false; | |
| 263 if (schema->GetBoolean("unprivileged", &unprivileged) && unprivileged) { | |
| 264 completely_unprivileged_apis_.insert(schema_namespace); | |
| 265 } else if (HasUnprivilegedChild(schema, "functions") || | |
| 266 HasUnprivilegedChild(schema, "events") || | |
| 267 HasUnprivilegedChild(schema, "properties")) { | |
| 268 partially_unprivileged_apis_.insert(schema_namespace); | |
| 269 } | |
| 270 } | 220 } |
| 271 } | 221 } |
| 272 | 222 |
| 273 ExtensionAPI::ExtensionAPI() { | 223 ExtensionAPI::ExtensionAPI() : default_configuration_initialized_(false) { |
| 274 } | 224 } |
| 275 | 225 |
| 276 ExtensionAPI::~ExtensionAPI() { | 226 ExtensionAPI::~ExtensionAPI() { |
| 277 } | 227 } |
| 278 | 228 |
| 279 void ExtensionAPI::InitDefaultConfiguration() { | 229 void ExtensionAPI::InitDefaultConfiguration() { |
| 280 RegisterDependencyProvider( | 230 RegisterDependencyProvider( |
| 281 "api", BaseFeatureProvider::GetByName("api")); | 231 "api", BaseFeatureProvider::GetByName("api")); |
| 282 RegisterDependencyProvider( | 232 RegisterDependencyProvider( |
| 283 "manifest", BaseFeatureProvider::GetByName("manifest")); | 233 "manifest", BaseFeatureProvider::GetByName("manifest")); |
| 284 RegisterDependencyProvider( | 234 RegisterDependencyProvider( |
| 285 "permission", BaseFeatureProvider::GetByName("permission")); | 235 "permission", BaseFeatureProvider::GetByName("permission")); |
| 286 | 236 |
| 287 // Schemas to be loaded from resources. | 237 // Schemas to be loaded from resources. |
| 288 CHECK(unloaded_schemas_.empty()); | 238 CHECK(unloaded_schemas_.empty()); |
| 289 RegisterSchema("app", ReadFromResource( | 239 RegisterSchemaResource("app", IDR_EXTENSION_API_JSON_APP); |
| 290 IDR_EXTENSION_API_JSON_APP)); | 240 RegisterSchemaResource("browserAction", IDR_EXTENSION_API_JSON_BROWSERACTION); |
| 291 RegisterSchema("browserAction", ReadFromResource( | 241 RegisterSchemaResource("browsingData", IDR_EXTENSION_API_JSON_BROWSINGDATA); |
| 292 IDR_EXTENSION_API_JSON_BROWSERACTION)); | 242 RegisterSchemaResource("commands", IDR_EXTENSION_API_JSON_COMMANDS); |
| 293 RegisterSchema("browsingData", ReadFromResource( | 243 RegisterSchemaResource("declarativeContent", |
| 294 IDR_EXTENSION_API_JSON_BROWSINGDATA)); | 244 IDR_EXTENSION_API_JSON_DECLARATIVE_CONTENT); |
| 295 RegisterSchema("commands", ReadFromResource( | 245 RegisterSchemaResource("declarativeWebRequest", |
| 296 IDR_EXTENSION_API_JSON_COMMANDS)); | 246 IDR_EXTENSION_API_JSON_DECLARATIVE_WEBREQUEST); |
| 297 RegisterSchema("declarativeContent", ReadFromResource( | 247 RegisterSchemaResource("experimental.input.virtualKeyboard", |
| 298 IDR_EXTENSION_API_JSON_DECLARATIVE_CONTENT)); | 248 IDR_EXTENSION_API_JSON_EXPERIMENTAL_INPUT_VIRTUALKEYBOARD); |
| 299 RegisterSchema("declarativeWebRequest", ReadFromResource( | 249 RegisterSchemaResource("experimental.processes", |
| 300 IDR_EXTENSION_API_JSON_DECLARATIVE_WEBREQUEST)); | 250 IDR_EXTENSION_API_JSON_EXPERIMENTAL_PROCESSES); |
| 301 RegisterSchema("experimental.input.virtualKeyboard", ReadFromResource( | 251 RegisterSchemaResource("experimental.rlz", |
| 302 IDR_EXTENSION_API_JSON_EXPERIMENTAL_INPUT_VIRTUALKEYBOARD)); | 252 IDR_EXTENSION_API_JSON_EXPERIMENTAL_RLZ); |
| 303 RegisterSchema("experimental.processes", ReadFromResource( | 253 RegisterSchemaResource("runtime", IDR_EXTENSION_API_JSON_RUNTIME); |
| 304 IDR_EXTENSION_API_JSON_EXPERIMENTAL_PROCESSES)); | 254 RegisterSchemaResource("fileBrowserHandler", |
| 305 RegisterSchema("experimental.rlz", ReadFromResource( | 255 IDR_EXTENSION_API_JSON_FILEBROWSERHANDLER); |
| 306 IDR_EXTENSION_API_JSON_EXPERIMENTAL_RLZ)); | 256 RegisterSchemaResource("fileBrowserPrivate", |
| 307 RegisterSchema("runtime", ReadFromResource( | 257 IDR_EXTENSION_API_JSON_FILEBROWSERPRIVATE); |
| 308 IDR_EXTENSION_API_JSON_RUNTIME)); | 258 RegisterSchemaResource("input.ime", IDR_EXTENSION_API_JSON_INPUT_IME); |
| 309 RegisterSchema("fileBrowserHandler", ReadFromResource( | 259 RegisterSchemaResource("inputMethodPrivate", |
| 310 IDR_EXTENSION_API_JSON_FILEBROWSERHANDLER)); | 260 IDR_EXTENSION_API_JSON_INPUTMETHODPRIVATE); |
| 311 RegisterSchema("fileBrowserPrivate", ReadFromResource( | 261 RegisterSchemaResource("pageAction", IDR_EXTENSION_API_JSON_PAGEACTION); |
| 312 IDR_EXTENSION_API_JSON_FILEBROWSERPRIVATE)); | 262 RegisterSchemaResource("pageActions", IDR_EXTENSION_API_JSON_PAGEACTIONS); |
| 313 RegisterSchema("input.ime", ReadFromResource( | 263 RegisterSchemaResource("privacy", IDR_EXTENSION_API_JSON_PRIVACY); |
| 314 IDR_EXTENSION_API_JSON_INPUT_IME)); | 264 RegisterSchemaResource("proxy", IDR_EXTENSION_API_JSON_PROXY); |
| 315 RegisterSchema("inputMethodPrivate", ReadFromResource( | 265 RegisterSchemaResource("scriptBadge", IDR_EXTENSION_API_JSON_SCRIPTBADGE); |
| 316 IDR_EXTENSION_API_JSON_INPUTMETHODPRIVATE)); | 266 RegisterSchemaResource("streamsPrivate", |
| 317 RegisterSchema("pageAction", ReadFromResource( | 267 IDR_EXTENSION_API_JSON_STREAMSPRIVATE); |
| 318 IDR_EXTENSION_API_JSON_PAGEACTION)); | 268 RegisterSchemaResource("ttsEngine", IDR_EXTENSION_API_JSON_TTSENGINE); |
| 319 RegisterSchema("pageActions", ReadFromResource( | 269 RegisterSchemaResource("tts", IDR_EXTENSION_API_JSON_TTS); |
| 320 IDR_EXTENSION_API_JSON_PAGEACTIONS)); | 270 RegisterSchemaResource("types", IDR_EXTENSION_API_JSON_TYPES); |
| 321 RegisterSchema("privacy", ReadFromResource( | 271 RegisterSchemaResource("webRequestInternal", |
| 322 IDR_EXTENSION_API_JSON_PRIVACY)); | 272 IDR_EXTENSION_API_JSON_WEBREQUESTINTERNAL); |
| 323 RegisterSchema("proxy", ReadFromResource( | 273 RegisterSchemaResource("webstore", IDR_EXTENSION_API_JSON_WEBSTORE); |
| 324 IDR_EXTENSION_API_JSON_PROXY)); | 274 RegisterSchemaResource("webstorePrivate", |
| 325 RegisterSchema("scriptBadge", ReadFromResource( | 275 IDR_EXTENSION_API_JSON_WEBSTOREPRIVATE); |
| 326 IDR_EXTENSION_API_JSON_SCRIPTBADGE)); | 276 default_configuration_initialized_ = true; |
| 327 RegisterSchema("streamsPrivate", ReadFromResource( | |
| 328 IDR_EXTENSION_API_JSON_STREAMSPRIVATE)); | |
| 329 RegisterSchema("ttsEngine", ReadFromResource( | |
| 330 IDR_EXTENSION_API_JSON_TTSENGINE)); | |
| 331 RegisterSchema("tts", ReadFromResource( | |
| 332 IDR_EXTENSION_API_JSON_TTS)); | |
| 333 RegisterSchema("types", ReadFromResource( | |
| 334 IDR_EXTENSION_API_JSON_TYPES)); | |
| 335 RegisterSchema("webRequestInternal", ReadFromResource( | |
| 336 IDR_EXTENSION_API_JSON_WEBREQUESTINTERNAL)); | |
| 337 RegisterSchema("webstore", ReadFromResource( | |
| 338 IDR_EXTENSION_API_JSON_WEBSTORE)); | |
| 339 RegisterSchema("webstorePrivate", ReadFromResource( | |
| 340 IDR_EXTENSION_API_JSON_WEBSTOREPRIVATE)); | |
| 341 | |
| 342 // Schemas to be loaded via JSON generated from IDL files. | |
| 343 GeneratedSchemas::Get(&unloaded_schemas_); | |
| 344 } | 277 } |
| 345 | 278 |
| 346 void ExtensionAPI::RegisterSchema(const std::string& name, | 279 void ExtensionAPI::RegisterSchemaResource(const std::string& name, |
| 347 const base::StringPiece& source) { | 280 int resource_id) { |
| 348 unloaded_schemas_[name] = source; | 281 unloaded_schemas_[name] = resource_id; |
| 349 } | 282 } |
| 350 | 283 |
| 351 void ExtensionAPI::RegisterDependencyProvider(const std::string& name, | 284 void ExtensionAPI::RegisterDependencyProvider(const std::string& name, |
| 352 FeatureProvider* provider) { | 285 FeatureProvider* provider) { |
| 353 dependency_providers_[name] = provider; | 286 dependency_providers_[name] = provider; |
| 354 } | 287 } |
| 355 | 288 |
| 356 bool ExtensionAPI::IsAnyFeatureAvailableToContext(const std::string& api_name, | 289 bool ExtensionAPI::IsAnyFeatureAvailableToContext(const std::string& api_name, |
| 357 Feature::Context context, | 290 Feature::Context context, |
| 358 const GURL& url) { | 291 const GURL& url) { |
| 359 FeatureProviderMap::iterator provider = dependency_providers_.find("api"); | 292 FeatureProviderMap::iterator provider = dependency_providers_.find("api"); |
| 360 CHECK(provider != dependency_providers_.end()); | 293 CHECK(provider != dependency_providers_.end()); |
| 361 std::set<std::string> features = provider->second->GetAllFeatureNames(); | 294 const std::vector<std::string>& features = |
| 295 provider->second->GetAllFeatureNames(); |
| 362 | 296 |
| 363 // Check to see if there are any parts of this API that are allowed in this | 297 // Check to see if there are any parts of this API that are allowed in this |
| 364 // context. | 298 // context. |
| 365 for (std::set<std::string>::iterator i = features.begin(); | 299 for (std::vector<std::string>::const_iterator i = features.begin(); |
| 366 i != features.end(); ++i) { | 300 i != features.end(); ++i) { |
| 367 const std::string& feature_name = *i; | 301 const std::string& feature_name = *i; |
| 368 if (feature_name != api_name && feature_name.find(api_name + ".") == 0) { | 302 if (feature_name != api_name && feature_name.find(api_name + ".") == 0) { |
| 369 if (IsAvailable(feature_name, NULL, context, url).is_available()) | 303 if (IsAvailable(feature_name, NULL, context, url).is_available()) |
| 370 return true; | 304 return true; |
| 371 } | 305 } |
| 372 } | 306 } |
| 373 return IsAvailable(api_name, NULL, context, url).is_available(); | 307 return IsAvailable(api_name, NULL, context, url).is_available(); |
| 374 } | 308 } |
| 375 | 309 |
| 376 Feature::Availability ExtensionAPI::IsAvailable(const std::string& full_name, | 310 Feature::Availability ExtensionAPI::IsAvailable(const std::string& full_name, |
| 377 const Extension* extension, | 311 const Extension* extension, |
| 378 Feature::Context context, | 312 Feature::Context context, |
| 379 const GURL& url) { | 313 const GURL& url) { |
| 380 std::string feature_type; | 314 std::string feature_type; |
| 381 std::string feature_name; | 315 std::string feature_name; |
| 382 SplitDependencyName(full_name, &feature_type, &feature_name); | 316 SplitDependencyName(full_name, &feature_type, &feature_name); |
| 383 | 317 |
| 384 std::string child_name; | |
| 385 std::string api_name = GetAPINameFromFullName(feature_name, &child_name); | |
| 386 | |
| 387 Feature* feature = GetFeatureDependency(full_name); | 318 Feature* feature = GetFeatureDependency(full_name); |
| 388 | 319 CHECK(feature) << full_name; |
| 389 // Check APIs not using the feature system first. | |
| 390 if (!feature) { | |
| 391 return IsNonFeatureAPIAvailable(api_name, context, extension, url) | |
| 392 ? Feature::CreateAvailability(Feature::IS_AVAILABLE, | |
| 393 std::string()) | |
| 394 : Feature::CreateAvailability(Feature::INVALID_CONTEXT, | |
| 395 kUnavailableMessage); | |
| 396 } | |
| 397 | 320 |
| 398 Feature::Availability availability = | 321 Feature::Availability availability = |
| 399 feature->IsAvailableToContext(extension, context, url); | 322 feature->IsAvailableToContext(extension, context, url); |
| 400 if (!availability.is_available()) | 323 if (!availability.is_available()) |
| 401 return availability; | 324 return availability; |
| 402 | 325 |
| 403 for (std::set<std::string>::iterator iter = feature->dependencies().begin(); | 326 for (std::set<std::string>::iterator iter = feature->dependencies().begin(); |
| 404 iter != feature->dependencies().end(); ++iter) { | 327 iter != feature->dependencies().end(); ++iter) { |
| 405 Feature::Availability dependency_availability = | 328 Feature::Availability dependency_availability = |
| 406 IsAvailable(*iter, extension, context, url); | 329 IsAvailable(*iter, extension, context, url); |
| 407 if (!dependency_availability.is_available()) | 330 if (!dependency_availability.is_available()) |
| 408 return dependency_availability; | 331 return dependency_availability; |
| 409 } | 332 } |
| 410 | 333 |
| 411 return Feature::CreateAvailability(Feature::IS_AVAILABLE, std::string()); | 334 return Feature::CreateAvailability(Feature::IS_AVAILABLE, std::string()); |
| 412 } | 335 } |
| 413 | 336 |
| 414 bool ExtensionAPI::IsPrivileged(const std::string& full_name) { | 337 bool ExtensionAPI::IsPrivileged(const std::string& full_name) { |
| 415 std::string child_name; | |
| 416 std::string api_name = GetAPINameFromFullName(full_name, &child_name); | |
| 417 Feature* feature = GetFeatureDependency(full_name); | 338 Feature* feature = GetFeatureDependency(full_name); |
| 418 | 339 CHECK(feature); |
| 419 // First try to use the feature system. | 340 DCHECK(!feature->GetContexts()->empty()); |
| 420 if (feature) { | 341 // An API is 'privileged' if it can only be run in a blessed context. |
| 421 // An API is 'privileged' if it can only be run in a blessed context. | 342 return feature->GetContexts()->size() == |
| 422 return feature->GetContexts()->size() == | 343 feature->GetContexts()->count(Feature::BLESSED_EXTENSION_CONTEXT); |
| 423 feature->GetContexts()->count(Feature::BLESSED_EXTENSION_CONTEXT); | |
| 424 } | |
| 425 | |
| 426 // Get the schema now to populate |completely_unprivileged_apis_|. | |
| 427 const DictionaryValue* schema = GetSchema(api_name); | |
| 428 // If this API hasn't been converted yet, fall back to the old system. | |
| 429 if (completely_unprivileged_apis_.count(api_name)) | |
| 430 return false; | |
| 431 | |
| 432 if (partially_unprivileged_apis_.count(api_name)) | |
| 433 return IsChildNamePrivileged(schema, child_name); | |
| 434 | |
| 435 return true; | |
| 436 } | |
| 437 | |
| 438 bool ExtensionAPI::IsChildNamePrivileged(const DictionaryValue* name_space_node, | |
| 439 const std::string& child_name) { | |
| 440 bool unprivileged = false; | |
| 441 const DictionaryValue* child = GetSchemaChild(name_space_node, child_name); | |
| 442 if (!child || !child->GetBoolean("unprivileged", &unprivileged)) | |
| 443 return true; | |
| 444 | |
| 445 return !unprivileged; | |
| 446 } | 344 } |
| 447 | 345 |
| 448 const DictionaryValue* ExtensionAPI::GetSchema(const std::string& full_name) { | 346 const DictionaryValue* ExtensionAPI::GetSchema(const std::string& full_name) { |
| 449 std::string child_name; | 347 std::string child_name; |
| 450 std::string api_name = GetAPINameFromFullName(full_name, &child_name); | 348 std::string api_name = GetAPINameFromFullName(full_name, &child_name); |
| 451 | 349 |
| 452 const DictionaryValue* result = NULL; | 350 const DictionaryValue* result = NULL; |
| 453 SchemaMap::iterator maybe_schema = schemas_.find(api_name); | 351 SchemaMap::iterator maybe_schema = schemas_.find(api_name); |
| 454 if (maybe_schema != schemas_.end()) { | 352 if (maybe_schema != schemas_.end()) { |
| 455 result = maybe_schema->second.get(); | 353 result = maybe_schema->second.get(); |
| 456 } else { | 354 } else { |
| 457 // Might not have loaded yet; or might just not exist. | 355 // Might not have loaded yet; or might just not exist. |
| 458 std::map<std::string, base::StringPiece>::iterator maybe_schema_resource = | 356 UnloadedSchemaMap::iterator maybe_schema_resource = |
| 459 unloaded_schemas_.find(api_name); | 357 unloaded_schemas_.find(api_name); |
| 460 if (maybe_schema_resource == unloaded_schemas_.end()) | 358 if (maybe_schema_resource != unloaded_schemas_.end()) { |
| 359 LoadSchema(maybe_schema_resource->first, |
| 360 ReadFromResource(maybe_schema_resource->second)); |
| 361 } else if (default_configuration_initialized_ && |
| 362 GeneratedSchemas::IsGenerated(api_name)) { |
| 363 LoadSchema(api_name, GeneratedSchemas::Get(api_name)); |
| 364 } else { |
| 461 return NULL; | 365 return NULL; |
| 366 } |
| 462 | 367 |
| 463 LoadSchema(maybe_schema_resource->first, maybe_schema_resource->second); | |
| 464 maybe_schema = schemas_.find(api_name); | 368 maybe_schema = schemas_.find(api_name); |
| 465 CHECK(schemas_.end() != maybe_schema); | 369 CHECK(schemas_.end() != maybe_schema); |
| 466 result = maybe_schema->second.get(); | 370 result = maybe_schema->second.get(); |
| 467 } | 371 } |
| 468 | 372 |
| 469 if (!child_name.empty()) | 373 if (!child_name.empty()) |
| 470 result = GetSchemaChild(result, child_name); | 374 result = GetSchemaChild(result, child_name); |
| 471 | 375 |
| 472 return result; | 376 return result; |
| 473 } | 377 } |
| 474 | 378 |
| 475 namespace { | |
| 476 | |
| 477 const char* kDisallowedPlatformAppFeatures[] = { | |
| 478 // "app" refers to the the legacy app namespace for hosted apps. | |
| 479 "app", | |
| 480 "extension", | |
| 481 "tabs", | |
| 482 "windows" | |
| 483 }; | |
| 484 | |
| 485 bool IsFeatureAllowedForExtension(const std::string& feature, | |
| 486 const extensions::Extension& extension) { | |
| 487 if (extension.is_platform_app()) { | |
| 488 for (size_t i = 0; i < arraysize(kDisallowedPlatformAppFeatures); ++i) { | |
| 489 if (feature == kDisallowedPlatformAppFeatures[i]) | |
| 490 return false; | |
| 491 } | |
| 492 } | |
| 493 | |
| 494 return true; | |
| 495 } | |
| 496 | |
| 497 } // namespace | |
| 498 | |
| 499 bool ExtensionAPI::IsNonFeatureAPIAvailable(const std::string& name, | |
| 500 Feature::Context context, | |
| 501 const Extension* extension, | |
| 502 const GURL& url) { | |
| 503 // Make sure schema is loaded. | |
| 504 GetSchema(name); | |
| 505 switch (context) { | |
| 506 case Feature::UNSPECIFIED_CONTEXT: | |
| 507 break; | |
| 508 | |
| 509 case Feature::BLESSED_EXTENSION_CONTEXT: | |
| 510 if (extension) { | |
| 511 // Availability is determined by the permissions of the extension. | |
| 512 if (!IsAPIAllowed(name, extension)) | |
| 513 return false; | |
| 514 if (!IsFeatureAllowedForExtension(name, *extension)) | |
| 515 return false; | |
| 516 } | |
| 517 break; | |
| 518 | |
| 519 case Feature::UNBLESSED_EXTENSION_CONTEXT: | |
| 520 case Feature::CONTENT_SCRIPT_CONTEXT: | |
| 521 if (extension) { | |
| 522 // Same as BLESSED_EXTENSION_CONTEXT, but only those APIs that are | |
| 523 // unprivileged. | |
| 524 if (!IsAPIAllowed(name, extension)) | |
| 525 return false; | |
| 526 if (!IsPrivilegedAPI(name)) | |
| 527 return false; | |
| 528 } | |
| 529 break; | |
| 530 | |
| 531 case Feature::WEB_PAGE_CONTEXT: | |
| 532 return false; | |
| 533 } | |
| 534 | |
| 535 return true; | |
| 536 } | |
| 537 | |
| 538 std::set<std::string> ExtensionAPI::GetAllAPINames() { | |
| 539 std::set<std::string> result; | |
| 540 for (SchemaMap::iterator i = schemas_.begin(); i != schemas_.end(); ++i) | |
| 541 result.insert(i->first); | |
| 542 for (UnloadedSchemaMap::iterator i = unloaded_schemas_.begin(); | |
| 543 i != unloaded_schemas_.end(); ++i) { | |
| 544 result.insert(i->first); | |
| 545 } | |
| 546 return result; | |
| 547 } | |
| 548 | |
| 549 Feature* ExtensionAPI::GetFeatureDependency(const std::string& full_name) { | 379 Feature* ExtensionAPI::GetFeatureDependency(const std::string& full_name) { |
| 550 std::string feature_type; | 380 std::string feature_type; |
| 551 std::string feature_name; | 381 std::string feature_name; |
| 552 SplitDependencyName(full_name, &feature_type, &feature_name); | 382 SplitDependencyName(full_name, &feature_type, &feature_name); |
| 553 | 383 |
| 554 FeatureProviderMap::iterator provider = | 384 FeatureProviderMap::iterator provider = |
| 555 dependency_providers_.find(feature_type); | 385 dependency_providers_.find(feature_type); |
| 556 if (provider == dependency_providers_.end()) | 386 if (provider == dependency_providers_.end()) |
| 557 return NULL; | 387 return NULL; |
| 558 | 388 |
| 559 Feature* feature = provider->second->GetFeature(feature_name); | 389 Feature* feature = provider->second->GetFeature(feature_name); |
| 560 // Try getting the feature for the parent API, if this was a child. | 390 // Try getting the feature for the parent API, if this was a child. |
| 561 if (!feature) { | 391 if (!feature) { |
| 562 std::string child_name; | 392 std::string child_name; |
| 563 feature = provider->second->GetFeature( | 393 feature = provider->second->GetFeature( |
| 564 GetAPINameFromFullName(feature_name, &child_name)); | 394 GetAPINameFromFullName(feature_name, &child_name)); |
| 565 } | 395 } |
| 566 return feature; | 396 return feature; |
| 567 } | 397 } |
| 568 | 398 |
| 569 std::string ExtensionAPI::GetAPINameFromFullName(const std::string& full_name, | 399 std::string ExtensionAPI::GetAPINameFromFullName(const std::string& full_name, |
| 570 std::string* child_name) { | 400 std::string* child_name) { |
| 571 std::string api_name_candidate = full_name; | 401 std::string api_name_candidate = full_name; |
| 572 while (true) { | 402 while (true) { |
| 573 if (schemas_.find(api_name_candidate) != schemas_.end() || | 403 if (schemas_.find(api_name_candidate) != schemas_.end() || |
| 404 GeneratedSchemas::IsGenerated(api_name_candidate) || |
| 574 unloaded_schemas_.find(api_name_candidate) != unloaded_schemas_.end()) { | 405 unloaded_schemas_.find(api_name_candidate) != unloaded_schemas_.end()) { |
| 575 std::string result = api_name_candidate; | 406 std::string result = api_name_candidate; |
| 576 | 407 |
| 577 if (child_name) { | 408 if (child_name) { |
| 578 if (result.length() < full_name.length()) | 409 if (result.length() < full_name.length()) |
| 579 *child_name = full_name.substr(result.length() + 1); | 410 *child_name = full_name.substr(result.length() + 1); |
| 580 else | 411 else |
| 581 *child_name = ""; | 412 *child_name = ""; |
| 582 } | 413 } |
| 583 | 414 |
| 584 return result; | 415 return result; |
| 585 } | 416 } |
| 586 | 417 |
| 587 size_t last_dot_index = api_name_candidate.rfind('.'); | 418 size_t last_dot_index = api_name_candidate.rfind('.'); |
| 588 if (last_dot_index == std::string::npos) | 419 if (last_dot_index == std::string::npos) |
| 589 break; | 420 break; |
| 590 | 421 |
| 591 api_name_candidate = api_name_candidate.substr(0, last_dot_index); | 422 api_name_candidate = api_name_candidate.substr(0, last_dot_index); |
| 592 } | 423 } |
| 593 | 424 |
| 594 *child_name = ""; | 425 *child_name = ""; |
| 595 return std::string(); | 426 return std::string(); |
| 596 } | 427 } |
| 597 | 428 |
| 598 bool ExtensionAPI::IsAPIAllowed(const std::string& name, | |
| 599 const Extension* extension) { | |
| 600 return PermissionsData::GetRequiredPermissions(extension)-> | |
| 601 HasAnyAccessToAPI(name) || | |
| 602 PermissionsData::GetOptionalPermissions(extension)-> | |
| 603 HasAnyAccessToAPI(name); | |
| 604 } | |
| 605 | |
| 606 bool ExtensionAPI::IsPrivilegedAPI(const std::string& name) { | |
| 607 return completely_unprivileged_apis_.count(name) || | |
| 608 partially_unprivileged_apis_.count(name); | |
| 609 } | |
| 610 | |
| 611 } // namespace extensions | 429 } // namespace extensions |
| OLD | NEW |