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

Side by Side Diff: chrome/renderer/resources/extensions/binding.js

Issue 14494013: Allow API functions and events to have entries in _api_features.json (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix bug in searching for unprivileged Created 7 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 | 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 require('json_schema'); 5 require('json_schema');
6 require('event_bindings'); 6 require('event_bindings');
7 var chrome = requireNative('chrome').GetChrome(); 7 var chrome = requireNative('chrome').GetChrome();
8 var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); 8 var chromeHidden = requireNative('chrome_hidden').GetChromeHidden();
9 var forEach = require('utils').forEach; 9 var forEach = require('utils').forEach;
10 var GetAvailability = requireNative('v8_context').GetAvailability; 10 var GetAvailability = requireNative('v8_context').GetAvailability;
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
196 compiledApi: api 196 compiledApi: api
197 }, extensionId, contextType); 197 }, extensionId, contextType);
198 }, this); 198 }, this);
199 }, 199 },
200 200
201 // Generates the bindings from |this.schema_| and integrates any custom 201 // Generates the bindings from |this.schema_| and integrates any custom
202 // bindings that might be present. 202 // bindings that might be present.
203 generate: function() { 203 generate: function() {
204 var schema = this.schema_; 204 var schema = this.schema_;
205 205
206 function shouldCheckUnprivileged() {
207 var shouldCheck = 'unprivileged' in schema;
208 if (shouldCheck)
209 return shouldCheck;
210
211 ['functions', 'events'].forEach(function(type) {
212 if (schema.hasOwnProperty(type)) {
213 schema[type].forEach(function(node) {
214 if ('unprivileged' in node)
215 shouldCheck = true;
216 });
217 }
218 });
219 if (shouldCheck)
220 return shouldCheck;
221
222 for (var property in schema.properties) {
223 if (schema.hasOwnProperty(property) &&
224 'unprivileged' in schema.properties[property]) {
225 shouldCheck = true;
226 break;
227 }
228 }
229 return shouldCheck;
230 }
231 var checkUnprivileged = shouldCheckUnprivileged();
232
206 // TODO(kalman/cduvall): Make GetAvailability handle this, then delete the 233 // TODO(kalman/cduvall): Make GetAvailability handle this, then delete the
207 // supporting code. 234 // supporting code.
208 if (!isSchemaNodeSupported(schema, platform, manifestVersion)) { 235 if (!isSchemaNodeSupported(schema, platform, manifestVersion)) {
209 console.error('chrome.' + schema.namespace + ' is not supported on ' + 236 console.error('chrome.' + schema.namespace + ' is not supported on ' +
210 'this platform or manifest version'); 237 'this platform or manifest version');
211 return undefined; 238 return undefined;
212 } 239 }
213 240
214 var availability = GetAvailability(schema.namespace);
215 if (!availability.is_available) {
216 console.error('chrome.' + schema.namespace + ' is not available: ' +
217 availability.message);
218 return undefined;
219 }
220
221 // See comment on internalAPIs at the top.
222 var mod = {}; 241 var mod = {};
223 242
224 var namespaces = schema.namespace.split('.'); 243 var namespaces = schema.namespace.split('.');
225 for (var index = 0, name; name = namespaces[index]; index++) { 244 for (var index = 0, name; name = namespaces[index]; index++) {
226 mod[name] = mod[name] || {}; 245 mod[name] = mod[name] || {};
227 mod = mod[name]; 246 mod = mod[name];
228 } 247 }
229 248
230 // Add types to global schemaValidator, the types we depend on from other 249 // Add types to global schemaValidator, the types we depend on from other
231 // namespaces will be added as needed. 250 // namespaces will be added as needed.
232 if (schema.types) { 251 if (schema.types) {
233 forEach(schema.types, function(i, t) { 252 forEach(schema.types, function(i, t) {
234 if (!isSchemaNodeSupported(t, platform, manifestVersion)) 253 if (!isSchemaNodeSupported(t, platform, manifestVersion))
235 return; 254 return;
236 255
237 schemaUtils.schemaValidator.addTypes(t); 256 schemaUtils.schemaValidator.addTypes(t);
238 }, this); 257 }, this);
239 } 258 }
240 259
260 // TODO(cduvall): Take out when all APIs have been converted to features.
241 // Returns whether access to the content of a schema should be denied, 261 // Returns whether access to the content of a schema should be denied,
242 // based on the presence of "unprivileged" and whether this is an 262 // based on the presence of "unprivileged" and whether this is an
243 // extension process (versus e.g. a content script). 263 // extension process (versus e.g. a content script).
244 function isSchemaAccessAllowed(itemSchema) { 264 function isSchemaAccessAllowed(itemSchema) {
245 return (contextType == 'BLESSED_EXTENSION') || 265 return (contextType == 'BLESSED_EXTENSION') ||
246 schema.unprivileged || 266 schema.unprivileged ||
247 itemSchema.unprivileged; 267 itemSchema.unprivileged;
248 }; 268 };
249 269
250 // Adds a getter that throws an access denied error to object |mod|
251 // for property |name|.
252 function addUnprivilegedAccessGetter(mod, name) {
253 mod.__defineGetter__(name, function() {
254 throw new Error(
255 '"' + name + '" can only be used in extension processes. See ' +
256 'the content scripts documentation for more details.');
257 });
258 }
259
260 // Setup Functions. 270 // Setup Functions.
261 if (schema.functions) { 271 if (schema.functions) {
262 forEach(schema.functions, function(i, functionDef) { 272 forEach(schema.functions, function(i, functionDef) {
263 if (functionDef.name in mod) { 273 if (functionDef.name in mod) {
264 throw new Error('Function ' + functionDef.name + 274 throw new Error('Function ' + functionDef.name +
265 ' already defined in ' + schema.namespace); 275 ' already defined in ' + schema.namespace);
266 } 276 }
267 277
268 if (!isSchemaNodeSupported(functionDef, platform, manifestVersion)) { 278 if (!isSchemaNodeSupported(functionDef, platform, manifestVersion)) {
269 this.apiFunctions_.registerUnavailable(functionDef.name); 279 this.apiFunctions_.registerUnavailable(functionDef.name);
270 return; 280 return;
271 } 281 }
272 if (!isSchemaAccessAllowed(functionDef)) {
273 this.apiFunctions_.registerUnavailable(functionDef.name);
274 addUnprivilegedAccessGetter(mod, functionDef.name);
275 return;
276 }
277 282
278 var apiFunction = {}; 283 var apiFunction = {};
279 apiFunction.definition = functionDef; 284 apiFunction.definition = functionDef;
280 apiFunction.name = schema.namespace + '.' + functionDef.name; 285 apiFunction.name = schema.namespace + '.' + functionDef.name;
281 286
287 if (!GetAvailability(apiFunction.name).is_available ||
288 (checkUnprivileged && !isSchemaAccessAllowed(functionDef))) {
289 this.apiFunctions_.registerUnavailable(functionDef.name);
290 return;
291 }
292
282 // TODO(aa): It would be best to run this in a unit test, but in order 293 // TODO(aa): It would be best to run this in a unit test, but in order
283 // to do that we would need to better factor this code so that it 294 // to do that we would need to better factor this code so that it
284 // doesn't depend on so much v8::Extension machinery. 295 // doesn't depend on so much v8::Extension machinery.
285 if (chromeHidden.validateAPI && 296 if (chromeHidden.validateAPI &&
286 schemaUtils.isFunctionSignatureAmbiguous( 297 schemaUtils.isFunctionSignatureAmbiguous(
287 apiFunction.definition)) { 298 apiFunction.definition)) {
288 throw new Error( 299 throw new Error(
289 apiFunction.name + ' has ambiguous optional arguments. ' + 300 apiFunction.name + ' has ambiguous optional arguments. ' +
290 'To implement custom disambiguation logic, add ' + 301 'To implement custom disambiguation logic, add ' +
291 '"allowAmbiguousOptionalArguments" to the function\'s schema.'); 302 '"allowAmbiguousOptionalArguments" to the function\'s schema.');
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 340
330 // Setup Events 341 // Setup Events
331 if (schema.events) { 342 if (schema.events) {
332 forEach(schema.events, function(i, eventDef) { 343 forEach(schema.events, function(i, eventDef) {
333 if (eventDef.name in mod) { 344 if (eventDef.name in mod) {
334 throw new Error('Event ' + eventDef.name + 345 throw new Error('Event ' + eventDef.name +
335 ' already defined in ' + schema.namespace); 346 ' already defined in ' + schema.namespace);
336 } 347 }
337 if (!isSchemaNodeSupported(eventDef, platform, manifestVersion)) 348 if (!isSchemaNodeSupported(eventDef, platform, manifestVersion))
338 return; 349 return;
339 if (!isSchemaAccessAllowed(eventDef)) { 350
340 addUnprivilegedAccessGetter(mod, eventDef.name); 351 var eventName = schema.namespace + "." + eventDef.name;
352 if (!GetAvailability(eventName).is_available ||
353 (checkUnprivileged && !isSchemaAccessAllowed(eventDef))) {
341 return; 354 return;
342 } 355 }
343 356
344 var eventName = schema.namespace + "." + eventDef.name;
345 var options = eventDef.options || {}; 357 var options = eventDef.options || {};
346
347 if (eventDef.filters && eventDef.filters.length > 0) 358 if (eventDef.filters && eventDef.filters.length > 0)
348 options.supportsFilters = true; 359 options.supportsFilters = true;
349 360
350 if (this.customEvent_) { 361 if (this.customEvent_) {
351 mod[eventDef.name] = new this.customEvent_( 362 mod[eventDef.name] = new this.customEvent_(
352 eventName, eventDef.parameters, eventDef.extraParameters, 363 eventName, eventDef.parameters, eventDef.extraParameters,
353 options); 364 options);
354 } else if (eventDef.anonymous) { 365 } else if (eventDef.anonymous) {
355 mod[eventDef.name] = new chrome.Event(); 366 mod[eventDef.name] = new chrome.Event();
356 } else { 367 } else {
357 mod[eventDef.name] = new chrome.Event( 368 mod[eventDef.name] = new chrome.Event(
358 eventName, eventDef.parameters, options); 369 eventName, eventDef.parameters, options);
359 } 370 }
360 }, this); 371 }, this);
361 } 372 }
362 373
363 function addProperties(m, parentDef) { 374 function addProperties(m, parentDef) {
364 var properties = parentDef.properties; 375 var properties = parentDef.properties;
365 if (!properties) 376 if (!properties)
366 return; 377 return;
367 378
368 forEach(properties, function(propertyName, propertyDef) { 379 forEach(properties, function(propertyName, propertyDef) {
369 if (propertyName in m) 380 if (propertyName in m)
370 return; // TODO(kalman): be strict like functions/events somehow. 381 return; // TODO(kalman): be strict like functions/events somehow.
371 if (!isSchemaNodeSupported(propertyDef, platform, manifestVersion)) 382 if (!isSchemaNodeSupported(propertyDef, platform, manifestVersion))
372 return; 383 return;
373 if (!isSchemaAccessAllowed(propertyDef)) { 384 if (!GetAvailability(schema.namespace + "." +
374 addUnprivilegedAccessGetter(m, propertyName); 385 propertyName).is_available ||
386 (checkUnprivileged && !isSchemaAccessAllowed(propertyDef))) {
375 return; 387 return;
376 } 388 }
377 389
378 var value = propertyDef.value; 390 var value = propertyDef.value;
379 if (value) { 391 if (value) {
380 // Values may just have raw types as defined in the JSON, such 392 // Values may just have raw types as defined in the JSON, such
381 // as "WINDOW_ID_NONE": { "value": -1 }. We handle this here. 393 // as "WINDOW_ID_NONE": { "value": -1 }. We handle this here.
382 // TODO(kalman): enforce that things with a "value" property can't 394 // TODO(kalman): enforce that things with a "value" property can't
383 // define their own types. 395 // define their own types.
384 var type = propertyDef.type || typeof(value); 396 var type = propertyDef.type || typeof(value);
(...skipping 21 matching lines...) Expand all
406 } else if (type !== 'string') { 418 } else if (type !== 'string') {
407 throw new Error('NOT IMPLEMENTED (extension_api.json error): ' + 419 throw new Error('NOT IMPLEMENTED (extension_api.json error): ' +
408 'Cannot parse values for type "' + type + '"'); 420 'Cannot parse values for type "' + type + '"');
409 } 421 }
410 m[propertyName] = value; 422 m[propertyName] = value;
411 } 423 }
412 }); 424 });
413 }; 425 };
414 426
415 addProperties(mod, schema); 427 addProperties(mod, schema);
428
429 var availability = GetAvailability(schema.namespace);
430 if (!availability.is_available && Object.keys(mod).length == 0) {
431 console.error('chrome.' + schema.namespace + ' is not available: ' +
432 availability.message);
433 return;
434 }
435
416 this.runHooks_(mod); 436 this.runHooks_(mod);
417 return mod; 437 return mod;
418 } 438 }
419 }; 439 };
420 440
421 exports.Binding = Binding; 441 exports.Binding = Binding;
OLDNEW
« no previous file with comments | « chrome/renderer/extensions/dispatcher.cc ('k') | chrome/renderer/resources/extensions/test_custom_bindings.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698