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