Search code examples
firefox-addonfirefox-addon-sdk

Security Error when trying to load content from resource in a Firefox Addon (SDK)


I am creating a firefox addon using the SDK. My goal is simple, to intercept a specific iframe and load my own HTML page (packaged as a resource with my addon) instead of the content that was requested originally.

So far I have the following code:

var httpRequestObserver = 
{
    observe: function(subject, topic, data)
    {
        var httpChannel, requestURL;

        if (topic == "http-on-modify-request") {
            httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
            requestURL = httpChannel.URI.spec;

            var newRequestURL, i;

            if (/someurl/.test(requestURL)) {
                var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);

                httpChannel.redirectTo(ioService.newURI(self.data.url('pages/test.html'), undefined, undefined));
            }

            return;
        }
    }
};

var observerService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
observerService.addObserver(httpRequestObserver, "http-on-modify-request", false);

This code works in that it detects the proper iframe loading and does the redirect correctly. However, I get the following error:

Security Error: Content at http://url.com may not load or link to jar:file:///.../pages/test.html.

How can I get around this limitation?


Solution

  • actually man i was really over thinking this.

    its already solved when I changed to using loadContext. Now when you get loadContext you get the contentWindow of whatever browser element (tab browser, or frame or iframe) and then just abort the http request like you are doing and then loadContext.associatedWindow.document.location = self.data('pages/tests.html');

    done

    ill paste the code here removing all the private stuff. you might need the chrome.manifest ill test it out and paste the code back here

    Cu.import('resource://gre/modules/Services.jsm');
    
    var httpRequestObserver = {
        observe: function (subject, topic, data) {
            var httpChannel, requestURL;
    
            if (topic == "http-on-modify-request") {
                httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
                requestURL = httpChannel.URI.spec;
    
                var newRequestURL, i;
    
                if (/someurl/.test(requestURL)) {
                    var goodies = loadContextGoodies(httpChannel);
                    if (goodies) {
                        httpChannel.cancel(Cr.NS_BINDING_ABORTED);
                        goodies.contentWindow.location = self.data.url('pages/test.html');
                    } else {
                        //dont do anything as there is no contentWindow associated with the httpChannel, liekly a google ad is loading or some ajax call or something, so this is not an error
                    }
                }
    
                return;
            }
        }
    };
    Services.obs.addObserver(httpRequestObserver, "http-on-modify-request", false);
    
    
    //this function gets the contentWindow and other good stuff from loadContext of httpChannel
    function loadContextGoodies(httpChannel) {
        //httpChannel must be the subject of http-on-modify-request QI'ed to nsiHTTPChannel as is done on line 8 "httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);"
        //start loadContext stuff
        var loadContext;
        try {
            var interfaceRequestor = httpChannel.notificationCallbacks.QueryInterface(Ci.nsIInterfaceRequestor);
            //var DOMWindow = interfaceRequestor.getInterface(Components.interfaces.nsIDOMWindow); //not to be done anymore because: https://developer.mozilla.org/en-US/docs/Updating_extensions_for_Firefox_3.5#Getting_a_load_context_from_a_request //instead do the loadContext stuff below
            try {
                loadContext = interfaceRequestor.getInterface(Ci.nsILoadContext);
            } catch (ex) {
                try {
                    loadContext = subject.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext);
                } catch (ex2) {
                }
            }
        } catch (ex0) {
        }
    
        if (!loadContext) {
            //no load context so dont do anything although you can run this, which is your old code
            //this probably means that its loading an ajax call or like a google ad thing
            return null;
        } else {
            var contentWindow = loadContext.associatedWindow;
            if (!contentWindow) {
                //this channel does not have a window, its probably loading a resource
                //this probably means that its loading an ajax call or like a google ad thing
                return null;
            } else {
                var aDOMWindow = contentWindow.top.QueryInterface(Ci.nsIInterfaceRequestor)
                    .getInterface(Ci.nsIWebNavigation)
                    .QueryInterface(Ci.nsIDocShellTreeItem)
                    .rootTreeItem
                    .QueryInterface(Ci.nsIInterfaceRequestor)
                    .getInterface(Ci.nsIDOMWindow);
                var gBrowser = aDOMWindow.gBrowser;
                var aTab = gBrowser._getTabForContentWindow(contentWindow.top); //this is the clickable tab xul element, the one found in the tab strip of the firefox window, aTab.linkedBrowser is same as browser var above //can stylize tab like aTab.style.backgroundColor = 'blue'; //can stylize the tab like aTab.style.fontColor = 'red';
                var browser = aTab.linkedBrowser; //this is the browser within the tab //this is where the example in the previous section ends
                return {
                    aDOMWindow: aDOMWindow,
                    gBrowser: gBrowser,
                    aTab: aTab,
                    browser: browser,
                    contentWindow: contentWindow
                };
            }
        }
        //end loadContext stuff
    }
    

    NOTE: Now try this first, I didn't test it yet, if you get a security error when it tries to redirect then create a chrome.manifest file and put it in the root directory. If it throws a security error than you definitely need a chrome.manifest file and that will without question fix it up. I'll test this myself later tonight when I get some time.

    The chrome.manifest should look like this:

    content kaboom-data ./resources/kaboom/data/ contentaccessible=yes
    

    Then in the code way above change the redirect line from goodies.contentWindow.location = self.data.url('pages/test.html'); to goodies.contentWindow.location = 'chrome://kaboom-data/pages/test.html');.