Using postMessage to extension background page - javascript

I'm trying to send a CryptoKey (generated by SubtleCrypto.generateKey()) object from a contentscript to the background page of a webextension.
When using chrome.runtime.sendMessage to send the object, it is lost, as CryptoKey is not stringifyable (see also this question). Using window.postMessage to transfer the key to another window does work, as this method uses structured cloning..
Is there something similar to postMessage to send data that is not stringifyable to the background page of a webextension?

Thanks to the comment by #wOxxOm I solved it by creating a web accessible resource with this code:
window.addEventListener("message", receiveMessage, false);
function receiveMessage(event) {
chrome.extension.getBackgroundPage().postMessage(event.data, "*");
}
This is triggered by the contentscript like that:
let iframe = document.createElement('iframe');
iframe.setAttribute('src', chrome.extension.getURL('webaccessible/index.html'));
iframe.addEventListener("load", () => {
iframe.contentWindow.postMessage(data);
})
While data is an object that contains the CryptoKey.
This data is received in the background script just like you normally would receive such messages:
window.addEventListener('message',(event) => {
console.log(event);
});

Related

how to pass data to variables in iframe

I am working on project which connects a local server and global server (servers cant communicate) server communicate to html files via socket io
I am very new to this concept
my scenario is
browser connects to local app
local server sends html page which has iframe in it and iframe's source is global server
global server sends html page
my browser is showing html page in the global server and my local server is also running
how can I pass data from local server to global server?
basically local server sends data to container html file and it passes data to the html file in iframe so that it can pass data to global server
maybe a method is called from container html to iframe html and sends data ? is it possible?
hope I made my point clear
please help
What i understood that you need to pass some kind of variable in iframe so you can append your iframe's "src" property with it in the form of querystring.
You can get this querystring value while reloading of iframe.
e.g.
<div class="my-frame-container" myurl="http://myserver.com" elementid="mycontainerframe"><iframe id="myiFrame" src="" allowtransparency="true" width="100%" height="100%" frameborder="0"></iframe></div>
someEvent(e.g.: click)
window.parent.postMessage(
{
event_id: 'reloadMyFrame',
},
"*"
);
and in the iframe js file you can add a event listener
var eventMethod = window.addEventListener ? "addEventListener" :
"attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" :
"message";
eventer(messageEvent, function (e) {
var eventId = e.data["event_id"];
if(eventId==="reloadMyFrame")
{
var container = $('.my-frame-container');
var frameSrc = container.attr('myurl');
$('#myiFrame').attr("src", url);
$('#myiFrame').reload();
}
}
}
The best way is using event bus javascript
//main doc
window.addEventListener("message", receiveMessage, false);
function receiveMessage(event)
{
console.log("main",event);
// ...
}
window.document.getElementById("iframe").contentWindow.postMessage('test', *);
//iframe
window.addEventListener("message", receiveMessage, false);
function receiveMessage(event)
{
console.log("iframe",event);
// ...
}
window.parent.postMessage('test', *);
be aware of CORS problematic
https://developer.mozilla.org/docs/Web/API/Window/postMessage
More complet exemple
post message works fine but instead of post message you can call methods inside frame like an instance
$('#myIFrame').on('load',()=>{
let q = document.getElementById("myIFrame").contentWindow
q.method() // a method inside iFrames js
})
and you can call method from inside iFrame to main like
window.top.method();
BUT it will get caught on Uncaught DOMException: Blocked a frame with origin () from accessing a cross-origin frame. if you disable-web-security it will work fine

Access an Iframe variable from parent window

I have a webpage at url https://parent.com and it has an iframe injected into it with source https://iframe.com. Iframe has a global variable defined called iframe_variable. I want to access the iframe_variable from parent document.
I know browsers don't allow cross origin communication and they provide a postMessage API to do it securely.
Constraint: I do not have access to any of parent or iframe code.
On Browser console, I somehow want to access iframe_variable
I have tried the following:
Get reference of iframe first.
var iframe = document.getElementsByTagName('iframe')[0]; // There is only one iframe on document
Create a listener for message event posted from parent window.
var iframeListener = function(e) {
console.log("Got message from parent");
e.source.postMessage(JSON.stringify({'IFRAME_VARIABLE': window.IFRAME_VARIABLE}));
}
Create a listener for parent window to accept 'message' posted from iframe.
parentListener = function(e) {
console.log('Got message from iframe');
var data = JSON.parse(e.data);
window.VARIABLE = data.IFRAME_VARIABLE;
}
Attach parent_listener to message event.
window.addEventListener('message', parentListener, false);
Now if i try to post a message to iframe from parent as follows:
iframe.contentWindow.postMessage('test message', '*')
It doesn't trigger 'iframeListener'. The reason is because it is not registered against the message event in iframe.
I don't think I can even do that from the browser console when I am on parent.com as any attempt to do iframe.contentWindow.addEventListener will result in an error as it will be an attempt to access a different domain.
Is there a workaround that? Is there anything that I am missing in my understanding and research.
P.S: I have not written the origin checks for simplicity. I know I must check for the origin a message is posted from. Not doing that leaves a huge security hole.

Send a message from an iframe on the main page

I have seen from this documentation: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage , the way to pass a data correctly to an iframe. But now I want to send an answer:
//from main page
myIframe.contentWindow.postMessage('send me a response', '*');
//from iframe of main page
window.addEventListener("message", receiveMessage, false);
function receiveMessage(event){
alert(event.data);//the value of message
//now i need to send an answer 'this is a response'
}
}
How do I send an answer to the main page from the iframe?
I need really of this answer.
Edit:
Ok i found the solution ty at all.
You have access to the parent window on the global window.parent.
I believe it is as easy as using this object's method at this point to postMessage. So something like:
var parent = window.parent;
parent.postMessage("some message");
A full example can be found here.
The gist is the window.parent.postMessage() function takes the following arguments: otherWindow.postMessage(message, targetOrigin, [transfer]);
I would consider using easyXDM
EasyXDM WebSite

How can I get the previous URL of a tab?

When writing a Chrome extension, given a tab, how can I get the URL of the previously-visited page in that tab? i.e. the url that will appear in the omnibar after I hit "back"?
Since I could not find any API approach, I just applied vux777's suggestion above: every time a page loads I store a mapping from its id to its URL. Then when I want to find the previous page of a tab, I can search for it there.
So, storage:
chrome.webNavigation.onCommitted.addListener(function (data) {
if (data.frameId !== 0) {
// Don't trigger on iframes
return;
}
var tabIdToUrl = {};
tabIdToUrl[data.tabId.toString()] = data.url;
chrome.storage.local.set(tabIdToUrl);
});
And retrieval:
chrome.storage.local.get(tabId, function (item) {
var url = item[tabId];
...
});
I am running into the same issue, really wished that chrome api could return both the before and after url at chrome.tabs.onUpdated event.
My solution is similar to #Oak, but instead of using chrome.storage.local I am using Window.sessionStorage due to the following two reasons:
chrome.storage.local behaves similarly to Window.localStorage, it persists even when the browser is closed and reopened. If you don't do cleanup yourself, your local storage will grow overtime with a lot of redundant information. With session storage, whenever you closed all of your browser instances (end of persistent background page's lifetime). it will conveniently forget everything :)
Window.sessionStorage stores data in strings only, which is good for this use case (tab.url), chrome.storage.local is a more powerful tool, you can save some space when you want to store objects.
my test case is something like this:
chrome.tabs.onUpdated.addListener(function(tabId,changeInfo,tab){
var newUrl = changeInfo.url;
if(newUrl){
window.sessionStorage[tabId] = newUrl;
}
});
Another approach uses the referrer of the page. This requires that:
there must be some way to retrieve the page referrer, either by loading a content script into the page that communicates the referrer to the extension, or by somehow inspecting the web navigation or request as it is happening in the background script to retrieve the Referer header (notice the typo)
the page that referred to the current page must have a referrer policy that provides sufficient information
content-script.js
// notify extension that a page has loaded its content script, and send referrer
chrome.runtime.sendMessage({ referrer: document.referrer });
background.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
console.log(sender.tab.id);
console.log(request.referrer);
});
Alternatively, the extension could query a tab to get its referrer. You must ensure the tab is ready (has a loaded content script):
content-script.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
sendResponse({ referrer: document.referrer });
});
background.js
function askTabForReferrer(tabId) {
chrome.tabs.sendMessage(tabId, {}, function(response) {
console.log(response.referrer);
});
}
const exisitingTabWithLoadedContentScriptId = 83;
askTabForReferrer(exisitingTabWithLoadedContentScriptId);

Injected HTML accessing the Chrome API and global variables

I'm working on a Chrome Extension, and I'm new to the process. The extension I'm working on injects an HTML sidebar into the page, injects java-script functions to the header, then let's the user press the buttons on the sidebar to create/save my extension's data.
However, when I want to save the information, I use localStorage, however, the localStorage always saves with respect to the current website. How can I use localStorage to save with respect to our extension?
Furthermore, I would like to use some global javascript variables in the chrome-extension. Where do these belong? I know I can't currently access them from the injected Javascript.
I've looked into message passing, and I've had some trouble with it. I'm not sure how it works in the scope of injected javascript into a page's header. I've tried working with this example, but my extension doesn't seem to catch the message.
// This function is called in the injected header javascript.
function sendToExtension() {
setTimeout(function() {
console.log('page javascript sending message');
window.postMessage({ type: 'page_js_type',
text: "Hello from the page's javascript!"},
'*' /* targetOrigin: any */);
}, 10);
}
// This is installed in a background script.
window.addEventListener('message', function(event) {
console.log('content_script.js got message:', event);
});
You have to use Chrome's sendMessage function and onMessage listener. See below:
function sendToExtension() {
console.log('Sending message');
chrome.runtime.sendMessage({ext: "myExtension"}, function(response) {
console.log(response.ack);
});
}
// Listener - Put this in the background script to listen to all the events.
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.ext) {
console.log('Message received from ' + request.ext);
sendResponse({ack:'received'}); // This send a response message to the requestor
}
});

Categories

Resources