| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "extensions/renderer/bindings/api_binding.h" | 5 #include "extensions/renderer/bindings/api_binding.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 147 // The associated APIBinding. This raw pointer is safe because the | 147 // The associated APIBinding. This raw pointer is safe because the |
| 148 // EventData is only accessed from the callbacks associated with the | 148 // EventData is only accessed from the callbacks associated with the |
| 149 // APIBinding, and both the APIBinding and APIEventHandler are owned by the | 149 // APIBinding, and both the APIBinding and APIEventHandler are owned by the |
| 150 // same object (the APIBindingsSystem). | 150 // same object (the APIBindingsSystem). |
| 151 APIBinding* binding; | 151 APIBinding* binding; |
| 152 }; | 152 }; |
| 153 | 153 |
| 154 struct APIBinding::CustomPropertyData { | 154 struct APIBinding::CustomPropertyData { |
| 155 CustomPropertyData(const std::string& type_name, | 155 CustomPropertyData(const std::string& type_name, |
| 156 const std::string& property_name, | 156 const std::string& property_name, |
| 157 const std::string& full_name, |
| 157 const base::ListValue* property_values, | 158 const base::ListValue* property_values, |
| 159 const BindingAccessChecker* access_checker, |
| 158 const CreateCustomType& create_custom_type) | 160 const CreateCustomType& create_custom_type) |
| 159 : type_name(type_name), | 161 : type_name(type_name), |
| 160 property_name(property_name), | 162 property_name(property_name), |
| 163 full_name(full_name), |
| 161 property_values(property_values), | 164 property_values(property_values), |
| 165 access_checker(access_checker), |
| 162 create_custom_type(create_custom_type) {} | 166 create_custom_type(create_custom_type) {} |
| 163 | 167 |
| 164 // The type of the property, e.g. 'storage.StorageArea'. | 168 // The type of the property, e.g. 'storage.StorageArea'. |
| 165 std::string type_name; | 169 std::string type_name; |
| 166 // The name of the property on the object, e.g. 'local' for | 170 // The name of the property on the object, e.g. 'local' for |
| 167 // chrome.storage.local. | 171 // chrome.storage.local. |
| 168 std::string property_name; | 172 std::string property_name; |
| 173 // The full name of the property for looking up the feature, e.g. |
| 174 // chrome.storage.local. |
| 175 std::string full_name; |
| 176 |
| 169 // Values curried into this particular type from the schema. | 177 // Values curried into this particular type from the schema. |
| 170 const base::ListValue* property_values; | 178 const base::ListValue* property_values; |
| 171 | 179 |
| 180 const BindingAccessChecker* const access_checker; |
| 181 |
| 172 CreateCustomType create_custom_type; | 182 CreateCustomType create_custom_type; |
| 173 }; | 183 }; |
| 174 | 184 |
| 175 APIBinding::APIBinding(const std::string& api_name, | 185 APIBinding::APIBinding(const std::string& api_name, |
| 176 const base::ListValue* function_definitions, | 186 const base::ListValue* function_definitions, |
| 177 const base::ListValue* type_definitions, | 187 const base::ListValue* type_definitions, |
| 178 const base::ListValue* event_definitions, | 188 const base::ListValue* event_definitions, |
| 179 const base::DictionaryValue* property_definitions, | 189 const base::DictionaryValue* property_definitions, |
| 180 const CreateCustomType& create_custom_type, | 190 const CreateCustomType& create_custom_type, |
| 181 std::unique_ptr<APIBindingHooks> binding_hooks, | 191 std::unique_ptr<APIBindingHooks> binding_hooks, |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 v8::ObjectTemplate::New(isolate); | 404 v8::ObjectTemplate::New(isolate); |
| 395 for (const auto& enum_entry : entry.second) { | 405 for (const auto& enum_entry : entry.second) { |
| 396 enum_object->Set(gin::StringToSymbol(isolate, enum_entry.second), | 406 enum_object->Set(gin::StringToSymbol(isolate, enum_entry.second), |
| 397 gin::StringToSymbol(isolate, enum_entry.first)); | 407 gin::StringToSymbol(isolate, enum_entry.first)); |
| 398 } | 408 } |
| 399 object_template->Set(isolate, entry.first.c_str(), enum_object); | 409 object_template->Set(isolate, entry.first.c_str(), enum_object); |
| 400 } | 410 } |
| 401 | 411 |
| 402 if (property_definitions_) { | 412 if (property_definitions_) { |
| 403 DecorateTemplateWithProperties(isolate, object_template, | 413 DecorateTemplateWithProperties(isolate, object_template, |
| 404 *property_definitions_); | 414 *property_definitions_, api_name_); |
| 405 } | 415 } |
| 406 | 416 |
| 407 // Allow custom bindings a chance to tweak the template, such as to add | 417 // Allow custom bindings a chance to tweak the template, such as to add |
| 408 // additional properties or types. | 418 // additional properties or types. |
| 409 binding_hooks_->InitializeTemplate(isolate, object_template, *type_refs_); | 419 binding_hooks_->InitializeTemplate(isolate, object_template, *type_refs_); |
| 410 | 420 |
| 411 object_template_.Set(isolate, object_template); | 421 object_template_.Set(isolate, object_template); |
| 412 } | 422 } |
| 413 | 423 |
| 414 void APIBinding::DecorateTemplateWithProperties( | 424 void APIBinding::DecorateTemplateWithProperties( |
| 415 v8::Isolate* isolate, | 425 v8::Isolate* isolate, |
| 416 v8::Local<v8::ObjectTemplate> object_template, | 426 v8::Local<v8::ObjectTemplate> object_template, |
| 417 const base::DictionaryValue& properties) { | 427 const base::DictionaryValue& properties, |
| 428 const std::string& path) { |
| 418 static const char kValueKey[] = "value"; | 429 static const char kValueKey[] = "value"; |
| 419 for (base::DictionaryValue::Iterator iter(properties); !iter.IsAtEnd(); | 430 for (base::DictionaryValue::Iterator iter(properties); !iter.IsAtEnd(); |
| 420 iter.Advance()) { | 431 iter.Advance()) { |
| 421 const base::DictionaryValue* dict = nullptr; | 432 const base::DictionaryValue* dict = nullptr; |
| 422 CHECK(iter.value().GetAsDictionary(&dict)); | 433 CHECK(iter.value().GetAsDictionary(&dict)); |
| 423 bool optional = false; | 434 bool optional = false; |
| 424 if (dict->GetBoolean("optional", &optional)) { | 435 if (dict->GetBoolean("optional", &optional)) { |
| 425 // TODO(devlin): What does optional even mean here? It's only used, it | 436 // TODO(devlin): What does optional even mean here? It's only used, it |
| 426 // seems, for lastError and inIncognitoContext, which are both handled | 437 // seems, for lastError and inIncognitoContext, which are both handled |
| 427 // with custom bindings. Investigate, and remove. | 438 // with custom bindings. Investigate, and remove. |
| 428 continue; | 439 continue; |
| 429 } | 440 } |
| 430 | 441 |
| 431 v8::Local<v8::String> v8_key = gin::StringToSymbol(isolate, iter.key()); | 442 v8::Local<v8::String> v8_key = gin::StringToSymbol(isolate, iter.key()); |
| 432 std::string ref; | 443 std::string ref; |
| 433 if (dict->GetString("$ref", &ref)) { | 444 if (dict->GetString("$ref", &ref)) { |
| 434 const base::ListValue* property_values = nullptr; | 445 const base::ListValue* property_values = nullptr; |
| 435 CHECK(dict->GetList("value", &property_values)); | 446 CHECK(dict->GetList("value", &property_values)); |
| 436 auto property_data = base::MakeUnique<CustomPropertyData>( | 447 auto property_data = base::MakeUnique<CustomPropertyData>( |
| 437 ref, iter.key(), property_values, create_custom_type_); | 448 ref, iter.key(), |
| 449 base::StringPrintf("%s.%s", path.c_str(), iter.key().c_str()), |
| 450 property_values, access_checker_, create_custom_type_); |
| 438 object_template->SetLazyDataProperty( | 451 object_template->SetLazyDataProperty( |
| 439 v8_key, &APIBinding::GetCustomPropertyObject, | 452 v8_key, &APIBinding::GetCustomPropertyObject, |
| 440 v8::External::New(isolate, property_data.get())); | 453 v8::External::New(isolate, property_data.get())); |
| 441 custom_properties_.push_back(std::move(property_data)); | 454 custom_properties_.push_back(std::move(property_data)); |
| 442 continue; | 455 continue; |
| 443 } | 456 } |
| 444 | 457 |
| 445 std::string type; | 458 std::string type; |
| 446 CHECK(dict->GetString("type", &type)); | 459 CHECK(dict->GetString("type", &type)); |
| 447 if (type != "object" && !dict->HasKey(kValueKey)) { | 460 if (type != "object" && !dict->HasKey(kValueKey)) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 460 object_template->Set(v8_key, v8::Boolean::New(isolate, val)); | 473 object_template->Set(v8_key, v8::Boolean::New(isolate, val)); |
| 461 } else if (type == "string") { | 474 } else if (type == "string") { |
| 462 std::string val; | 475 std::string val; |
| 463 CHECK(dict->GetString(kValueKey, &val)) << iter.key(); | 476 CHECK(dict->GetString(kValueKey, &val)) << iter.key(); |
| 464 object_template->Set(v8_key, gin::StringToSymbol(isolate, val)); | 477 object_template->Set(v8_key, gin::StringToSymbol(isolate, val)); |
| 465 } else if (type == "object" || !ref.empty()) { | 478 } else if (type == "object" || !ref.empty()) { |
| 466 v8::Local<v8::ObjectTemplate> property_template = | 479 v8::Local<v8::ObjectTemplate> property_template = |
| 467 v8::ObjectTemplate::New(isolate); | 480 v8::ObjectTemplate::New(isolate); |
| 468 const base::DictionaryValue* property_dict = nullptr; | 481 const base::DictionaryValue* property_dict = nullptr; |
| 469 CHECK(dict->GetDictionary("properties", &property_dict)); | 482 CHECK(dict->GetDictionary("properties", &property_dict)); |
| 470 DecorateTemplateWithProperties(isolate, property_template, | 483 DecorateTemplateWithProperties( |
| 471 *property_dict); | 484 isolate, property_template, *property_dict, |
| 485 base::StringPrintf("%s.%s", path.c_str(), iter.key().c_str())); |
| 472 object_template->Set(v8_key, property_template); | 486 object_template->Set(v8_key, property_template); |
| 473 } | 487 } |
| 474 } | 488 } |
| 475 } | 489 } |
| 476 | 490 |
| 477 // static | 491 // static |
| 478 void APIBinding::GetEventObject( | 492 void APIBinding::GetEventObject( |
| 479 v8::Local<v8::Name> property, | 493 v8::Local<v8::Name> property, |
| 480 const v8::PropertyCallbackInfo<v8::Value>& info) { | 494 const v8::PropertyCallbackInfo<v8::Value>& info) { |
| 481 v8::Isolate* isolate = info.GetIsolate(); | 495 v8::Isolate* isolate = info.GetIsolate(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 513 v8::HandleScope handle_scope(isolate); | 527 v8::HandleScope handle_scope(isolate); |
| 514 v8::Local<v8::Context> context = info.Holder()->CreationContext(); | 528 v8::Local<v8::Context> context = info.Holder()->CreationContext(); |
| 515 if (!IsContextValid(context)) | 529 if (!IsContextValid(context)) |
| 516 return; | 530 return; |
| 517 | 531 |
| 518 v8::Context::Scope context_scope(context); | 532 v8::Context::Scope context_scope(context); |
| 519 CHECK(info.Data()->IsExternal()); | 533 CHECK(info.Data()->IsExternal()); |
| 520 auto* property_data = | 534 auto* property_data = |
| 521 static_cast<CustomPropertyData*>(info.Data().As<v8::External>()->Value()); | 535 static_cast<CustomPropertyData*>(info.Data().As<v8::External>()->Value()); |
| 522 | 536 |
| 537 // If the property isn't available to this context, do nothing. |
| 538 // TODO(devlin): This is a little suboptimal. Two notable downsides: |
| 539 // - This only applies to custom properties. This means that if an API has a |
| 540 // property with a raw value, it won't be restricted. Currently, this isn't |
| 541 // a problem, but it could be in the future. |
| 542 // - The key remains in the parent object (though the value will be |
| 543 // undefined). |
| 544 // Given the rarity of these restricted properties, this is okay, but it would |
| 545 // be nice if it were better. |
| 546 if (!property_data->access_checker->HasAccess(context, |
| 547 property_data->full_name)) { |
| 548 return; |
| 549 } |
| 550 |
| 523 v8::Local<v8::Object> property = property_data->create_custom_type.Run( | 551 v8::Local<v8::Object> property = property_data->create_custom_type.Run( |
| 524 isolate, property_data->type_name, property_data->property_name, | 552 isolate, property_data->type_name, property_data->property_name, |
| 525 property_data->property_values); | 553 property_data->property_values); |
| 526 if (property.IsEmpty()) | 554 if (property.IsEmpty()) |
| 527 return; | 555 return; |
| 528 | 556 |
| 529 info.GetReturnValue().Set(property); | 557 info.GetReturnValue().Set(property); |
| 530 } | 558 } |
| 531 | 559 |
| 532 void APIBinding::HandleCall(const std::string& name, | 560 void APIBinding::HandleCall(const std::string& name, |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 622 arguments->ThrowTypeError(api_errors::InvocationError( | 650 arguments->ThrowTypeError(api_errors::InvocationError( |
| 623 name, signature->GetExpectedSignature(), error)); | 651 name, signature->GetExpectedSignature(), error)); |
| 624 return; | 652 return; |
| 625 } | 653 } |
| 626 | 654 |
| 627 request_handler_->StartRequest(context, name, std::move(converted_arguments), | 655 request_handler_->StartRequest(context, name, std::move(converted_arguments), |
| 628 callback, custom_callback, thread); | 656 callback, custom_callback, thread); |
| 629 } | 657 } |
| 630 | 658 |
| 631 } // namespace extensions | 659 } // namespace extensions |
| OLD | NEW |