Can I fire up a Chrome extension API from code? - javascript

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

Related

Inject content script into iFrame across domains (but with optional permissions)? [duplicate]

Content Script can be injected programatically or permanently by declaring in Extension manifest file. Programatic injection require host permission, which is generally grant by browser or page action.
In my use case, I want to inject gmail, outlook.com and yahoo mail web site without user action. I can do by declaring all of them manifest, but by doing so require all data access to those account. Some use may want to grant only outlook.com, but not gmail. Programatic injection does not work because I need to know when to inject. Using tabs permission is also require another permission.
Is there any good way to optionally inject web site?
You cannot run code on a site without the appropriate permissions. Fortunately, you can add the host permissions to optional_permissions in the manifest file to declare them optional and still allow the extension to use them.
In response to a user gesture, you can use chrome.permission.request to request additional permissions. This API can only be used in extension pages (background page, popup page, options page, ...). As of Chrome 36.0.1957.0, the required user gesture also carries over from content scripts, so if you want to, you could add a click event listener from a content script and use chrome.runtime.sendMessage to send the request to the background page, which in turn calls chrome.permissions.request.
Optional code execution in tabs
After obtaining the host permissions (optional or mandatory), you have to somehow inject the content script (or CSS style) in the matching pages. There are a few options, in order of my preference:
Use the chrome.declarativeContent.RequestContentScript action to insert a content script in the page. Read the documentation if you want to learn how to use this API.
Use the webNavigation API (e.g. chrome.webNavigation.onCommitted) to detect when the user has navigated to the page, then use chrome.tabs.executeScript to insert the content script in the tab (or chrome.tabs.insertCSS to insert styles).
Use the tabs API (chrome.tabs.onUpdated) to detect that a page might have changed, and insert a content script in the page using chrome.tabs.executeScript.
I strongly recommend option 1, because it was specifically designed for this use case. Note: This API was added in Chrome 38, but only worked with optional permissions since Chrome 39. Despite the "WARNING: This action is still experimental and is not supported on stable builds of Chrome." in the documentation, the API is actually supported on stable. Initially the idea was to wait for a review before publishing the API on stable, but that review never came and so now this API has been working fine for almost two years.
The second and third options are similar. The difference between the two is that using the webNavigation API adds an additional permission warning ("Read your browsing history"). For this warning, you get an API that can efficiently filter the navigations, so the number of chrome.tabs.executeScript calls can be minimized.
If you don't want to put this extra permission warning in your permission dialog, then you could blindly try to inject on every tab. If your extension has the permission, then the injection will succeed. Otherwise, it fails. This doesn't sound very efficient, and it is not... ...on the bright side, this method does not require any additional permissions.
By using either of the latter two methods, your content script must be designed in such a way that it can handle multiple insertions (e.g. with a guard). Inserting in frames is also supported (allFrames:true), but only if your extension is allowed to access the tab's URL (or the frame's URL if frameId is set).
I advise against using declarativeContent APIs because they're deprecated and buggy with CSS, as described by the last comment on https://bugs.chromium.org/p/chromium/issues/detail?id=708115.
Use the new content script registration APIs instead. Here's what you need, in two parts:
Programmatic script injection
There's a new contentScripts.register() API which can programmatically register content scripts and they'll be loaded exactly like content_scripts defined in the manifest:
browser.contentScripts.register({
matches: ['https://your-dynamic-domain.example.com/*'],
js: [{file: 'content.js'}]
});
This API is only available in Firefox but there's a Chrome polyfill you can use. If you're using Manifest v3, there's the native chrome.scripting.registerContentScript which does the same thing but slightly differently.
Acquiring new permissions
By using chrome.permissions.request you can add new domains on which you can inject content scripts. An example would be:
// In a content script or options page
document.querySelector('button').addEventListener('click', () => {
chrome.permissions.request({
origins: ['https://your-dynamic-domain.example.com/*']
}, granted => {
if (granted) {
/* Use contentScripts.register */
}
});
});
And you'll have to add optional_permissions in your manifest.json to allow new origins to be requested:
{
"optional_permissions": [
"*://*/*"
]
}
In Manifest v3 this property was renamed to optional_host_permissions.
I also wrote some tools to further simplify this for you and for the end user, such as
webext-domain-permission-toggle and webext-dynamic-content-scripts. They will automatically register your scripts in the next browser launches and allow the user the remove the new permissions and scripts.
Since the existing answer is now a few years old, optional injection is now much easier and is described here. It says that to inject a new file conditionally, you can use the following code:
// The lines I have commented are in the documentation, but the uncommented
// lines are the important part
//chrome.runtime.onMessage.addListener((message, callback) => {
// if (message == “runContentScript”){
chrome.tabs.executeScript({
file: 'contentScript.js'
});
// }
//});
You will need the Active Tab Permission to do this.

How do I check if firebug is installed with javascript?

Here it is described how to check if Firebug is installed by checking if an image of firebug exists: http://webdevwonders.com/detecting-firefox-add-ons/
But it seems to be a bit outdated, cause the images he uses there don't exist anymore in firebug.
the firebug chrome.manifest looks like:
content firebug content/firebug/ contentaccessible=yes
...
but in the whole addon I only find one png now, and that is placed in the rootfolder of the addon. But some other content is accessible, for example: chrome://firebug/content/trace.js
Ho
So, in gerneral:
How do I make an image accessible that resides inside a Firefox SDK Addon?
I program an Addon and I want to make an image ok.png available to all javascripts in Firefox.
I added the image in the data folder and added a chrome.manifest
content response-timeout-24-hours data/
content response-timeout-24-hours data/ contentaccessible=yes
But no way to call it via a URL like
chrome://response-timeout-24-hours/data/ok.png
How do the paths belong together? which is relative to which?
I created a Bug report here.
So if you want to make your add-on detectable you need another approach:
you can use a PageMod to attach a content script that would wait for a
message from your web-app and "respond" by sending another message
back to your app. you would know that if you don't receive the
response, your addon is not installed. check out the documentation for
more details:
https://developer.mozilla.org/en-US/Add-ons/SDK/High-Level_APIs/page-mod
I used this to make my add-on detectable.

chrome extensions - Content Scripts on demand

I wrote my small extension for Chrome which works in the context of the webpage.
Everything is fine, except that code is executed every time when I visit URL defined in the manifest.json in content-scripts matches.
What I would like is to launch it manually - 'on demand' - after clicking on the icon of the extension next to the url bar.
Is this possible?
Yes - it is possible.
I've took it from: http://developer.chrome.com/extensions/content_scripts.html
The relevant part is:
"...To insert code into a page, 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 executeScript()..."
/* in background.html */
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(null,
{code:"document.body.bgColor='red'"});
});

Invoking a Google Chrome extension from Javascript

There is an excellent extension called Blipshot which takes page screenshots. I need to invoke the extension with page level javascript, instead of clicking its icon. Is this possible?
You cannot invoke any methods of an extension from within a web page. However, it's possible to inject a content script into the web page, and use sendMessage and onMessage, or onConnect and connect.
To edit an extension: Visit chrome://extensions page, and enable the Developer mode. Unpack an extension and/or visit the extension's directory. Edit the manifest.json file, and add the necessary lines (see here).
Add an event event listener at the background page. Add a poller in the content script, eg:
// Content script
var poller = window.setInterval(function() {
if (document.documentElement.getAttribute('extensionCalled')) {
chrome.extension.sendMessage({"anyname": "anything"}, function() {
/*optional callback function.*/alert("Something happened")
});
clearInterval(poller);
}
}, 200);
// Background
chrome.extension.onMessage.addListener(function(request, sender, callback) {
if (request.anyname == "anything") {
function_logic_here();
//Optionally, callback:
callback();
}
});
See also
Chrome extension - retrieving Gmail's original message - Using DOM events to communicate between a page and extension (recommended)
MDN: postMessage - It can be used to communicate between a page and extension (this method may cause conflicts when the page itself is also using the message events).
References:
Extension messaging
Content scripts
Content scripts in extensions
It would only be possible if the extension provides an interface to do it. Extensions run in an isolated environment, so you don't have direct access to any of their functions.
The closest they get is content scripts, which have access to the DOM. Because of that, you can communicate using events, but obviously the extension would need to set up event handlers for them, so it completely depends on the extension.

Beginner Assistance - Where does this code belong?

I'm trying to develop a firefox extension that inserts additional HTTP header fields into outgoing HTTP requests (to interface with an apache extension i'm concurrently developing).
While I understand the individual components of an extension and understand the basic tutorials that are presented on the web, I'm finding it difficult going from the "Hello World" tutorial extensions, into developing a full blown extension.
The sample code I am wanting to adapt for my purposes is presented at the bottom of Setting HTTP request headers.
I am wondering, where in the extension hierarchy should this code be placed and how is such code called/constructed/activated, will it run automatically when the extension is initialised?
Thanks in advance.
For a basic extension, you would place your code in the chrome/content directory of the extension. You would hook this content into Firefox using an overlay. While overlays are usually xul content (buttons, etc) they can be anything. Including a script tag which would load fire off your Javascript code.
That code is an XPCOM component and goes into a components/<some name>.js file.
You should read up on XPCOM components if you want to dig it, but yes, .js files in components are loaded at startup. Such files contain registration code (starts at the var myModule = { line in that example), which tells Firefox whether the component defined in the file is available upon request or should it be instantiated automatically.
In that example you can see the component getting registered to be notified of the application's startup:
catMgr.addCategoryEntry("app-startup", this.myName, this.myProgID, true, true);
and when handling the app-startup notification it registers itself for the http-on-modify-request notification:
os.addObserver(this, "http-on-modify-request", false);

Categories