Communication between created Iframe and extension, google chrome extension - javascript

I try to send message from an iframe loaded from my extension to my extension (background script or content script).
The created Iframe is loaded from the extension via a content script.
I am searching for a way to communicate but all my attempts failed...
Manifest.json
{
"author": "***********",
"background": {
"page": "back/background.html",
"persistent": true
},
"browser_action": {
"default_title": "***",
"default_popup": "./popup/popup.html"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["./content/allurls.js"],
"all_frames":true
},
{
"matches": ["<all_urls>"],
"js": ["./banner/confirm_banner.js"]
}
],
"web_accessible_resources": [
"frame.html"
],
"description": "oui",
"manifest_version": 2,
"name": "***",
"permissions": ["tabs"],
"version": "1.0"
}
Confirm_banner.js (load the iframe)
var extensionOrigin = 'chrome-extension://' + chrome.runtime.id;
window.onload = load_iframe();
function load_iframe()
{
if (!location.ancestorOrigins.contains(extensionOrigin))
{
var iframe = document.createElement('iframe');
iframe.src = chrome.runtime.getURL('../frame.html');
iframe.style.cssText = 'position:fixed;top:0;left:0;display:block;' +
'width:100%;height:40px;';
document.body.appendChild(iframe);
}
}
Frame.js (script linked with frame.html)
$(document).ready(function()
{
$('#jamais').click(function()
{
send_message("BANNER", "jamais");
alert("send");
});
});
function send_message(type, data)
{
var msg = {
type: type,
data: data
};
window.postMessage(msg, "*");
}
Handler in allurls.js (content script)
window.addEventListener('message', function(event) {
if (event.data.type && (event.data.type === 'BANNER'))
{
alert("ouimonsieur");
}
});
So the message from iframe.js is well sent (prooved by the alert) but the content script recieve nothing from it, even before the :
if (event.data.type && (event.data.type === 'BANNER'))
Can someone see what is wrong or what other message passing protocol i can use (i also tried with top.window.postmessage) ?

Ty wOxxOm for the answer, i was close :
just replace window by parent in frame.js and all works perfectly.
Because even if the content script run in iframe,
Frame.js is not a content script, it's a iframe script and runs in the context of the extension.

Related

Content script doesn't communicate with background script - chrome extension

I'm trying to send new tab URL from background.js to content.js. The .sendMessage() performs but doesn't get to the content.js
background.js:
chrome.tabs.onUpdated.addListener(
function (tabId, changeInfo, tab) {
if (changeInfo.url) {
chrome.tabs.sendMessage(tabId, {
url: changeInfo.url
})
}
}
);
content.js:
chrome.runtime.onMessage.addListener(function(request, sender, callback) {
console.log('here');
});
manifest.json:
{
"manifest_version": 2,
"name": "Url tracker",
"description": "Track your latest visited URLs",
"version": "0.0.1",
"icons": {
"16": "logo-small.png",
"48": "logo-small.png",
"128": "logo-small.png"
},
"permissions": [
"activeTab",
"tabs"
],
"background": {
"scripts":["background.js"],
"persistent": false
},
"content_scripts": [{
"matches": ["<all_urls>"],
"all_frames": true,
"js": ["content.js"]
}]
}
Content scripts run after DOMContentLoaded by default (it can be changed) but the URL is reported to onUpdated when the tab starts loading i.e. before the content script runs.
The solution is to add a check to skip the first update because it's not needed: an instance of the content script runs in each matching web page and it already knows location.href of its page.
if (changeInfo.url && tab.status === 'complete') {
After you reload your extension on chrome://extensions page (or update it from the web store), all its content scripts get "orphanized" and can't receive messages.
The solution is to re-inject them explicitly.

Going bonkers over this small code, chrome.runtime.onMessage gives undefined, always. What can I do?

I know there are similar questions and I've tried almost everything in them. I'm trying to build a chrome extension and it needs to pass a message from content.js to background.js.
The code:
background.js
var xstext;
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
xstext=request.stext;
});
var wtf = "https://www.google.com/search?q="+xstext;
chrome.commands.onCommand.addListener(function(command) {
if(command=="ntab"){
chrome.tabs.create({ url: wtf});
}
});
content.js
var text = window.getSelection();
var stext=text.toString();
chrome.runtime.sendMessage({stext: stext});
manifest.json
"manifest_version": 2,
"name": "vind",
"version": "1.0",
"description": "Search stuff easily!",
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"content_scripts": [
{
"all_frames": true,
"run_at": "document_start",
"matches": [
"<all_urls>"
],
"js": ["content.js"]
}
],
"browser_action": {
"default_icon": {
"16": "images/icon16.png",
"32": "images/icon32.png"
},
"default_popup": "popup.html"
},
"commands": {
"ntab": {
"suggested_key": {
"default": "Alt+G",
"windows": "Alt+G",
"mac": "Alt+G",
"chromeos": "Alt+G",
"linux": "Alt+G"
},
"description": "New tab for the query"
}
}
}
I want to pass the selected text from content.js to background.js, I have tried adding return: true; in the listener to no avail. I'm getting 'undefined' added to the main string, so nothing seems to get passed. what should I do?
This approach won't work because 1) your content script is saving the text at the moment it runs which happens just one time at page load and 2) since the background script is not persistent it'll unload after receiving a message and xstext will disappear.
Do the reverse: ask the content script when the hotkey is pressed.
background.js, entire contents:
chrome.commands.onCommand.addListener(command => {
if (command === 'ntab') {
chrome.tabs.query({active: true, lastFocusedWindow: true}, ([tab]) => {
if (!tab) return;
chrome.tabs.sendMessage(tab.id, 'getText', text => {
chrome.tabs.create({
url: 'https://www.google.com/search?q=' + encodeURIComponent(text),
});
});
});
}
});
content.js, entire contents:
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg === 'getText' && document.hasFocus()
&& (!document.activeElement || !/^I?FRAME$/.test(document.activeElement.tagName))) {
sendResponse(getSelection().toString());
}
});
P.S. An advanced solution would be to run the content script on demand (using chrome.tabs.executeScript in background.js onCommand listener) so you can remove content_scripts section from manifest.json and use activeTab permission instead.

How to listen for url change with Chrome Extension

I am writing a Google Chrome extension to automate some common tasks. The functionality I want is as follows:
Create a new tab and navigate to my webmail
enter username and password
click "submit" button
Wait until the webmail page appears, and choose the "roundcube" client.
I have completed steps 1,2,and 3 and they work. I am having a lot of trouble trying to listen for the url change after my credentials are submitted so that the function that selects roundcube client can run
I know I can run a script when client selection page appears by adding to my manifest but I want to use "chrome.tabs.executeScript" instead so that roundcube is chosen only if I run the script from the chrome extension and not if I go to client selection page manually.
Here is my manifest.json:
{
"manifest_version": 2,
"name" : "Chrome Autobot",
"description": "This extension will run various automation scripts for google chrome",
"version" : "1.0",
"browser_action" : {
"default_icon" : "icon.png",
"default_popup": "index.html"
},
"permissions": [
"activeTab",
"webNavigation",
"tabs",
"http://*/*",
"https://*/*"
]
}
Here is my chrome script:
jQuery(function($) {
"Use Strict";
var openWebmail = function() {
chrome.tabs.create({
url: 'http://mywebmaillogin.com:2095/'
}, function() {
chrome.tabs.executeScript(null, {file: "scripts/openEmail.js"});
});
chrome.tabs.onUpdated.addListener(function(){
chrome.tabs.executeScript(null, {file: "scripts/openEmail.js"});
alert('i work');
});
};
var init = $('.script-init');
init.on('click', function() {
openWebmail();
});
});
and here is the content script to be executed as a callback of tab creation (when the email login page is fetched and the DOM has loaded), and also when the email credentials are submitted and the client selection page's DOM has loaded (which is not working right now)
var openEmail = function() {
var loc = window.location.href;
if(loc === 'http://mywebmaillogin.com:2095/') {
var submit = document.getElementById('login_submit');
user.value = 'myusername';
pass.value = 'mypassword';
if(user.value === 'myusername' && pass.value === 'mypassword') {
submit.click();
}
else {
openEmail();
}
}
if(loc.indexOf('http://mywebmaillogin:2095/') > -1 && loc.indexOf('login=1') > -1) {
alert('I work');
}
}()
any help would be appreciated... thanks!
As mentioned by #NycCompSci, you cannot call the chrome api from content scripts. I was able to pass api data to content scripts with message passing though, so thought I'd share that here. First call onUpdated in background.js:
Manifest
{
"name": "My test extension",
"version": "1",
"manifest_version": 2,
"background": {
"scripts":["background.js"]
},
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"js": ["contentscript.js"]
}
],
"permissions": [
"tabs"
]
}
background.js
chrome.tabs.onUpdated.addListener(function
(tabId, changeInfo, tab) {
// read changeInfo data and do something with it (like read the url)
if (changeInfo.url) {
// do something here
}
}
);
Then you can expand that script to send data (including the new url and other chrome.tabs.onUpdated info) from background.js to your content script like this:
background.js
chrome.tabs.onUpdated.addListener(
function(tabId, changeInfo, tab) {
// read changeInfo data and do something with it
// like send the new url to contentscripts.js
if (changeInfo.url) {
chrome.tabs.sendMessage( tabId, {
message: 'hello!',
url: changeInfo.url
})
}
}
);
Now you just need to listen for that data in your content script:
contentscript.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
// listen for messages sent from background.js
if (request.message === 'hello!') {
console.log(request.url) // new url is now in content scripts!
}
});
use chrome.tabs.onUpdated
Maifest.json
{
"name": "My test extension",
"version": "1",
"manifest_version": 2,
"background": {
"scripts":["background.js"]
},
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"js": ["contentscript.js"]
}
],
"permissions": [
"tabs"
]
}
contentscript.js
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
alert('updated from contentscript');
});
background.js
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
alert('updated from background');
});
Based on / Thanks to #ztrat4dkyle's answer, what works for me:
manifest.json
{
...
"background": {
"scripts":["background.js"]
},
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"js": ["content.js"]
}
],
"permissions": [
"tabs"
]
}
background.js
chrome.runtime.onInstalled.addListener(function() {
// ...
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
// changeInfo object: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/onUpdated#changeInfo
// status is more reliable (in my case)
// use "alert(JSON.stringify(changeInfo))" to check what's available and works in your case
if (changeInfo.status === 'complete') {
chrome.tabs.sendMessage(tabId, {
message: 'TabUpdated'
});
}
})
});
content.js
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request.message === 'TabUpdated') {
console.log(document.location.href);
}
})

Content script jQuery dynamic include broken?

I don't want to include jQuery on every page by listing it in the manifest
In the console, this works fine, but I can't dynamically include jQuery in a content script
No idea why
Put these two files in a folder (content.js and manifest.json)
Go to chrome:extensions in omnibox (url bar)
Load Unpacked Extension
Select Folder
Go to any page and CMD+Shift+R reload without cache
Check out the console and see jQuery is undefined
content.js
if (document.readyState === "complete") {
appendJQuery();
} else {
document.addEventListener("DOMContentLoaded", appendJQuery);
} function appendJQuery () {
var jq = document.createElement("script");
window.document.querySelector("head").appendChild(jq);
jq.onload = function () {
console.log(typeof $); // $ is not defined ?????
}
jq.src = "https://code.jquery.com/jquery-2.1.1.min.js";
}
manifest.json
{
"manifest_version": 2,
"name": "Sample",
"short_name": "Sample",
"version": "1.1",
"permissions": ["tabs", "http://*/*, https://*/*", "*://*/*", "<all_urls>"],
"content_scripts": [{
"matches": ["*://*/*", "http://*/*", "https://*/*", "file://*/*"],
"js": ["content.js"],
"run_at": "document_start"
}]
}
then jQuery is undefined......... wtf??? anyone know why??

How to Communication with the embedding page Chrome Extension?

I need to implement messaging in the expansion. From content_script`a in background.js looked for a way to exchange documents using window.postMessage () and window.addEventListener (), but the messages are not sent. Through content_script I loaded js code in head.
Here's the code to background.js:
window.addEventListener ("message", function (event) {
  // We only accept messages from ourselves
  if (event.source! = window)
    return;
  if (event.data.type && (event.data.type == "FROM_PAGE")) {
    console.log ("Content script received:" + event.data.text);
    port.postMessage (event.data.text);
  }
}, False);
This in content_script.js:
var s = document.createElement ('script');
s.src = chrome.extension.getURL ('inject.js');
(Document.head || document.documentElement) .appendChild (s);
s.onload = function () {
    s.parentNode.removeChild (s);
};
This in inject.js:
window.postMessage ({type: "FROM_PAGE", text: "Hello from the webpage!"}, "*");
What am i doing wrong?
you should use:
chrome.runtime.onMessage.addListener
and
chrome.runtime.sendMessage
to pass messages between different js components. this answer helped me a lot: Chrome Extension how to send data from content script to popup.html
The basic flow of communication between a webpage and a content script or background script is:
Use content scripts to share DOM with the Web, use window.postMessage to send messages, and content.js uses extended API to forward the message to background.js after receiving the message.
manifest.json
{
"name": "you name",
"description": "you description",
"version": "1.1.0",
"background": {
"scripts": ["background.js"],
"persistent": false
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"all_frames": true
}
],
"manifest_version": 2
}
web.html
<body>
<button id="me">Button</button>
</body>
content.js
window.addEventListener('message', event => {
chrome.runtime.sendMessage(`${event.data} forwarded to the background.js`);
});
document.querySelector('#me').addEventListener('click', () => {
window.postMessage('Message from DOM', '*');
});
background.js
chrome.runtime.onMessage.addListener(msg => console.log(msg));
Long-lived connections
content.js
const port = chrome.runtime.connect();
window.addEventListener('message', event => {
port.postMessage(event.data);
});
document.querySelector('#me').addEventListener('click', () => {
window.postMessage('Message from DOM', '*');
});
background.js
chrome.runtime.onConnect.addListener(port => {
port.onMessage.addListener(msg => {
console.log('msg: ', msg);
});
});
Another way to communicate directly with background.js
manifest.json (add externally_connectable)
{
"name": "you name",
"description": "you description",
"version": "1.1.0",
"background": {
"scripts": ["background.js"],
"persistent": false
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"all_frames": true
}
],
"manifest_version": 2,
"externally_connectable": {
"matches": ["http://localhost/*"]
}
}
web.html
<body>
<button id="me">Button</button>
<script>
// Your extension ID, (pabahpeigkdpglhnjponplchdffchkdj).
document.querySelector('#me').addEventListener('click', () => {
chrome.runtime.sendMessage('pabahpeigkdpglhnjponplchdffchkdj', 'Web Message');
});
</script>
</body>
background.js
chrome.runtime.onMessageExternal.addListener(request => {
console.log('request: ', request);
});

Categories