error while sending message from extension script to content script - google-chrome-extension

extension script:
$(document).ready(function() {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id,{"askDomain":true},function(response) {
if(response.domain) {
console.log(response.domain);
populateExtension(response.domain);
}
});
});
});
content script:
chrome.runtime.onMessage.addListener(["askDomain"],function(request,sender,sendResponse) {
console.log("asking domain");
if(request.askDomain) {
// sendResponse({"domain":window.location.href});
}
});
I am sending message from extension scrip to content script. When the page loads I receive this error on the content page console:
extensions::event_bindings:266Uncaught Error: This event does not support filters.
What am i doing wrong?

Related

Background script: Error: Could not establish connection. Receiving end does not exist

I am trying to send a message from background script to content script in my chrome extension. But it looks like the message gets send before the content script is loaded?
This is the error I get when I am using my extension normally:
Uncaught (in promise) Error: Could not establish connection. Receiving end does not exist.
This is my background script with the tabs.onUpdated function:
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.url) {
console.log(changeInfo.url, tabId)
chrome.tabs.sendMessage(tabId, {
url: changeInfo.url,
type: 'URL_CHANGE'
});
}
});
This is my content script receive function:
chrome.runtime.onMessage.addListener((obj, sender, response) => {
console.log('received', obj)
if (obj.type === 'URL_CHANGE') {
console.log('testestsetst')
getAuth()
getUrlType(obj.url)
} else if (obj.type === 'AUTH') {
getAuth()
} else if (obj.type === 'UN-AUTH') {
removeAuth()
}
});
Whenever I run the extension normally I don't see an output from my content script and I get the error as stated above. However, when I debug the background script and step through the code, I get no error and my content script prints everything correctly. Could this be due to the page needing to load? And if so, how do I solve this?
Solved it by checking for tab complete and sending the url through the tab parameter as follows:
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.status === 'complete') {
chrome.tabs.sendMessage(tabId, {
url: tab.url,
type: 'URL_CHANGE'
});
}
});
background.js
chrome.runtime.onInstalled.addListener(function (details) {
if (details.reason == "install") {
chrome.tabs.create({ url: chrome.runtime.getURL(`onboard-page.html`) }, function (tab) {
chrome.tabs.onUpdated.addListener(function listener(tabId, changeInfo) {
if (tabId === tab.id && changeInfo.status == 'complete') {
chrome.tabs.onUpdated.removeListener(listener)
// Now the tab is ready!
chrome.tabs.sendMessage(tab.id, "hello")
}
});
});
} else if (details.reason == "update") {
}
});
content-script.js
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse){
console.log(message)
});

Chrome Extension: Check if iframe and current page has loaded

I've built an extension that loads a React-application via an iframe.
I'm passing a message from the application and listening for that message in content script to ensure application has loaded.
Here's a simplified version of what I have so far:
App.js
componentDidMount() {
window.top.postMessage({isAppLoaded: true}, '*'};
}
Content.js
chrome.runtime.onMessage.addListener(function (msg, sender) {
if (msg.isPageLoaded) {
console.log('Current page has loaded!');
}
}
window.addEventListener('message', function(event) {
if (event.data.isAppLoaded) {
console.log('React app successfully loaded!');
}
}
Background.js
chrome.tabs.onUpdated.addListener(function (tabId, info) {
if (info.status === 'complete') {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {isPageLoaded: true});
})
}
})
On some websites the page loads first then the React-app and vice-versa on some other websites. This becomes more complicated with websites that have lots of embedded iframes such as LinkedIn.
What is the correct/better way to guarantee the React-app AND the page has finished loading?
Please ignore the wildcard message passing. I'm aware of its security vulnerabilities. Above code snippets are simplified version of what I have.

chrome.webRequest doesn't catch all requests

I'm writing chrome extension and I need to catch all requests from the beginning of downloading page.
I'm using chrome.webRequest.onBeforeRequest in background.js, and send them to content.js for logging.
But I don't see all requests. It looks like background.js start working with delay (and I missing important requests). How can I avoid it?
Here is my background.js:
chrome.webRequest.onBeforeRequest.addListener(logURL, { urls: ["<all_urls>"] });
function logURL(requestDetails) {
chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
chrome.tabs.sendMessage(
tabs[0].id,
{ message: requestDetails.url },
function(response) {}
);
});
}
and content.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.message == "reload") {
location.reload();
console.log("reload");
} else {
console.log(request.message);
}
});
How can I catch all request or run my background.js previously? Maybe I have made mistakes and can't find them?
Thanks!
If somebody will have the same mistake:
chrome.webRequest catch all requests, but content.js file inject later (after few requests).
So you should collect requests in background.js and send them after content.js injection (for example you can send a message to background.js).

How to send responses from onMessageExternal Listener?

I am sending a message from a content script to my extension using chrome.runtime.sendMessage.
Content Script:
chrome.runtime.sendMessage(extensionId, {
"some" : "request"
}
},
function(response) {
alert("got response");
}
);
The receiving part in the background script looks like that:
Background Script A
chrome.runtime.onMessageExternal.addListener(function(request, sender, sendResponse) {
console.log("send response");
sendResponse({
"some" : "response"
});
});
This works well: send response is logged to the console of the background page and I receive the alert got response from the content script.
I then introduced some asynchronous JavaScript to the listener:
Background Script B
chrome.runtime.onMessageExternal.addListener(function(request, sender, sendResponse) {
window.crypto.subtle.generateKey({
name: "RSASSA-PKCS1-v1_5",
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: {
name: "SHA-256"
}
}, false, ["sign"]).then(function(keyPair) {
console.log("send response");
sendResponse({
"some" : "response"
});
});
});
here the callback is called regularly (meaning, send response is logged to the console of the background page after completion. The content script however never receives the response (i.e. there is no got response alert).
What am I doing wrong here? Why is the responseCallback called in A but not in B? That's exactly what the callback chain is made for or isn't it?
This seems to be a bug/feature in chrome. Apparently you need to return true, otherwise the message channel will be closed:
https://developer.chrome.com/extensions/runtime.html#event-onMessageExternal
This function becomes invalid when the event listener returns, unless you return true from the event listener to indicate you wish to send a response asynchronously (this will keep the message channel open to the other end until sendResponse is called).
Adding return true; to the background script like this solves the issue:
chrome.runtime.onMessageExternal.addListener(function(request, sender, sendResponse) {
window.crypto.subtle.generateKey({
name: "RSASSA-PKCS1-v1_5",
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: {
name: "SHA-256"
}
}, false, ["sign"]).then(function(keyPair) {
console.log("send response");
sendResponse({
"some" : "response"
});
});
return true;
});

chrome.tabs.sendMessage: “Port error: Could not establish connection. Receiving end does not exist” on cached pages only

I've read through all of the related errors, and I think this case is a bit different. I'm trying to send a message from the background context to a content script. E.g.
chrome.tabs.query({
currentWindow: true,
active: true
}, function(tabs){
chrome.tabs.sendMessage(tabs[0].id, {
name: name,
args: args
}, function(response){
if (!response) return callback('You tried to message a tab that does not exist');
});
});
This will throw a Port error if the open tab was loaded before the extension was installed. To recreate:
Open a new tab and load a web page
Navigate to the extensions tab and reload the local unpacked extension
Navigate back to the web tab and invoke the extension via a Browser Action--it will throw the Port error unless the web page is manually reloaded.
Is there a workaround for this?
Instead of sending a message, programatically insert a content script and use the callback's results:
chrome.tabs.query({
currentWindow: true,
active: true
}, function(tabs) {
chrome.tabs.executeScript(tabs[0].id, {
code: 'location.href',
runAt: 'document_start',
allFrames: false // Run at the top-level frame only to get
// just one result
}, function(results) {
var result = results[0];
console.log(result); // Example
});
});
Instead of specifiying the code in a string, you can also run a file by using file: 'code.js' instead of code: '...'.

Resources