Execute Script of Chrome extension only once - javascript

I've made a Chrome script that modifies a specific login Page. It works as expected, but I can see in the console that it is always active, although it should only be applied on the login site.
My manifest file:
{
"manifest_version": 2,
"name": "Login Enhancer",
"description": "Login without a hassle",
"version": "1.0",
"icons": {
"16": "icon16.png",
"48": "icon48.png",
"128": "icon128.png"
},
"permissions": [
"https://*.examplesite.io/subdomain/portal/#/login"
],
"background": {
"scripts": [
"background.js"
]
}
}
background.js:
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
if (changeInfo.status == 'complete' && tab.active) {
chrome.tabs.executeScript(null, {file: 'script.js'});
}
});
script.js
// delete useless Remember Me Function
document.querySelector('.remember-me').remove();
After I've logged in when I'm browsing on examplesite.io/subdomain the console says on every new page:
Uncaught TypeError: Cannot read property 'remove' of null
at script.js:2
Obviously there is no more remember-me button to remove. This has probably to do with the Listener in my background.js File. What is the correct listener so the script.js is only executed once on https://*.examplesite.io/subdomain/portal/#/login and not everywhere on https://*.examplesite.io?

For what you have shown in the question, the best way to do this is to use a content_scripts entry in your manifest.json to load your content script instead of using chrome.tabs.executeScript() to do so. Doing it as a content_scripts entry will inject the script once whenever the specified page is loaded. It is significantly less complicated than using chrome.tabs.executeScript() for the purpose of loading a script when a URL matches a certain page. In general, chrome.tabs.executeScript() should be used when the interaction with the user begins with the user clicking on a browserAction or pageAction button (which you are not using), or when you want more detailed control over when the script is injected other than always once for pages matching a specific URL, or URL pattern (which you don't need for what you are doing).
In your case, you are wanting to inject the script once, every time a specific URL is loaded. This is exactly the use case for which the content_scripts key in manifest.json exists.
Given that your background script was doing nothing other than loading your content script, using a content_scripts entry means you do not need a background script. In addition, you don't need to explicitly specify permissions for that particular URL. Your extension is implicitly given permissions for the URLs which match the content_scripts matches key.
You could do this by changing your manifest.json to:
{
"manifest_version": 2,
"name": "Login Enhancer",
"description": "Login without a hassle",
"version": "1.0",
"icons": {
"16": "icon16.png",
"48": "icon48.png",
"128": "icon128.png"
},
"content_scripts": [
{
"matches": ["https://*.examplesite.io/subdomain/portal/#/login"],
"js": ["script.js"]
}
]
}

Related

Are there any suitable APIs in writing chrome extension to download images behind cookie authentication?

I am writing a Chrome extension which let me grab image links and download them on certain web pages. So if the images need basic authentication, for example username and password login, even I have already successfully logged in and got the correct image's url, my codes still can only download a 'protective' picture instead the right one as If I were logged out. Please let me know how can I get the correct one ?
I have tried several ways to achieve this:
Use chrome.downloads.download and it just gives me above result.
Then I tried to bind a header which contains cookie I successfully logged in with, result remains same. I also got an error in Chrome extension, which says Unchecked runtime.lastError: Unsafe request header name. I guess this is not allowed in such situation.
Besides chrome.downloads.download, I also tried chrome.downloads.onDeterminingFilename which gives me same result.
background.js
chrome.pageAction.onClicked.addListener(function() {
let scriptCode =
`(function() {
return document.cookie;
})();`
chrome.tabs.executeScript({code: scriptCode}, function(cookies_result){
chrome.downloads.download({
url: "http://www.sample.com/abc/sample.jpg",
filename: "Pictures/new.jpg",
conflictAction: 'overwrite',
headers: [
{name: "Cookie", value: cookies_result[0]},
],
});
});
});
manifest.json
{
"name": "Batch Save",
"version": "0.1",
"manifest_version": 2,
"description": "Save multiple items",
"page_action": {
"default_title": "batch save images to ...",
"default_icon": {
"16": "images/save_16.png",
"32": "images/save_32.png",
"48": "images/save_48.png",
"128": "images/save_128.png"
}
},
"icons": {
"16": "images/save_16.png",
"32": "images/save_32.png",
"48": "images/save_48.png",
"128": "images/save_128.png"
},
"permissions": [
"activeTab",
"declarativeContent",
"storage",
"downloads",
"cookies"
],
"background": {
"scripts": ["src/background.js"],
"persistent": false
}
}
So I expect to use the API to download the correct image (in above instance http://www.sample.com/abc/sample.jpg, 300kb) when I have already logged in, not the wrong one(could be another smaller icon, like 1.gif, 50kb) which is shown for guests who are not logged in.
And also, since desired images are already displayed in browser, which means they are already transmitted and stored in some places (at least cache), is it possible to copy or save from somewhere locally or may grab the images on the fly while they arriving as binary data then save them, which avoids requesting other time on backend?

Content script not listening to message event

I am developing my first browser extension for my website.
What this extension should basically do is to have a browser action which opens a pop-up where you can edit specific cookie values for the current page.
However, cookie A can exist on the page / while cookie B can exist on the page /checkout. So I don't want to list every cookie inside the pop-up, only the one which is active on the current page.
So, I searched the documentation and found that in order to communicate between web page and add-on you have to use the message system as described here
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#Communicating_with_the_web_page
To do so, my website has a JavaScript file which is loaded on every page. In this JavaScript I'm executing the following code
window.postMessage({type: 'FROM_PAGE', data: visibleCookies}, '*');
This piece of code is definitely executed, because I put a console.log before or after that statement, I can see that it's being logged.
Now, in my content script I want to listen to this by executing the following code
// experimentManager.js
console.log('testd');
window.addEventListener('message', (event) => {
console.log(event);
if (event.source !== window) {
return;
}
});
However, the console.log(event); is never executed. The listener is never activated. When I press the browser action so that the popup opens testd is logged into console, but still, the listener doesn't get any events. It's just not getting executed.
I don't know which files are relevant, but this is my manifest.json
// manifest.json
{
"manifest_version": 2,
"name": "My first addon",
"version": "1.0",
"description": "My first addon description",
"icons": {
"48": "icons/icon.png"
},
"browser_action": {
"default_icon": "icons/icon.png",
"default_title": "My first addon",
"default_popup": "popup/manage_experiment.html",
"browser_style": true
},
"permissions": [
"tabs",
"cookies",
"<all_urls>"
],
"content_scripts": [
{
"matches": ["*://*.mydomain/*"],
"js": ["experimentManager.js"]
}
]
}
And inside the pop-up script I'm executing this code among other things
browser.tabs.executeScript({file: "/content_scripts/experimentManager.js"})
.then(manageExperiments)
.catch(handleError);
which is probably the reason why the console.log('testd') gets executed, but nothing else?
What am I missing?

Content script not executing in new window

I am trying to create a Chrome extension that, when clicked, opens a new incognito window and performs some DOM action on it. These are the files I'm using:
manifest.json
{
"manifest_version": 2,
"name": "SampleExtension",
"description": "",
"version": "1.0",
"incognito": "spanning",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["http://www.google.com"],
"js": ["myscript.js"]
}
],
"permissions": [
"tabs",
"activeTab",
"http://www.google.com"
]
}
popup.js
chrome.windows.create({
"url": "http://www.google.com",
"focused": true,
"incognito": true
});
chrome.tabs.executeScript(null, {
"file": "myscript.js",
"run_at": "document_end",
"all_frames": true
});
myscript.js
document.querySelector('a[target]').click();
The extension opens the new window, but my content script doesn't seem to be executing. Any thoughts?
Edit: Added "incognito": "spanning" to the manifest. Still doesn't work, however.
First of all, I understand that you have enabled to run in Incognito Mode. Extensions are disabled by default and, hence, it would not run otherwise.
Secondly, your match pattern needs to end with a slash:
"matches": ["http://www.google.com/"],
Thirdly, Google will redirect you to its https version, hence I would improve the match pattern like this:
"matches": ["*://www.google.com/"],
Still, it didn't work for me as I was redirected to my local Google domain. Hence, I had to do add more:
"matches": [
"*://www.google.com/*",
"*://www.google.com.sg/*"
],
Also, I added the final wildcard, because Google was adding some ?urlParams that I had to match too. And this made it work. Note that I tried with other pages like "*://www.stackoverflow.com/*", and it was easier than Google :)
In case your Google page was just a test, I'd advise to use some less redirected pages to test with.
A final note: I do not think it's possible to use the wildcard for the domain (I tried). However, you can request all the main domains, or request all_pages and then add the logic for Google only on my_script.js to decide whether to execute the action or not. (However, this last piece is not ideal).
Edit post comments:
It seems your function fails because the element is not loaded yet. An easy way to solve this is by doing an interval which checks whether the element is on the page. When it finds it, clicks it and removes the interval.
// Function which clicks element if existing and clears interval after doing it.
var clickLink = function() {
if (document.querySelectorAll('a[target]').length > 0) {
clearInterval(waitAndClick); // stop interval
document.querySelector('a[target]').click(); // click element.
}
}
// Run click function every second, until it clicks it.
var waitAndClick = setInterval(clickLink, 1000);

Chrome extension inject js

I want to create a new chrome extension but it don't work.
I want to inject a js file into web page (all web page,not only one.If i push the chrome icon on google the script must execute,if i push the icon on facebook it must execute ect.)
this is background.js
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript({
null,{file: "backgrounds.js"} });
});
this is backgrounds.js
document.body.innerHTML="display div elem with style and id";
this is manifest.json
{
"name": "MyExt",
"description": "an extension,what else?",
"version": "1.0",
"permissions": [
"activeTab"
],
"content_scripts": [
{
"matches": ["http://*/*"],
"js": ["background.js"]
}
],
"browser_action": {
"default_title": "myExt"
},
"manifest_version": 2
}
what i wrong?
I'm on windows 8.1 Update 1 with chrome last version
Your manifest is wrong: you should set background.js as your background script:
"background" : { "scripts" : [ "background.js" ] },
and remove the "content_scripts" section.
The "activeTab" permission means that you don't need to specify host permissions to inject in the current tab upon browser action click, so no other permissions are needed.
The tabId argument is optional, you can just drop it instead of passing null. And your invocation is wrong (you're wrapping two arguments in a single object). Here's the correct way:
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript({file: "backgrounds.js"});
});

Chrome executeScript function not working

So I have an extension I'm writing and I'm trying to execute a script when the user clicks on the pageAction icon. When the icon is clicked, the method calls chrome.tabs.executeScript(...). The problem is that the chrome.tabs.executeScript function is not executing and I can't tell why. I know that I'm getting to the code where it calls executeScript because I have an alert there that appears. Here is some of my code:
manifest.json
{
"manifest_version": 2,
"name": "name here",
"description": "description here",
"version": "0.1",
"permissions": [
"<all_urls>",
"tabs"
],
"icons": {
"16" : "images/icon16.png",
"48" : "images/icon48.png",
"128": "images/icon128.png"
},
"background": {
"scripts": ["js/check.js"]
},
"page_action": {
"default_icon": {
"19": "images/icon19.png",
"38": "images/icon38.png"
},
"default_title": "default title here"
}
}
js/check.js
chrome.tabs.onUpdated.addListener(checkForValidUrl);
function checkForValidUrl(tabId, changeInfo, tab) {
if (tab.url.indexOf('g') > -1) {
chrome.pageAction.show(tabId);
}
};
chrome.pageAction.onClicked.addListener(function(tab) {
alert("hello world"); //this code is executed...
//...this code is not
chrome.tabs.executeScript(tab.id, {file: "save.js"}, function() {
if(chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message);
}
});
});
js/save.js
alert("hello world");
Like I say in the code, the hello world in my pageAction onClick function works. The executeScript method does not. Any idea about what is going on would be helpful.
After messing around with lots of different things in my code, I've found the solution to my problem. The error seems to be in the line that says {file: "save.js"}. When it's looking for save.js, it's apparently looking in the top directory, where my manifest.json file is located, not in the directory that my code is in. I had to change my code to {file: "js/save.js"} in order for my save.js file to be found.
According to the docs:
To insert code into a page, your extension must have cross-origin permissions for the page. It also must be able to use the chrome.tabs module. You can get both kinds of permission using the manifest file's permissions field.
So you need a permission for the site, i.e. http://example.com/ in the permission field.

Categories

Resources