tmj
tmj

Reputation: 1858

Firefox add-on: function not available after juggling scopes

As of Firefox 36, Function.__exposedProps__ was made unavailable. Instead if one wanted to expose a chrome JS object to be used in content scripts, they have to use Components.utils.cloneInto with the target scope as browser.contentWindow.wrappedJSObject.

If one does not turn on the cloneFunctions flag, only those attributes are cloned that are not functions. Turning the flag does clone functions too, but not those functions that are defined via the Function.prototype path. For those functions one has to export them via Components.utils.exportTo with the target scope as your exposed object.

Coming to the issue I'm facing. (As I am unable to put it in words, I am adding a MWE).

Chrome end JS:

function Foo(){
    this._nFunc = "something";
    this._func  = function(){/*do something*/};
}

Foo.prototype.Bar = function(){
    this._func();
}

Foo.prototype.FooBar = function(){
    this._nFunc = "somthing else";
}

var myFoo = new Foo();
var targetScope  = browser.contentWindow.wrappedJSObject;

targetScope.myExposedObject = Components.utils.cloneInto(myFoo, targetScope, {cloneFunctions:true});
Components.utils.exportFunction(myFoo.Bar, targetScope.myExposedObject , {defineAs:"Bar"});
Components.utils.exportFunction(myFoo.FooBar, targetScope.myExposedObject , {defineAs:"FooBar"});

Content end JS:

window.myExposedObject.FooBar(); // works
window.myExposedObject._func();  // works
window.myExposedObject.Bar()     // error this._func is undefined

Upon logging the this scope received by the function Bar(), we get _func:(void 0), while _nFunc is logged correctly.

Questions:

  1. Is there something I'm missing, or is this a limitation in Firefox? If it is a limitation, please suggest possible ways to workaround the limitation.
  2. Initially I thought that Bar() was somehow unable to access the scope of the calling object, and I tried to supply it the scope as parameters, i.e., Foo.prototype.Bar = function(scope){ scope._func();} and window.myExposedObject.Bar(window.myExposedObject);. Interestingly upon logging, the scope object also turned out to be (void 0). Why is that? I am sure that I am missing something here. What I expected was that the exposed object would map to the original object and upon sending the exposed object as parameters the chrome end JS would be able to get the original object.

Upvotes: 1

Views: 172

Answers (1)

the8472
the8472

Reputation: 43042

While what you're trying to do might be possible with the right combination of cloneInto/exportFunction and waiving of xrays i would suggest you simply load the unprivileged part of your class hierarchy directly into the target context with the subscript loader and only hook the minimal amount of privileged functions into the prototype once it has been created.

This should reduce the attack surface and also avoid headaches with inheritance.

Additionally, these may prove useful:

https://developer.mozilla.org/en-US/docs/Components.utils.createObjectIn https://developer.mozilla.org/en-US/docs/Components.utils.makeObjectPropsNormal

Upvotes: 1

Related Questions