chrome extension: sharing an object between content scripts and background script - google-chrome-extension

I am developing a chrome extension that uses jQuery/Zepto in the content script. Now, the extension is meant to run on every website, which means a copy of jQuery/Zepto is loaded on each tab the user opens.
Is there a way to share the jQuery/Zepto object between the various content scripts?
I know content scripts can communicate with the background script. I was hoping to be able to let the background script have access to the jQuery object and return a reference to it, to each of the content scripts. But I realized only JSON messages can be passed between content and background scripts.
Is there any way to achieve what I want?

Content scripts in different tabs do not have access to each other's JavaScript objects either.
Chrome supports communication between content scripts and/or the background page via chrome.runtime.sendMessage + .onMessage. Because all messages are JSON-serialized, JavaScript object cannot be "leaked" to other contexts in this way.
So: No, you cannot share objects such as jQuery with (content scripts in) other tabs.

Execution environment of Content Scripts ensure content scripts can communicate among themselves
Ex:
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["myscript.js","myscript1.js"]
}
]
}
A Individual DOM Environment where content scripts ["myscript.js","myscript1.js"] injected ensures myscript1.js have access to all contents (Functions,Variables) of myscript.js, but this stops from two Individual DOM Environment's being communicating.
Having said that, What Limitation\requirement you see in Content Scripts which calls for requirement where message passing needs background pages to access DOM of injected pages?
Please Elaborate

Related

Chrome Extension: How to inject a content script into an iframe's page

I'm working on a Chrome extension that among other things supports a page with multiple dynamically created iframes in it, pointing to multiple different domains. I need to load a content script into each of those iframes, ideally without loading it into every page.
There's a separate content script that's running on all those iframe pages, which can detect that it's in an applicable iframe, and I'd like it to load this other content script. After some wrangling, it can get the frameId of that iframe, but chrome.tabs.executeScript() takes only tabId, not frameId, so the script loads in the top-level page, not the desired iframe.
Note that the script I want to inject needs to run as a content script, with access to the available Chrome APIs.
Is it possible to do this? How?
Update: Ach, you're of course right wOxxOm, that "frameId can be specified inside executeScript's second parameter". Thank you again, make that an answer and I'll accept it. I need to read more carefully, apparently. I'm a long-time programmer, but new to Chrome extensions, there's a lot to absorb.
Secondary question: It appears that I need to add <all_urls> or http://*/* and https://*/*, permission to the manifest for this to be allowed. The main content_script that's doing this has similar match patterns, and I could add this secondary script there too, but it's actually only needed for pages shown in these iframes, so this seems better to me. Are there other downsides to doing it this way, or is there some better approach, other than xhr/eval?

Devtools chrome extension: Run script at start of every frame/page load?

I'm writing a devtools Chrome extension with a dev panel. The devtools script can use chrome.devtools.inspectedWindow.reload to reload the page and run a script before other scripts run (in every frame in the inspected window). However, the injected script is no longer run for subsequent page reloads and newly created frames.
How can I inject a script into the inspected window that is run at the start of every subsequent page load in the inspected window?
I know I can use a content script that runs at document_start, but that would run the script at the start of each page load regardless of whether the dev panel is open - and the script is intensive, so I'd like to avoid running the script when it's not needed.
Could the devtools script somehow listen for the beginning of page loads in the inspected window and respond by running a script in the page's context?
One option that you can use to avoid running the script when it's not needed, as you have said, is programmatic injection. As discussed:
Inserting code into a page programmatically is useful when your JavaScript or CSS code shouldn't be injected into every single page that matches the pattern — for example, if you want a script to run only when the user clicks a browser action's icon.
To insert code into a page, you must have the following:
your extension must have cross-origin permissions for the page.
It also must be able to use the chrome.tabs module.
You can get both kinds of permission using the manifest file's permissions field.
Once you have permissions set up, you can inject JavaScript into a page by calling tabs.executeScript.
As also discussed in chrome.devtools.inspectedWindow in executing code in the inspected window, use the tabs.executeScript method unless you need the specific functionality that the eval method provides.
However in Communicating Between Extension Components, please note that:
The DevTools page can't call tabs.executeScript directly. To inject a content script from the DevTools page, you must retrieve the ID of the inspected window's tab using the inspectedWindow.tabId property and send a message to the background page. From the background page, call tabs.executeScript to inject the script.
You may go through the given documentations for more information and examples.

How to persist PNaCl process within a Chrome Extension

My team and I have created a Chrome Extension which bundles a PNaCl application to handle multimedia encoding & muxing which is adapted from the Pepper SDK (version 39) examples and the online SDK tutorial. The application's purpose to capture content from the user's desktop, tab, and webcam in order to create multimedia files.
The extension works as expected while it's visible but the PNaCl process is stopped/unloaded when the extension is hidden. I need to know what is the best strategy to persist a PNaCl process when the Chrome Extension is no longer visible.
The PNaCl app is embedded in my primary UI code (in my case this is set to index.html). The extension contains Background Pages which continues to process requests when hidden so I'm confident the manifest.json permissions and process work as expected. Additionally there are no exceptions.
So far I've attempted:
Make a background JavaScript page the interface to the PNaCl application so it's reference is stored in the background page which should persist.
Create a Chrome Window in order to persist PNaCl application and present a live-preview of the captured stream while the extension is hidden.
(Ongoing) Embed the PNaCl container a background HTML page rather primary HTML page which represents the extension UI.
So far none of them have persisted the PNaCl process.
The relevant parts of my manifest.json:
{
"manifest_version": 2,
"minimum_chrome_version": "39.0.0.0",
"offline_enabled": true,
"permissions":[
"desktopCapture",
"tabCapture",
"tabs",
"unlimitedStorage"
],
"browser_action":{
"default_popup": "index.html"
},
"background":{
"scripts": ["helpers.js", "background.js", "capture_state.js"],
"persistent": true
}
}
If I'm able to resolve before I get a response I'll respond with a solution.
We've resolved the issue despite the lack of documentation.
Here are the primary issues:
Issue #1 - Listener ID in front-end extension code.
We had our id="listener" inside of our front-end extension code (which is unloaded when the extension is hidden) and manually specifying a background.html page doesn't allow us to use background JavaScript files (a requirement of our application).
Resolution: We dynamically added the id="listener" and altered the common.js file using document.addElement to the generated background page (which is automatically created when the extension is loaded).
Issue #2 - getUserMedia method invoked in front-end extension code.
Our application requires that the streams returned from getUserMedia persist so that we can capture from the mic, webcam, and desktop in the background even if the extension is hidden.
Since we requested these in the front-end extension code (to create a live-preview) we thought we could simply pass them into the generated background page and they would persist.
What we found is that when the extension is hidden reading from the streams halts immediately without error. We found this out by digging through our code and monitoring the Chrome Task Manager to see that when the extension was hidden it's CPU usage goes to 0 but it's memory stays elevated (much like phenomena you'd expect when a thread deadlocks or is blocking).
Resolution: Moving the getUserMedia invocation to one of the background scripts and using the streams it returns resolves this.
If you create the PNaCl object in the popup window, which is supposed to be a throwaway destroyed whenever it loses focus, you won't be able to persist it.
It's not losing visibility, it's just completely unloaded.
Your "Ongoing" idea of putting the <embed> into the background page is probably correct.

How to use dropbox API from chrome extension content script?

If I write a chrome extension, it normally consist of multiple parts:
One is the devtools page which is a normal HTML page with origin set to
"chrome-extension://<guid>/filename". On that page I can use
the Dropbox API to get user confirmation via HTML popup and then use
the saved auth info and do all work via the Dropbox javascript library.
Another part of extension is the content script which is executed
in the context of specified third-party web pages ("injected") and have
origin cookies and web storage shared with them.
Is it possible to also use the Dropbox JavaScript library in that content script?
I can't call authenticate in interactive mode since it will re-ask for confirmation for each different webpage I'm injected into. And calling authenticate without interactive will fail since the content script doesn't share the origin, cookies and web storage with the devtools extension page :(. Maybe there's some way to "pass" the Dropbox auth info from the part of the extension that offers GUI and where user successfully confirms dropbox usage to the parts of the extension that are GUI-less, like content script or background page?
I have managed to get Facebook working from code injected into a web app via a content script. I suspect there are multiple ways, but what I did was take advantage of the chrome.identity API to do the OAuth work for me, specifically the launchWebAuthFlow().
This can only be done in the background page (in my case an event page), but I send messages to the event page which replies with the access_token, which can then be used in URLs in the same was as the 'web' technique - i.e. in HTTP requests with XHR.
You can send/receive messages via the content script (using events on document), but I decided to do it directly using "external" messages with the chrome.runtime.sendMessage() API in the web app context, and chrome.runtime.onMessageExternal() in the background script. This requires adding "matches" for the URLs you're injecting code into in an "externally_connectable" section of the manifest.json.
I believe this can be adapted to make it work with Dropbox.

Can `chrome.*` extension API's be used inside content scripts?

I am trying to use chrome.windows.onCreated but I got Uncaught TypeError: Cannot read property 'onCreated' of undefined. I noticed in the samples, all calls to chrome.* API's seem to originate from background scripts? Can I not use them in content scripts?
I want to trigger clicks in my browser. Then get some information (scrape) in popup window. For that I think I will need to know when a window is opened. So I need windows.onCreated? Can I use that in content scripts? Or how will I combine background and content scripts?
From the documentation for Content scripts:
However, content scripts have some limitations. They cannot:
Use chrome.* APIs (except for parts of chrome.extension)
Use variables or functions defined by their extension's pages
Use variables or functions defined by web pages or by other content scripts
These limitations can indirectly be avoided, mainly by sending messages within the extension. The documentation offers several examples which involves message passing. Prior Chrome 20, the message API methods was called onRequest and sendRequest. Since version 20, they're called onMessage and sendMessage.
Here's an answer which mentions the steps how to pass a message from a content script to a popup:
https://stackoverflow.com/a/11617742

Resources