| Index: extensions/renderer/bindings/api_binding.cc
|
| diff --git a/extensions/renderer/bindings/api_binding.cc b/extensions/renderer/bindings/api_binding.cc
|
| index e69eccab892f4b353b29b5c5192d380ccfb0b138..8d08d0094910ce69305badba09637e22a2d8a522 100644
|
| --- a/extensions/renderer/bindings/api_binding.cc
|
| +++ b/extensions/renderer/bindings/api_binding.cc
|
| @@ -154,11 +154,15 @@ struct APIBinding::EventData {
|
| struct APIBinding::CustomPropertyData {
|
| CustomPropertyData(const std::string& type_name,
|
| const std::string& property_name,
|
| + const std::string& full_name,
|
| const base::ListValue* property_values,
|
| + const BindingAccessChecker* access_checker,
|
| const CreateCustomType& create_custom_type)
|
| : type_name(type_name),
|
| property_name(property_name),
|
| + full_name(full_name),
|
| property_values(property_values),
|
| + access_checker(access_checker),
|
| create_custom_type(create_custom_type) {}
|
|
|
| // The type of the property, e.g. 'storage.StorageArea'.
|
| @@ -166,9 +170,15 @@ struct APIBinding::CustomPropertyData {
|
| // The name of the property on the object, e.g. 'local' for
|
| // chrome.storage.local.
|
| std::string property_name;
|
| + // The full name of the property for looking up the feature, e.g.
|
| + // chrome.storage.local.
|
| + std::string full_name;
|
| +
|
| // Values curried into this particular type from the schema.
|
| const base::ListValue* property_values;
|
|
|
| + const BindingAccessChecker* const access_checker;
|
| +
|
| CreateCustomType create_custom_type;
|
| };
|
|
|
| @@ -401,7 +411,7 @@ void APIBinding::InitializeTemplate(v8::Isolate* isolate) {
|
|
|
| if (property_definitions_) {
|
| DecorateTemplateWithProperties(isolate, object_template,
|
| - *property_definitions_);
|
| + *property_definitions_, api_name_);
|
| }
|
|
|
| // Allow custom bindings a chance to tweak the template, such as to add
|
| @@ -414,7 +424,8 @@ void APIBinding::InitializeTemplate(v8::Isolate* isolate) {
|
| void APIBinding::DecorateTemplateWithProperties(
|
| v8::Isolate* isolate,
|
| v8::Local<v8::ObjectTemplate> object_template,
|
| - const base::DictionaryValue& properties) {
|
| + const base::DictionaryValue& properties,
|
| + const std::string& path) {
|
| static const char kValueKey[] = "value";
|
| for (base::DictionaryValue::Iterator iter(properties); !iter.IsAtEnd();
|
| iter.Advance()) {
|
| @@ -434,7 +445,9 @@ void APIBinding::DecorateTemplateWithProperties(
|
| const base::ListValue* property_values = nullptr;
|
| CHECK(dict->GetList("value", &property_values));
|
| auto property_data = base::MakeUnique<CustomPropertyData>(
|
| - ref, iter.key(), property_values, create_custom_type_);
|
| + ref, iter.key(),
|
| + base::StringPrintf("%s.%s", path.c_str(), iter.key().c_str()),
|
| + property_values, access_checker_, create_custom_type_);
|
| object_template->SetLazyDataProperty(
|
| v8_key, &APIBinding::GetCustomPropertyObject,
|
| v8::External::New(isolate, property_data.get()));
|
| @@ -467,8 +480,9 @@ void APIBinding::DecorateTemplateWithProperties(
|
| v8::ObjectTemplate::New(isolate);
|
| const base::DictionaryValue* property_dict = nullptr;
|
| CHECK(dict->GetDictionary("properties", &property_dict));
|
| - DecorateTemplateWithProperties(isolate, property_template,
|
| - *property_dict);
|
| + DecorateTemplateWithProperties(
|
| + isolate, property_template, *property_dict,
|
| + base::StringPrintf("%s.%s", path.c_str(), iter.key().c_str()));
|
| object_template->Set(v8_key, property_template);
|
| }
|
| }
|
| @@ -520,6 +534,20 @@ void APIBinding::GetCustomPropertyObject(
|
| auto* property_data =
|
| static_cast<CustomPropertyData*>(info.Data().As<v8::External>()->Value());
|
|
|
| + // If the property isn't available to this context, do nothing.
|
| + // TODO(devlin): This is a little suboptimal. Two notable downsides:
|
| + // - This only applies to custom properties. This means that if an API has a
|
| + // property with a raw value, it won't be restricted. Currently, this isn't
|
| + // a problem, but it could be in the future.
|
| + // - The key remains in the parent object (though the value will be
|
| + // undefined).
|
| + // Given the rarity of these restricted properties, this is okay, but it would
|
| + // be nice if it were better.
|
| + if (!property_data->access_checker->HasAccess(context,
|
| + property_data->full_name)) {
|
| + return;
|
| + }
|
| +
|
| v8::Local<v8::Object> property = property_data->create_custom_type.Run(
|
| isolate, property_data->type_name, property_data->property_name,
|
| property_data->property_values);
|
|
|