According to this article on MDN, using postMessage to pass messages to and from a content script in chrome is not secure because can't properly define a source property, and that it's targetOrigin is difficult to securely pass to a potentially malicious site. Is this still true. Are there any other ways to confirm the source of a received message, and to only send messages to a specific content script exclusively? Or are there any alternatives to using content scripts altogether?
The "chrome" in the article on MDN does not refer to "Google Chrome", but to extension code that runs with Chrome privileges (look here for other meanings of "chrome" in Firefox).
In Google Chrome / Chromium, content scripts run in a different environment than the web page (that means that window in the content script is different from window in the web page).
However, when you send a message from the content script to the page, event.source will be identical to the window of the page. So, to verify that the message was really sent from a (content) script within the same page, you could use if (event.source === window) { ... }.
If you want to send a message to another content script (in the same tab), then you have two options:
If the frames are located at different origins, or if the content scripts are located in different tabs, then you have to send a message to the background page, which in turn passes the message to the target content script using the Chrome extension message passing APIs.
If the communicating frames are located at the same origin, then their variables can directly be shared without using the message passing API. Refer to their window objects using top, parent, <HTMLIFrameElement>.contentWindow, frames[index], etc.
Another (hackish) way to get a message from the one content script to another is through the chrome.storage API. At the receiving end, bind a chrome.storage.onChanged event. To "send" a message, use chrome.storage.local.set. Don't forget to remove the key-value pair once you have (not) received the message.
Related
I am creating a chrome extension that requires an HTTP Get Request API call whenever a new page loads. My extension then inserts an IFrame in the web page, to which I would like to provide the data from the API call. I have devised two different ways of doing this. I have been able to get both ways to work, however, I am wondering which is more advisable.
After the content script injects the iframe it makes a call to a background script. In the background script, we fetch the data and do message passing with the postMessage function to send the data to the IFrame. The data is then received by a script inside the IFrame and the data is loaded.
After the content script injects the iframe a script runs inside the IFrame that fetches the data. This same script then loads the data.
Or if there are any other methods, I would be grateful for any recommendations. My logic as of now comparing the two methods I have described is that the first method has advantages of conducting the API calls from the backgorund script, while the second method has the advantage of not requireing a large amount of communication between various scripts.
Is either of these methods superior? Thank you for the advice.
Any extension page or frame that has a chrome-extension:// URL has equal rights. It includes iframes that you insert in web pages with src pointing to an html file from your extension exposed via web_accessible_resources in manifest.json.
It means there are no inherent restrictions or preferred methods.
It only depends on the life cycle of data.
When it would make sense to make the request in the background page:
to cache it in a variable/object if you have a persistent background page for whatever reason;
to avoid interruption of the request due to the tab being closed or navigated away by the user or the main document's script;
to transform the data using some library that you load in the background script and don't want to load it in the UI page/frame for whatever reason e.g. it's slow to load.
any other reason.
As for sharing between pages it should be fast even with messaging unless your data exceeds 64MB message size limit in which case you would have to use Blob URLs or directly access the variable via getBackgroundPage that returns the window object of the background script. There's also BroadcastChannel API that should be able to work between all chrome-extension:// page or frames of an extension and in Chrome it should be much faster than messaging thanks to using the structured cloning algorithm instead of JSON stringify/parsing used by messaging internally.
As a rule of thumb for any performance-related concerns: use devtools performance profiler.
Whenever I load a webpage, I need to get the URL of the current tab to be stored in some variable. I would prefer, to get the URL of the website I am requesting, before anything loads, so I can do some logic depending on the URL.
What are the methods that I can use so I can achieve that?
(this is for firefox extension)
Depending on the specifics of your task, three of the how-tos on the main MDN page on web extensions are relevant:
Intercepting HTTP requests (webRequest)
Modify a web page (content scripts), and
the tabs API (specifically onUpdated).
I used this code to open chrome extension but not opened
<li class="bms-item">bms</li>
Web context cannot open chrome-extension:// or chrome:// links due to security restrictions. The idea is that simply opening the page may perform some action with higher privileges than the webpage.
As mentioned by wOxxOm in comments, you should use externally_connectable (assuming you control both the extension and the webpage). There's a handy guide in the documentation, but the schema is as follows:
You declare in your extension's manifest that your domain, https://example.com/, can call the extension.
From your webpage code, you check that chrome.runtime.sendMessage is available - that means an extension that is ready to listen is installed.
You then call chrome.runtime.sendMessage with the extension ID and the request to do something (i.e. open an extension page).
In the extension's background page, receive the message with chrome.runtime.onMessageExternal and do something, e.g. open the page with chrome.tabs API.
If you control the extension, but not the website, and you're adding the button from a content script, you should assign a handler that calls chrome.runtime.sendMessage and, again, handle it from the background page (which can open an extension page, unlike the content script). This time though it's going to be chrome.runtime.onMessage event.
Alternatively, declaring the page as web-accessible should help (untested).
If you don't control the extension, there's nothing you can do for the security reason above.
Our web site makes use of showModalDialog. Based on what is done within the dialog, we may or may not wish to reload the page that opened the dialog. We do this by having the dialog JavaScript set window.returnValue to true or false, and then the underlying page inspects that in the return value of the call to showModalDialog.
This works fine when the dialog document and underlying page are loaded from the same origin domain. As is typical with the web, when the dialog's domain doesn't match the page's, the return value from showModalDialog is always undefined.
I've entertained passing the flag from the dialog to the underlying window in different ways. Fortunately, we're targeting browsers that all support postMessage, but the dialog JavaScript doesn't appear to be getting a value for window.opener, so I don't think it can get a reference to the window so it can post a message. Implementing an iframe workaround like this is unfeasible with our code base because it would require us to install iframe recipient documents on multiple sites that can all open this same dialog.
Is there a better way for us to have a dialog communicate with cross-origin opening pages without requiring that they reload?
I may have found my own answer. From what I understand, if I set the document.domain property for both the opener document and the dialog document to the same value, I should be able to access this information. Since both are within subdomains of the same root domain name, it should work. If I try this and it works, I will accept this answer.
I have seen this excellent firefox extension, Screengrab!. It takes a "picture" of the web page and copies it to the clipboard or saves it to a png file. I need to do so, but with a new web page, from an url I have in javascript. I can open the web page in a new window, but then I have to call the extension -not to press the control- and saves the page once the page is fully loaded.
Is it possible?
I am pretty certain that it is not possible to access any Firefox add-on through web page content. This could create privacy and/or security issues within the Firefox browser (as the user has never given you permission to access such content on their machine). For this reason, I believe Firefox add-ons run in an entirely different JavaScript context, thereby making this entirely impossible.
However, as Dmitriy's answer states, there are server-side workarounds that can be performed.
Does not look like ScreenGrab has any javascript API.
There is a PHP solution for Saving Web Page as Image.
If you need to do it from JavaScript (from client side) - you can:
Step 1: Create a PHP server app that does the trick (see the link), and that accepts JSONP call.
Step 2: Create a client side page (JavaScript) that will send a JSONP request to that PHP script. See my answer here, that will help you to create such request.