Execute Page JS Function that makes a https request from content script

(Carl) #1

Hi there,

I hope you can help me with an issue I’m facing while developing a firefox extension.

Basically, my extension calls a javascript function from a certain page within my content script. This javascript function executes a http request to fetch data.

Sidenote: The content script can be started and stoped via a pop up html and js file.

I’ve tried to use the wrappedJSObject but get an error “Permission denied …” when calling window.wrappedJSObject.Primefaces.ab()

Calling a javascript function to change css for example words with the wrappedJSObject by the way.

I guess that It has to do with my manifest.json file, but I’m not sure as I’ve already tried different approaches.

My manifest.json:

{

    "manifest_version": 2,
    "name": "Menninger Freight Booking",
    "version": "1.0",
  
    "description": "Manages automatic booking of freight offers.",
  
    "icons": {
      "48": "icons/38.png"
    },

    "permissions": [
      "activeTab",
      "storage",
      "webRequest",
      "webNavigation", 
      "*://*.localhost/*",
      "*://jsonplaceholder.typicode.com/*"
    ],
  
    "content_scripts": [
      {
        "matches": ["*://*.localhost/*", "*://my.timocom.com/app/tco/freight/search/*", "*://jsonplaceholder.typicode.com/*"],
        "js": ["js/jquery-3.3.1.min.js", "js/contentscript.js"]
      }
    ],
    "browser_action": {
      "default_icon": {
        "19": "icons/19.png",
        "38": "icons/38.png"
      },
      "default_title": "Menninger",
      "default_popup": "popup/choose_settings.html"
    }
  
  }

My content script as follows:

(function () {
  
  
        if (window.hasRun) {
        return;
        }
    
        window.hasRun = true;
  
        browser.runtime.onMessage.addListener((message) => {

            if (message.command === "startBooking") {

                 /**
                 * Some other code here
                 */

                try {

                    // ab() function executes an xhr request
                    window.wrappedJSObject.PrimeFaces.ab({
                    source:'app:cnt:ricosForm:remoteCmdSelectRow',
                    formId: 'app:cnt:ricosForm',
                    process: '@none',
                    update:'app:cnt:searchDetail:messages',
                    oncomplete: function(xhr, status, args) {
                        console.log("STATUS", status, xhr, args);
                    },
                    params: [{name: "selectedrownum", value: 2}]
                    });
                }
                catch (e){
                    // Permission denied error is raised here!
                    console.error("An error occurred while executing PrimeFaces.ab() for retrieving detail page with error", e);
                }
            }
            else if (message.command === "stopBooking") {
                
                console.log("Received stop booking command");
                
                /**
                 * Do sth else here
                 */
                
            }
    });
})();

Could you please advice me how to handle this problem?

Best Regards,

Carl

0 Likes

(Martin Giger) #2

You need to clone the object you’re passing in as parameter into the page scope. See https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Sharing_objects_with_page_scripts#Sharing_content_script_objects_with_page_scripts

0 Likes

(Carl) #3

Hey Martin,

thanks for that. Seems to work so far.

Best,

Carl

0 Likes

(Carl) #4

Well, I’ve tried different options now but don’t have any success.

Either I get the error "PrimeFaces is undefined" or "Permission denied to access property "source""

I’ve used the the cloneInto() as well as the exportFunction() methods available in my content script.

First I’m using the wrappedJSObject as follows:

  var unsafeWindow = window.wrappedJSObject;
  var PrimeFaces = unsafeWindow.PrimeFaces;

I wrapped the PrimeFaces call into the following function:

function getDetailPage() {
// Navigates to detail page of freight booking with PrimeFaces.ab()
try {
 PrimeFaces.ab({
    source:'app:cnt:ricosForm:remoteCmdSelectRow',
    formId: 'app:cnt:ricosForm',
    process: '@none',
    update:'app:cnt:searchDetail:messages',
    oncomplete: function(xhr, status, args) {
        //clearInterval(localStorage.getItem("timer"))
        console.log("HELLO WORLD I'm here")
        console.log("STATUS", status, xhr, args)
    },
    params: [{name: "selectedrownum", value: 2}]
  });
}
catch (e){
  console.error("An error occurred IN SIMPLEFUNCTION while executing PrimeFaces.ab() for retrieving detail page with error", e);
}

}

Then, I copy the function with

exportFunction(getDetailPage, unsafeWindow, {defineAs:"getDetailPage"})

But I’m getting a permission denied error on the source

Error: "Permission denied to access property "source""

ab https://my.timocom.com/app/tco/javax.faces.resource/jsMain-min.js.xhtml?ln=js&tc_v=23.0.3.0:2

I also tried to use cloneInto with an object as described in the documentation

var messenger = {
    perform: function() {
      console.log("PERFORM IT");
    },
    getDetailPage: function() {
      console.log("GETTING DETAIL PAGE!");
      try {
        PrimeFaces.ab({
          source:'app:cnt:ricosForm:remoteCmdSelectRow',
          formId: 'app:cnt:ricosForm',
          process: '@none',
          update:'app:cnt:searchDetail:messages',
          oncomplete: function(xhr, status, args) {
              //clearInterval(localStorage.getItem("timer"));
              console.log("HELLO WORLD I'm here");
              console.log("STATUS", status, xhr, args);
          },
          params: [{name: "selectedrownum", value: 0}]
        });
      }
      catch (e) {
        console.error("Error getting Detail Page: ", e)
      }
    },
    makeGetCall: function () {
      $.get("https://jsonplaceholder.typicode.com/todos/1", function( data ){
              console.log("AJAX REQUEST PERFORMED", data);
            });
    }
  };

and the cloning into via cloneInto but I’m getting an undefined error when calling messenger.getDetailPage(). On the other side the makeGetCall() that uses the jquery from the page is working.

I’m now really stuck with that, and thinking that the cause of the permission denied error is somewhere in a cross origin problem between the site and the extension.

I’ve tried to extend the manifest.json as follows, but no positiv result so far, also added content_security_policy to it and <all_urls>.

{

    "manifest_version": 2,
    "name": "Menninger Freight Booking",
    "version": "1.0",
  
    "description": "Manages automatic booking of freight offers.",
  
    "icons": {
      "48": "icons/38.png"
    },

    "permissions": [
      "activeTab",
      "storage",
      "webRequest",
      "webNavigation", 
      "webRequestBlocking",
      "*://*.localhost/*",
      "*://jsonplaceholder.typicode.com/*",
      "*://my.timocom.com/*",
      "<all_urls>" 
    ],
    "content_security_policy": "script-src 'self' 'unsafe-eval' https://my.timocom.com; object-src 'self'",
    "content_scripts": [
      {
        "matches": ["*://*.localhost/*", "*://my.timocom.com/app/tco/freight/search/*", "*://jsonplaceholder.typicode.com/*"],
        "js": ["js/jquery-3.3.1.min.js", "js/menninger.js"],
        "css": ["css/menninger.css"]
      }
    ],
    "browser_action": {
      "default_icon": {
        "19": "icons/19.png",
        "38": "icons/38.png"
      },
      "default_title": "Menninger",
      "default_popup": "popup/choose_settings.html"
    }
  
  }

Any further tipps on this issue?

Best Regards,

Carl

0 Likes

(Martin Giger) #5

I’m not seeing the cloneInto call in your second code snippet. The object you’d want to clone is the one you’re passing as parameter to the function on wrappedJSObject, so

{
  source: 'app:cnt:ricosForm:remoteCmdSelectRow',
  formId: 'app:cnt:ricosForm',
  process: '@none',
  update: 'app:cnt:searchDetail:messages',
  oncomplete: function(xhr, status, args) {
    //clearInterval(localStorage.getItem("timer"));
    console.log("HELLO WORLD I'm here");
    console.log("STATUS", status, xhr, args);
  },
  params: [{name: "selectedrownum", value: 0}]
}

Don’t forget to also clone functions (as mentioned in the docs)!

Lastly, this is entirely unrelated to anything in your manifest, that only controls permissions or things like CORS. The CSP will only affect your own scripts, and not things running in a page context.

0 Likes