Message Passing Example From Chrome Extensions - google-chrome-extension

I'm using the example from the Google tutorial and finding it difficult to pass a simple message to the content script from the popup.
Can you provide some suggestions on how to pass a simple message and view it either in the console log or alert?
manifest.json
{
"manifest_version": 2,
"name": "msg-test",
"description": "message test",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"background": {
"scripts": ["background.js"],
"persistent": true
},
"content_scripts": [{
"matches": ["http://*/*","http://www.site.com/*"],
"js": ["content.js"],
"run_at": "document_end"
}],
"permissions": [
"tabs",
"http://*/*"
]
}
background.js
chrome.runtime.onConnect.addListener(function(port){
port.postMessage({greeting:"hello"});
});
content.js
var port = chrome.runtime.connect({name:"content"});
port.onMessage.addListener(function(message,sender){
if(message.greeting === "hello"){
alert(message.greeting);
}
});
popup.js
window.onload = function() {
document.getElementById('btn2').onclick = function() {
alert("button 2 was clicked");
};
document.getElementById('btn1').onclick = function() {
alert("button 1 was clicked");
};
}
*Note: In this example the content script will fire when the page matches manifest.json and the alert box will show.

First, I wouldn't message pass between your popup and your content script. I would message pass between your Background page and your content scripts. Your popup page should only be used to show some ui to interact with your app.
With that being said, I will show you the way to pass messages between your background and your content script.
In your content script:
//This line opens up a long-lived connection to your background page.
var port = chrome.runtime.connect({name:"mycontentscript"});
port.onMessage.addListener(function(message,sender){
if(message.greeting === "hello"){
alert(message.greeting);
}
});
In your background page(possibly your popup? but I don't recommend it)
chrome.runtime.onConnect.addListener(function(port){
port.postMessage({greeting:"hello"});
});
Here is the sequence of events that will take place:
Your application will inject your content script into the page
Your content script will open up a port to communicate with the background script.
Your background script will be notified that a port was open, allowing it to send a message to it, or attach a message listener to it.
In the background script or the content script, you can listen for messages by using port.onMessage.addListener(). provided that port is in scope. Using ports is much easier to grasp and allows for simple, two way communication!
Edit:
If you would like to pass messages to your background page from your popup script, use the exact same method:
var port = chrome.runtime.connect({name: "popup-port"});
port.postMessage({status:"poppedup"});
Edit 2:
To navigate your user to a new page, do this:
function navigateToPage(url){
chrome.tabs.query({url: url}, function(tabs) {
var tab = tabs[0];
return tab ? chrome.tabs.update(tab.id, {active:true}) : chrome.tabs.create({url: url});
});
}
});
What this function does is, it checks to see if there is a tab with the url you want to go to, if there is, switch to it, else, create a tab with that url and navigate to it.

Related

Can you write a Chrome extension that runs nothing unless the devtools panel is open? [duplicate]

I have a new browser extension I'm developing, which means that to make it publicly available on the Chrome Web Store, I must use manifest v3. My extension is a DevTools extension, which means that to communicate with the content script, I have to use a background service worker to proxy the messages. Unfortunately, the docs on DevTools extensions haven't been updated for manifest v3, and the technique they suggest for messaging between the content script and the DevTools panel via the background script won't work if the background worker is terminated.
I've seen some answers here and Chromium project issue report comments suggest that the only available workaround is to reset the connection every five minutes. That seems hacky and unreliable. Is there a better mechanism for this, something more event based than an arbitrary timer?
We can make the connection hub out of the devtools_page itself. This hidden page runs inside devtools for the current tab, it doesn't unload while devtools is open, and it has full access to all of chrome API same as the background script.
manifest.json:
"devtools_page": "devtools.html",
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["content.js"],
"run_at": "document_start"
}]
devtools.html:
<script src="devtools.js"></script>
devtools.js:
let portDev, portTab;
const tabId = chrome.devtools.inspectedWindow.tabId;
const onDevMessage = msg => portTab.postMessage(msg);
const onTabMessage = msg => portDev.postMessage(msg);
chrome.runtime.onConnect.addListener(port => {
if (+port.name !== tabId) return;
portDev = port;
portDev.onMessage.addListener(onDevMessage);
portTab = chrome.tabs.connect(tabId, {name: 'dev'});
portTab.onMessage.addListener(onTabMessage);
});
// chrome.devtools.panels.create...
panel.js:
const port = chrome.runtime.connect({
name: `${chrome.devtools.inspectedWindow.tabId}`,
});
port.onMessage.addListener(msg => {
// This prints in devtools-on-devtools: https://stackoverflow.com/q/12291138
// To print in tab's console see `chrome.devtools.inspectedWindow.eval`
console.log(msg);
});
self.onclick = () => port.postMessage('foo');
content.js:
let portDev;
const onMessage = msg => {
console.log(msg);
portDev.postMessage('bar');
};
const onDisconnect = () => {
portDev = null;
};
chrome.runtime.onConnect.addListener(port => {
if (port.name !== 'dev') return;
portDev = port;
portDev.onMessage.addListener(onMessage);
portDev.onDisconnect.addListener(onDisconnect);
});
P.S. Regarding the 5-minute timer reset trick, if you still need the background script to be persistent, in this case it is reasonably reliable because the tab is guaranteed to be open while devtools for this tab is open.

chrome-extension: How to detect and retrieve url from tab when redirect happens?

Just started on chrome - extension development. I'm trying to retrieve the url from a newly created tab but my expected url comes from the server as response with 302 status code and browser redirects to it. I tried with chrome.tabs.onUpdated.addListener() but its not detecting the URL with 302. I searched in chrome.tabs API and i don't see any events for redirect. What is the best way to detect if any redirection is happening in the tab and get the url from that object?
My use case is, when user clicks on one button, it opens a new tab with a specific url and since this url is SSO protected which will go through SSO dance and finally goes to target page.During SSO dance there are 3 redirects happening before serving the target page and i'm trying to detect and retrieve one of the url in the redirect process.
P.S: This is my first question and i'm excited to be part of this community. Thanks in advance.
Update1: I tried with chrome.webRequest.onBeforeRedirect.addListener
manifest.json
{
"name": "CatBlock",
"version": "1.0",
"description": "I can't has cheezburger!",
"permissions": ["alarms", "webRequest", "webRequestBlocking", "activeTab", "tabs",
"https://*/*"],
"background": {
"scripts": ["background.js"]
},
"manifest_version": 2
}
background.js
chrome.webRequest.onBeforeRequest.addListener(
function(info) {
console.log("Cat intercepteddd: " + info.url);
});
chrome.webRequest.onBeforeRedirect.addListener(
function(info) {
console.log("Cat intercepteddd: " + info.url);
});
chrome.webRequest.onResponseStarted.addListener(
function(info) {
console.log("Cat intercepteddd: " + info.url);
});
const responseListener = function(details) {
const headers = details.responseHeaders;
for (let i = 0; i < headers.length; i++) {
if (headers[i].name == "location") {
console.log("redirectURL:" + headers[i].value);
}
}
return { responseHeaders: newHeaders};
};
chrome.webRequest.onHeadersReceived.addListener(
responseListener,{urls: [URL_TO_DETECT]}, ["blocking", "responseHeaders"]);
Usually 303 redirects will be caught on the response headers, use the above code to get the redirect url from response header, make sure to have the code in background.js

Getting basic message passing to work in Chrome extension

I'm trying to get basic message passing to work in a Chrome extension. There are a number of related questions on SF on this (most notably here: Basic google chrome extension message passing not working), but unfortunately the advice there seems not to work for me.
Here's my manifest.json file:
{
"name": "Steve Screenshot",
"description": "Do something",
"version": "0.1",
"manifest_version": 2,
"content_scripts": [
{
"matches" : ["*://*/*"],
"js": ["simple.js"]
}
]
}
And my simple.js file:
chrome.runtime.onMessage.addListener(function(request, sender, callback) {
console.log('message received');
});
// Invoke it!!!
chrome.runtime.sendMessage({
msg: 'whatever'
}, function(response) {
console.log('message sent');
});
At runtime, the console log shows the "message sent" message but NOT the "message received" message. To the best of my understanding, I am ?correctly? invoking chrome.runtime.onMessage/sendMessage. Can anyone comment?
Thanks,
--Steve
The problem is that you are trying to use chrome.runtime.sendMessage to send a message to a content script. You cannot send messages to content scripts using runtime.sendMessage, you must use tabs.sendMessage. (Read about that here).
A good setup for message passing is to use a background page as sort of a 'router' for your messages. When you need to pass a message to content scripts you do so from the background page using the tabs api. For a simple test, you could add a tabs.query call in the background script to send a message to ALL content scripts like so:
chrome.tabs.query({}, function(tabs) {
for(var i = 0; i < tabs.length; i++) {
chrome.tabs.sendMessage(tabs[i].id, {msg: 'whatever'});
}
}
To send messages to individual content scripts will require some additional logic but is very doable (one way is to maintain some associative queue structure in the background page).
Also, note that you can use chrome.runtime.sendMessage from inside a content script, but this will send a message to event listeners in your extension that are not inside content scripts. (So you can send a message to the background page using this method)

http requests not working chrome extension

I am developing a chrome extension that requires corss domain XHR. So I need to make get requests to a server and get some text out of it. I am currently loading the unpacked extension from my computer. The script doesn't seem to be working.
Here is my manifest.json:
{
"name": "My extension",
"version": "1.1",
"manifest_version": 2,
"description": "Testing http requests",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"http://*/"
]
}
And here is the script that performs the get request (from this tutorial):
function showresponse(){
var query = document.getElementById("query").value;
var url = "http://blah.com/search.php?term="+query;
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
console.log("hello world");
document.getElementById("container").innerHTML = xhr.responseText;
}
}
xhr.send(null);
}
The id's etc are set according to my popup.html file and that's set up correctly and it includes this js file containing the showresponse() function definition.
I also tried packaging my extension to get a myextension.crx file after reading this question and I tried opening the file in my browser, but chrome doesn't allow installing the extension from localhost or unknown servers for security reasons I suppose.
My question is how do I make a cross domain XHR in a chrome extension?
Also the response from the get request to the server is actually an html document and I need to filter some text out of the returned html tags. As I am making a query to a php script, can I receive and therefore play around with the html output if I make a get request in javascript?
How do I go about acheiving this?

Change the URL in chrome after the page has loaded

I've written the following script to change the URL of a tab in Chrome, but can't figure out how to get it to automatically run on every page.
var nytimes = /.*nytimes\.com.*/;
var patt = /(&gwh=).*$/;
function updateUrl(tab){
if(tab.url.match(nytimes))
{
var newUrl = tab.url.replace(patt,"");
chrome.tabs.update(tab.id, {url: newurl});
}
}
chrome.tabs.onUpdated.addListener(function(tab) {updateUrl(tab);});
I put that into my background page, but it isn't working. Do I need to put the code somewhere else to get it to run?
I strongly suggest you read about content scripts. They are exactly what you're looking for but you need to understand that they have limited access to the Chrome.* API, so you'll have to use message passing in order to use your current functionality. However, by using content scripts you can probably make this simpler using one of my proposed solutions.
Solution 1
Assuming you want to send the redirect to the same URL every time, you can easily configure your extension to only run your content script on the NY Times site. For example;
Content Script: content.js
location = 'http://example.com';
Solution 2
However, if the redirect URL can vary you many want to abstract that logic in to your background page. For example;
Content Script: content.js
// Or you can pass a more specific section of the URL (e.g. `location.pathname`)
chrome.extension.sendRequest({href: location.href}, function(data) {
location = data.url;
});
Background Page: background.js
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
sendResponse({
url: getUrl(request.href) // TODO: `getUrl` method containing your logic...
});
});
Important!
Regardless of which approach you go for you will also need to request permission to run the content script on the target site in your manifest file.
Manifest: manifest.json
{
...
"content_scripts": [
{
"js": ["content.js"],
"matches": ["*://*.nytimes.com/*"],
"run_at": "document_start"
}
],
...
}

Resources