Chromium Code Reviews| 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 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 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 204 var schema = this.schema_; | 204 var schema = this.schema_; |
| 205 | 205 |
| 206 // TODO(kalman/cduvall): Make GetAvailability handle this, then delete the | 206 // TODO(kalman/cduvall): Make GetAvailability handle this, then delete the |
| 207 // supporting code. | 207 // supporting code. |
| 208 if (!isSchemaNodeSupported(schema, platform, manifestVersion)) { | 208 if (!isSchemaNodeSupported(schema, platform, manifestVersion)) { |
| 209 console.error('chrome.' + schema.namespace + ' is not supported on ' + | 209 console.error('chrome.' + schema.namespace + ' is not supported on ' + |
| 210 'this platform or manifest version'); | 210 'this platform or manifest version'); |
| 211 return undefined; | 211 return undefined; |
| 212 } | 212 } |
| 213 | 213 |
| 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 = {}; | 214 var mod = {}; |
| 223 | 215 |
| 224 var namespaces = schema.namespace.split('.'); | 216 var namespaces = schema.namespace.split('.'); |
| 225 for (var index = 0, name; name = namespaces[index]; index++) { | 217 for (var index = 0, name; name = namespaces[index]; index++) { |
| 226 mod[name] = mod[name] || {}; | 218 mod[name] = mod[name] || {}; |
| 227 mod = mod[name]; | 219 mod = mod[name]; |
| 228 } | 220 } |
| 229 | 221 |
| 230 // Add types to global schemaValidator, the types we depend on from other | 222 // Add types to global schemaValidator, the types we depend on from other |
| 231 // namespaces will be added as needed. | 223 // namespaces will be added as needed. |
| 232 if (schema.types) { | 224 if (schema.types) { |
| 233 forEach(schema.types, function(i, t) { | 225 forEach(schema.types, function(i, t) { |
| 234 if (!isSchemaNodeSupported(t, platform, manifestVersion)) | 226 if (!isSchemaNodeSupported(t, platform, manifestVersion)) |
| 235 return; | 227 return; |
| 236 | 228 |
| 237 schemaUtils.schemaValidator.addTypes(t); | 229 schemaUtils.schemaValidator.addTypes(t); |
| 238 }, this); | 230 }, this); |
| 239 } | 231 } |
| 240 | 232 |
| 241 // Returns whether access to the content of a schema should be denied, | |
| 242 // based on the presence of "unprivileged" and whether this is an | |
| 243 // extension process (versus e.g. a content script). | |
| 244 function isSchemaAccessAllowed(itemSchema) { | |
| 245 return (contextType == 'BLESSED_EXTENSION') || | |
| 246 schema.unprivileged || | |
| 247 itemSchema.unprivileged; | |
| 248 }; | |
| 249 | |
| 250 // Adds a getter that throws an access denied error to object |mod| | 233 // Adds a getter that throws an access denied error to object |mod| |
| 251 // for property |name|. | 234 // for property |name|. |
| 252 function addUnprivilegedAccessGetter(mod, name) { | 235 function addUnprivilegedAccessGetter(mod, name) { |
| 253 mod.__defineGetter__(name, function() { | 236 mod.__defineGetter__(name, function() { |
| 254 throw new Error( | 237 throw new Error( |
| 255 '"' + name + '" can only be used in extension processes. See ' + | 238 '"' + name + '" can only be used in extension processes. See ' + |
| 256 'the content scripts documentation for more details.'); | 239 'the content scripts documentation for more details.'); |
| 257 }); | 240 }); |
| 258 } | 241 } |
| 259 | 242 |
| 260 // Setup Functions. | 243 // Setup Functions. |
| 261 if (schema.functions) { | 244 if (schema.functions) { |
| 262 forEach(schema.functions, function(i, functionDef) { | 245 forEach(schema.functions, function(i, functionDef) { |
| 263 if (functionDef.name in mod) { | 246 if (functionDef.name in mod) { |
| 264 throw new Error('Function ' + functionDef.name + | 247 throw new Error('Function ' + functionDef.name + |
| 265 ' already defined in ' + schema.namespace); | 248 ' already defined in ' + schema.namespace); |
| 266 } | 249 } |
| 267 | 250 |
| 268 if (!isSchemaNodeSupported(functionDef, platform, manifestVersion)) { | 251 if (!isSchemaNodeSupported(functionDef, platform, manifestVersion)) { |
| 269 this.apiFunctions_.registerUnavailable(functionDef.name); | 252 this.apiFunctions_.registerUnavailable(functionDef.name); |
| 270 return; | 253 return; |
| 271 } | 254 } |
| 272 if (!isSchemaAccessAllowed(functionDef)) { | |
| 273 this.apiFunctions_.registerUnavailable(functionDef.name); | |
| 274 addUnprivilegedAccessGetter(mod, functionDef.name); | |
| 275 return; | |
| 276 } | |
| 277 | 255 |
| 278 var apiFunction = {}; | 256 var apiFunction = {}; |
| 279 apiFunction.definition = functionDef; | 257 apiFunction.definition = functionDef; |
| 280 apiFunction.name = schema.namespace + '.' + functionDef.name; | 258 apiFunction.name = schema.namespace + '.' + functionDef.name; |
| 281 | 259 |
| 260 if (!GetAvailability(apiFunction.name).is_available) { | |
| 261 this.apiFunctions_.registerUnavailable(functionDef.name); | |
| 262 addUnprivilegedAccessGetter(mod, functionDef.name); | |
|
not at google - send to devlin
2013/05/01 20:47:04
Just leave it blank. No need for the unprivileged
cduvall
2013/05/01 23:47:10
Done.
| |
| 263 return; | |
| 264 } | |
| 265 | |
| 282 // TODO(aa): It would be best to run this in a unit test, but in order | 266 // 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 | 267 // to do that we would need to better factor this code so that it |
| 284 // doesn't depend on so much v8::Extension machinery. | 268 // doesn't depend on so much v8::Extension machinery. |
| 285 if (chromeHidden.validateAPI && | 269 if (chromeHidden.validateAPI && |
| 286 schemaUtils.isFunctionSignatureAmbiguous( | 270 schemaUtils.isFunctionSignatureAmbiguous( |
| 287 apiFunction.definition)) { | 271 apiFunction.definition)) { |
| 288 throw new Error( | 272 throw new Error( |
| 289 apiFunction.name + ' has ambiguous optional arguments. ' + | 273 apiFunction.name + ' has ambiguous optional arguments. ' + |
| 290 'To implement custom disambiguation logic, add ' + | 274 'To implement custom disambiguation logic, add ' + |
| 291 '"allowAmbiguousOptionalArguments" to the function\'s schema.'); | 275 '"allowAmbiguousOptionalArguments" to the function\'s schema.'); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 329 | 313 |
| 330 // Setup Events | 314 // Setup Events |
| 331 if (schema.events) { | 315 if (schema.events) { |
| 332 forEach(schema.events, function(i, eventDef) { | 316 forEach(schema.events, function(i, eventDef) { |
| 333 if (eventDef.name in mod) { | 317 if (eventDef.name in mod) { |
| 334 throw new Error('Event ' + eventDef.name + | 318 throw new Error('Event ' + eventDef.name + |
| 335 ' already defined in ' + schema.namespace); | 319 ' already defined in ' + schema.namespace); |
| 336 } | 320 } |
| 337 if (!isSchemaNodeSupported(eventDef, platform, manifestVersion)) | 321 if (!isSchemaNodeSupported(eventDef, platform, manifestVersion)) |
| 338 return; | 322 return; |
| 339 if (!isSchemaAccessAllowed(eventDef)) { | 323 |
| 324 var eventName = schema.namespace + "." + eventDef.name; | |
| 325 var options = eventDef.options || {}; | |
|
not at google - send to devlin
2013/05/01 20:47:04
might as well define options after this block.
cduvall
2013/05/01 23:47:10
Done.
| |
| 326 if (!GetAvailability(eventName).is_available) { | |
| 340 addUnprivilegedAccessGetter(mod, eventDef.name); | 327 addUnprivilegedAccessGetter(mod, eventDef.name); |
|
not at google - send to devlin
2013/05/01 20:47:04
ditto - no unprivileged access getter, just leave
cduvall
2013/05/01 23:47:10
Done.
| |
| 341 return; | 328 return; |
| 342 } | 329 } |
| 343 | 330 |
| 344 var eventName = schema.namespace + "." + eventDef.name; | |
| 345 var options = eventDef.options || {}; | |
| 346 | |
| 347 if (eventDef.filters && eventDef.filters.length > 0) | 331 if (eventDef.filters && eventDef.filters.length > 0) |
| 348 options.supportsFilters = true; | 332 options.supportsFilters = true; |
| 349 | 333 |
| 350 if (this.customEvent_) { | 334 if (this.customEvent_) { |
| 351 mod[eventDef.name] = new this.customEvent_( | 335 mod[eventDef.name] = new this.customEvent_( |
| 352 eventName, eventDef.parameters, eventDef.extraParameters, | 336 eventName, eventDef.parameters, eventDef.extraParameters, |
| 353 options); | 337 options); |
| 354 } else if (eventDef.anonymous) { | 338 } else if (eventDef.anonymous) { |
| 355 mod[eventDef.name] = new chrome.Event(); | 339 mod[eventDef.name] = new chrome.Event(); |
| 356 } else { | 340 } else { |
| 357 mod[eventDef.name] = new chrome.Event( | 341 mod[eventDef.name] = new chrome.Event( |
| 358 eventName, eventDef.parameters, options); | 342 eventName, eventDef.parameters, options); |
| 359 } | 343 } |
| 360 }, this); | 344 }, this); |
| 361 } | 345 } |
| 362 | 346 |
| 363 function addProperties(m, parentDef) { | 347 function addProperties(m, parentDef) { |
| 364 var properties = parentDef.properties; | 348 var properties = parentDef.properties; |
| 365 if (!properties) | 349 if (!properties) |
| 366 return; | 350 return; |
| 367 | 351 |
| 368 forEach(properties, function(propertyName, propertyDef) { | 352 forEach(properties, function(propertyName, propertyDef) { |
| 369 if (propertyName in m) | 353 if (propertyName in m) |
| 370 return; // TODO(kalman): be strict like functions/events somehow. | 354 return; // TODO(kalman): be strict like functions/events somehow. |
| 371 if (!isSchemaNodeSupported(propertyDef, platform, manifestVersion)) | 355 if (!isSchemaNodeSupported(propertyDef, platform, manifestVersion)) |
| 372 return; | 356 return; |
| 373 if (!isSchemaAccessAllowed(propertyDef)) { | 357 if (!GetAvailability(schema.namespace + "." + |
| 374 addUnprivilegedAccessGetter(m, propertyName); | 358 propertyName).is_available) { |
| 359 addUnprivilegedAccessGetter(mod, propertyName); | |
|
not at google - send to devlin
2013/05/01 20:47:04
ditto
cduvall
2013/05/01 23:47:10
Done.
| |
| 375 return; | 360 return; |
| 376 } | 361 } |
| 377 | 362 |
| 378 var value = propertyDef.value; | 363 var value = propertyDef.value; |
| 379 if (value) { | 364 if (value) { |
| 380 // Values may just have raw types as defined in the JSON, such | 365 // Values may just have raw types as defined in the JSON, such |
| 381 // as "WINDOW_ID_NONE": { "value": -1 }. We handle this here. | 366 // as "WINDOW_ID_NONE": { "value": -1 }. We handle this here. |
| 382 // TODO(kalman): enforce that things with a "value" property can't | 367 // TODO(kalman): enforce that things with a "value" property can't |
| 383 // define their own types. | 368 // define their own types. |
| 384 var type = propertyDef.type || typeof(value); | 369 var type = propertyDef.type || typeof(value); |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 407 throw new Error('NOT IMPLEMENTED (extension_api.json error): ' + | 392 throw new Error('NOT IMPLEMENTED (extension_api.json error): ' + |
| 408 'Cannot parse values for type "' + type + '"'); | 393 'Cannot parse values for type "' + type + '"'); |
| 409 } | 394 } |
| 410 m[propertyName] = value; | 395 m[propertyName] = value; |
| 411 } | 396 } |
| 412 }); | 397 }); |
| 413 }; | 398 }; |
| 414 | 399 |
| 415 addProperties(mod, schema); | 400 addProperties(mod, schema); |
| 416 this.runHooks_(mod); | 401 this.runHooks_(mod); |
| 402 | |
| 403 var availability = GetAvailability(schema.namespace); | |
| 404 | |
| 405 function hasItemOfType(typeArray) { | |
| 406 return typeArray.length && !typeArray.filter(function (def) { | |
| 407 return mod.hasOwnProperty(def.name); | |
| 408 }).length; | |
| 409 } | |
| 410 | |
| 411 if (!availability.is_available && | |
| 412 (hasItemOfType(schema.events) || hasItemOfType(schema.functions))) { | |
|
not at google - send to devlin
2013/05/01 20:47:04
a simpler test may be to just check whether the mo
cduvall
2013/05/01 23:47:10
Done.
| |
| 413 console.error('chrome.' + schema.namespace + ' is not available: ' + | |
| 414 availability.message); | |
| 415 return; | |
| 416 } | |
| 417 | |
| 417 return mod; | 418 return mod; |
| 418 } | 419 } |
| 419 }; | 420 }; |
| 420 | 421 |
| 421 exports.Binding = Binding; | 422 exports.Binding = Binding; |
| OLD | NEW |