how to access a firefox extension variable from the current document/window - javascript

my firefox extension has an object myExt .
myExt = {
request: function(){
//adds dynamic script element to the current webpage's head tag
},
callback: function(json) {
//do something with this
}
};
myExt.request adds a dynamically added script element to a server that returns json, i want the json to be sent to myExt.callback that exists within my extension's js code.
from my extension
//from my extension, i add a script element
myExt.request();
pings the server, back into the webpage
//from server i get the following response
myExt.callback ( {"some":"json"}) ;
//but the window doesnt find a reference to myExt
how do i make a reference to myExt variable from the webpage ?

Firefox extensions run JavaScript with high privilege (chrome) and have full access to the browser. JavaScript code from a web page run unprivileged JavaScript and among other things cannot reference or interact directly with the privileged JavaScript.
In general, you have to be very careful when your extension code interacts with code coming from websites in order not to open a security hole that could allow a malicious website to execute JavaScript with chrome privileges.
You can find more information here, including code snippets if you need to exchange data between privileged and unprivileged JavaScript:
https://developer.mozilla.org/en/Security_best_practices_in_extensions

See also this link to exchange data between privileged and unprivileged JavaScript:
https://developer.mozilla.org/en/Code_snippets/Interaction_between_privileged_and_non-privileged_pages

Related

Can I fire up a Chrome extension API from code?

Is it possible to launch a Google Chrome extension within a website? E.g run some javascript that will launch the extensions UI?
I'm building a web-app that will allow users to take screenshots of their desktop and edit them. I've got a sample extension up and running using dektopCapture but it is an 'app' style of an extension.
It allows to select a window to stream from, then take a
snapshot within the extension UI(using a button) that is saved as an image string
My question is:
Is it possible to fire up the desktopCapture UI (the window that gets the available windows to stream from), from within my web-app, maybe a button, take the stream and place it on a canvas/HTML5 video element within my web-app?
I'm figuring that I could hook-up an event-listener within the extension and use runtime.onMessage to post a message from within my app
Notes:
If there's a more intuitive way to do this, I can go that route - e.g If I could keep as much interaction within the web-app with just the extension running in the background, that would be even better.
The extension is of type browser_action but I want it to be applicable to a single page(the app's webpage) so if it can be used in a page_action I'd prefer that instead. There's really no need to have browser_action icon if I can trigger this from within a webpage
I'm also planning to build a FF extension so any insights there are also appreciated.
So I'm answering my own question.
I've managed to get it working using externally_connectables.
The externally_connectable manifest property declares which
extensions, apps, and web pages can connect to your extension via
runtime.connect and runtime.sendMessage.
1. Declare app/webpage in manifest.json
Just declare your web-app/page within your manifest.json as an externally_connectable.
E.g I wanted to connect my app is hosted on Github Pages and I have a domain name of https://nicholaswmin.github.io, so it does a bit like this:
"externally_connectable": {
"matches": ["https://nicholaswmin.github.io/*"]
}, //rest of manifest.json
2. Set up event listener for messages in background.js
Then set up an event listener in your background.js like so:
chrome.runtime.onMessageExternal.addListener(function(request, sender, sendResponse) {
//Stuff you want to run goes here, even desktopCapture calls
});
3. Send message from your web/app page
And call it from within your web-app/website like this:
chrome.runtime.sendMessage("APP ID GOES HERE",
{data: { key : "capture"}});
Make sure that your website is correctly declared as an externally_connectable in your manifest.json and that you are passing the app-id when sending the message

JavaScript problems when launching site in iframe

I have set up an Articulate Storyline course (a Flash version accessed using the page "story.html" and an HTML5 version accessed using "story_html5.html"). It works fine when run directly, however, when I try to run everything in an iframe on the company server (linking to the course files on my personal server) I get JavaScript errors:
The course uses player.GetVar("HTML5spelaren") to access a variable called HTML5spelaren, which is located on the story_html5.html page itself. When running in an iframe I get a "Permission denied to access property 'HTML5spelaren'".
Finally the course uses the JavaScript var newWin=document.window.open("report.html", "Kursintyg"); to display a course completion certificate in a new window. When running in an iframe however this results in a "Permission denied to access property 'open'".
Is there a way to rewrite the JavaScripts to get around this? I need to be able to detect if the course is running in Flash or HTML5 mode (that's what I use the variable in story_html5.html for), as well as being able to use JavaScript to open a new page from within the iframe when clicking on a link.
Page structure:
https://dl.dropboxusercontent.com/u/11131031/pagestructure.png
/Andreas
There's a way for different domains to speak to one another via javascript. You can use postMessage: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
In your case, in story.html or story_html5.html could use something like:
parent.postMessage(HTML5spelaren, parent_domain);
and you add an event listener in the company page:
window.addEventListener("message", receiveMessage, false);
And in receiveMessage function you retrieve the data that you need. Something like:
function receiveMessage(event){
your_variable = event.data
}
Same logic can be probably be applied to your popup.
You can post from child to parent or from parent to child.
My guess is that content you're linking to in the iFrame is on a different server/domain. If so, the error is a security feature to stop cross-site scripting (XSS) attacks.
Consider putting both the parent iFrame and the articulate content (child) on the same server. This should eliminate the problem.

How can I get the html of a page as a string in a Firefox extension?

I need to get the html of the current page that is loaded as a string, so that I may manipulate it and use that information later on. I am needing to use this in a Firefox extension, and I am having a lot of trouble getting it to work.
I originally tried storing the value using .outerHTML, which I had seen and got to work in other places. Here is an example of how that worked:
var pageHTML = document.documentElement.outerHTML;
I also tried searching just for the piece that I needed at the time, like so:
document.getElementById("header")
However, neither of these seem to access the HTML. I assume this is because the code is operating in the browser, not in the document itself. How can I go about accessing the HTML 'document' of a page loaded in a tab from a Firefox extension.
The Firefox addon SDK includes a module called page-mod which is intended for this purpose. Content scripts run under page-mod will be run in the context of the web page, rather than the typical sandboxed context.
From that page's documentation:
You can modify the document in your script:
var pageMod = require("sdk/page-mod");
pageMod.PageMod({ include: "*.mozilla.org",
contentScript: 'document.body.innerHTML =' +
'"<h1>Page matches ruleset</h1>";'
});

Using localstorage in bookmarks

I quite like using bookmarks with small scripts in them.
For example, I have edited the note editing script from this post on Reddit to automatically save and load the last note via localstorage.
...
window.addEventListener("load", function () {
div.innerHTML = localStorage.getItem("note");
}, false);
document.body.addEventListener("keyup", debounce(function () {
localStorage.setItem("note", div.innerHTML);
}, 760));
...
It runs fine if I open my html document as an actual html document stored on my hard drive. But when I run it using the URL bar pasting in the (minified) version of my code with data: text/html, ..., I get a NS_ERROR_NOT_AVAILABLE: error. This makes sense, since localstorage is domain-bound.
Is there a way to make localstorage work with bookmarks?
The full note code is available here, note that this code will work if you save it locally on your hard-drive. So you can bookmark this and use it if you want to.
As you describe in the question, localstorage belongs to a web origin. In your browser, bookmarked data: URIs have "null" origin. This means that the browser treats the data: page as being served from a unique origin each time it loads. Even if such an origin could have localStorage, there would be no way to return to the origin to access the data there.
A bookmarklet runs a script in the origin of the current page. This is a problem that has made certain things, like your task, very difficult. In another example, password managers that provide a bookmarklet need to be careful--they're running code in the current page's security sandbox. It's easy for a minor flaw in their code to expose sensitive keys to the currently open page.
If you're determined to have the bookmark point to a data: URI, the current answer is no.
Addendum: There are other ways to have an origin other than by getting a domain. Extensions in Google Chrome have their own origin, and they can run entirely from your local computer.

how to call a function in Firefox extension from a html button

How to call a Javascript function declared in my extension, using a html button from my web page?
I have a html page, with a button inside. When the user click the button, it will call a function that I already declared inside my own firefox extension.
Since you control the web page, the easiest and the safest method to do what you want would be to dispatch a custom DOM event in the web page and listen to it in the extension code:
https://developer.mozilla.org/En/Code_snippets/Interaction_between_privileged_and_non-privileged_pages
Here's an example extension I wrote that does exactly this http://mozilla.doslash.org/cw/ (not updated to the most recent Firefox version, but it's clean and should be easy to update).
Your Firefox extension runs in a different Javascript context to your HTML page, so the extension cannot be directly called from the Javascript in your HTML page.
However, you can design the extension to allow access from HTML. HTML Javascript isn't generally allowed to access the Component object, so you need to allow the HTML code a way to get at the object in your extension. To do this, create an XPCOM component in your extension, and set the object in the "JavaScript global property" category through the nsICategoryManager object. The entry name is the string used from unprivileged Javascript, the value is the contract ID for your XPCOM class.
However, you also need to allow unprivileged Javascript access to your object, or the script security manager will block access. To allow this, implement nsISecurityCheckedComponent - providing canCreateWrapper(in nsIIDPtr iid), canCallMethod(in nsIIDPtr iid, in wstring methodName), canGetProperty(in nsIIDPtr iid, in wstring propertyName) and canSetProperty(in nsIIDPtr iid, in wstring propertyName) to return allAccess for the allowed properties, and noAccess otherwise.
Be careful what you do with user input, and what you allow access to - it is very easy to accidentally create a security hole in the browser doing this.
Try to put this at the beginning of your javascript function that tries to access a local file:
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
This will give the user the choice as to whether they want to allow your code to access the local filesystem.

Categories