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

Side by Side Diff: extensions/renderer/declarative_content_hooks_delegate.cc

Issue 2853023002: [Extensions Bindings] Add native declarativeContent verification (Closed)
Patch Set: jbroman's Created 3 years, 7 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
OLDNEW
(Empty)
1 // Copyright 2017 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 "extensions/renderer/declarative_content_hooks_delegate.h"
6
7 #include "base/bind.h"
8 #include "base/memory/ptr_util.h"
9 #include "extensions/renderer/api_type_reference_map.h"
10 #include "extensions/renderer/argument_spec.h"
11 #include "gin/arguments.h"
12 #include "gin/converter.h"
13 #include "third_party/WebKit/public/platform/WebString.h"
14 #include "third_party/WebKit/public/web/WebSelector.h"
15
16 namespace extensions {
17
18 namespace {
19
20 void CallbackHelper(const v8::FunctionCallbackInfo<v8::Value>& info) {
21 CHECK(info.Data()->IsExternal());
22 v8::Local<v8::External> external = info.Data().As<v8::External>();
23 auto* callback =
24 static_cast<DeclarativeContentHooksDelegate::HandlerCallback*>(
25 external->Value());
26 callback->Run(info);
27 }
28
29 // Copies the 'own' properties from src -> dst.
30 bool V8Assign(v8::Local<v8::Context> context,
31 v8::Local<v8::Object> src,
32 v8::Local<v8::Object> dst) {
33 v8::Local<v8::Array> own_property_names;
34 if (!src->GetOwnPropertyNames(context).ToLocal(&own_property_names))
35 return false;
36
37 uint32_t length = own_property_names->Length();
38 for (uint32_t i = 0; i < length; ++i) {
39 v8::Local<v8::Value> key;
40 if (!own_property_names->Get(context, i).ToLocal(&key))
41 return false;
42 DCHECK(key->IsString() || key->IsUint32());
43
44 v8::Local<v8::Value> prop_value;
45 if (!src->Get(context, key).ToLocal(&prop_value))
46 return false;
47
48 v8::Maybe<bool> success =
49 key->IsString()
50 ? dst->CreateDataProperty(context, key.As<v8::String>(), prop_value)
51 : dst->CreateDataProperty(context, key.As<v8::Uint32>()->Value(),
52 prop_value);
53 if (!success.IsJust() || !success.FromJust())
54 return false;
55 }
56
57 return true;
58 }
59
60 // Canonicalizes any css selectors specified in a page state matcher, returning
61 // true on success.
62 bool CanonicalizeCssSelectors(v8::Local<v8::Context> context,
63 v8::Local<v8::Object> object,
64 std::string* error) {
65 v8::Isolate* isolate = context->GetIsolate();
66 v8::Local<v8::String> key = gin::StringToSymbol(isolate, "css");
lazyboy 2017/05/03 18:47:00 declarative_content_constants::kCss
Devlin 2017/05/03 22:55:02 Done. (Note: this meant moving the file, which wa
67 v8::Maybe<bool> has_css = object->HasOwnProperty(context, key);
68 // Note: don't bother populating |error| if script threw an exception.
69 if (!has_css.IsJust())
70 return false;
71
72 if (!has_css.FromJust())
73 return true;
74
75 v8::Local<v8::Value> css;
76 if (!object->Get(context, key).ToLocal(&css))
77 return false;
78
79 if (css->IsUndefined())
80 return true;
81
82 if (!css->IsArray())
83 return false;
84
85 v8::Local<v8::Array> css_array = css.As<v8::Array>();
86 uint32_t length = css_array->Length();
87 for (uint32_t i = 0; i < length; ++i) {
88 v8::Local<v8::Value> val;
89 if (!css_array->Get(context, i).ToLocal(&val) || !val->IsString())
90 return false;
91 v8::String::Utf8Value selector(val.As<v8::String>());
92 std::string parsed =
93 blink::CanonicalizeSelector(
lazyboy 2017/05/03 18:47:00 note: The blink::CanonicalizeSelector call from cs
Devlin 2017/05/03 22:55:02 Added a note.
94 blink::WebString::FromUTF8(*selector, selector.length()),
95 blink::kWebSelectorTypeCompound)
96 .Utf8();
97 if (parsed.empty()) {
98 *error =
99 "Invalid css selector: " + std::string(*selector, selector.length());
lazyboy 2017/05/03 18:47:00 nit: s/css/CSS since we're not talking about the "
Devlin 2017/05/03 22:55:01 Done.
100 return false;
101 }
102 v8::Maybe<bool> set_result =
103 css_array->Set(context, i, gin::StringToSymbol(isolate, parsed));
104 if (!set_result.IsJust() || !set_result.FromJust())
105 return false;
106 }
107
108 return true;
109 }
110
111 // Validates the source object against the expected spec, and copies over values
112 // to |this_object|. Returns true on success.
113 bool Validate(const ArgumentSpec* spec,
114 const APITypeReferenceMap& type_refs,
115 v8::Local<v8::Context> context,
116 v8::Local<v8::Object> this_object,
117 v8::Local<v8::Object> source_object,
118 const std::string& type_name,
119 std::string* error) {
120 if (!source_object.IsEmpty() &&
121 !V8Assign(context, source_object, this_object)) {
122 return false;
123 }
124
125 v8::Isolate* isolate = context->GetIsolate();
126 v8::Maybe<bool> set_result = this_object->CreateDataProperty(
127 context, gin::StringToSymbol(isolate, "instanceType"),
lazyboy 2017/05/03 18:47:01 declarative_content_constants::kInstanceType
Devlin 2017/05/03 22:55:01 Done.
128 gin::StringToSymbol(isolate, type_name));
129 if (!set_result.IsJust() || !set_result.FromJust()) {
130 return false;
131 }
132
133 if (!spec->ParseArgument(context, this_object, type_refs, nullptr, error)) {
134 return false;
135 }
136
137 if (type_name == "declarativeContent.PageStateMatcher" &&
lazyboy 2017/05/03 18:47:00 The full names match declarative_contents_constant
Devlin 2017/05/03 22:55:02 Done.
138 !CanonicalizeCssSelectors(context, this_object, error)) {
139 return false;
140 }
141 return true;
142 }
143
144 } // namespace
145
146 DeclarativeContentHooksDelegate::DeclarativeContentHooksDelegate() {}
147 DeclarativeContentHooksDelegate::~DeclarativeContentHooksDelegate() {}
148
149 void DeclarativeContentHooksDelegate::InitializeTemplate(
150 v8::Isolate* isolate,
151 v8::Local<v8::ObjectTemplate> object_template,
152 const APITypeReferenceMap& type_refs) {
153 // Add constructors for the API types.
154 // TODO(devlin): We'll need to extract out common logic here and share it with
155 // declarativeWebRequest.
156 struct {
157 const char* full_name;
158 const char* exposed_name;
159 } kTypes[] = {
160 {"declarativeContent.PageStateMatcher", "PageStateMatcher"},
161 {"declarativeContent.ShowPageAction", "ShowPageAction"},
162 {"declarativeContent.SetIcon", "SetIcon"},
163 {"declarativeContent.RequestContentScript", "RequestContentScript"},
164 };
165 for (const auto& type : kTypes) {
166 const ArgumentSpec* spec = type_refs.GetSpec(type.full_name);
167 DCHECK(spec);
168 // This object should outlive any calls to the function, so this
169 // base::Unretained and the callback itself are safe. Similarly, the same
170 // bindings system owns all these objects, so the spec and type refs should
171 // also be safe.
172 callbacks_.push_back(base::MakeUnique<HandlerCallback>(
lazyboy 2017/05/03 18:47:01 At size 4, the vector is going to most likely real
Devlin 2017/05/03 22:55:01 Done.
173 base::Bind(&DeclarativeContentHooksDelegate::HandleCall,
174 base::Unretained(this), spec, &type_refs, type.full_name)));
175 object_template->Set(
176 gin::StringToSymbol(isolate, type.exposed_name),
177 v8::FunctionTemplate::New(
178 isolate, &CallbackHelper,
179 v8::External::New(isolate, callbacks_.back().get())));
180 }
181 }
182
183 void DeclarativeContentHooksDelegate::HandleCall(
184 const ArgumentSpec* spec,
185 const APITypeReferenceMap* type_refs,
186 const std::string& type_name,
187 const v8::FunctionCallbackInfo<v8::Value>& info) {
188 gin::Arguments arguments(info);
189 v8::Isolate* isolate = arguments.isolate();
190 v8::HandleScope handle_scope(isolate);
191 v8::Local<v8::Context> context = isolate->GetCurrentContext();
192
193 // TODO(devlin): It would be pretty nice to be able to throw an error if
194 // Arguments::IsConstructCall() is false. That would ensure that the caller
195 // used `new declarativeContent.Foo()`, which is a) the documented approach
196 // and b) allows us (more) confidence that the |this| object we receive is
197 // an unmodified instance. But we don't know how many extensions enforcing
198 // that may break, and it's also incompatible with SetIcon().
199
200 v8::Local<v8::Object> this_object = info.This();
201 if (this_object.IsEmpty()) {
202 // Crazy script (e.g. declarativeContent.Foo.apply(null, args);).
203 NOTREACHED();
204 return;
205 }
206
207 // TODO(devlin): Find a way to use APISignature here? It's a little awkward
208 // because of undocumented expected properties like instanceType and not
209 // requiring an argument at all. We may need a better way of expressing these
210 // in the JSON schema.
211 if (arguments.Length() > 1) {
212 arguments.ThrowTypeError("Invalid invocation.");
213 return;
214 }
215
216 v8::Local<v8::Object> properties;
217 if (arguments.Length() == 1 && !arguments.GetNext(&properties)) {
218 arguments.ThrowTypeError("Invalid invocation.");
219 return;
220 }
221
222 std::string error;
223 bool success = false;
224 {
225 v8::TryCatch try_catch(isolate);
226 success = Validate(spec, *type_refs, context, this_object, properties,
227 type_name, &error);
228 if (try_catch.HasCaught()) {
229 try_catch.ReThrow();
230 return;
231 }
232 }
233
234 if (!success)
235 arguments.ThrowTypeError("Invalid invocation: " + error);
236 }
237
238 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/renderer/declarative_content_hooks_delegate.h ('k') | extensions/renderer/native_extension_bindings_system.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698