i'm a user of a site (of which I have no control on) which sometimes presents a redirect loop (page A redirects to B, and B to A). Removing a specific cookie fixes the issue. I'd like to automatize the suppression of that cookie when a direct loop is detected.
I was thinking of developing a small chrome extension for that effect (which would be the first plugin I write). Would that work?
I tried using the webRequest API (onBeforeRedirect), but it doesn't seem to catch the redirect.
Here is my manifest.json:
{
"manifest_version": 2,
"name": "name",
"description": "description",
"version": "1.0",
"permissions": [
"<all_urls>","webRequest","webRequestBlocking"
],
"background": {
"scripts": ["test.js"],
"persistent": true
}
}
And here is my test.js:
var callback = function(details) {
console.log("redirect caught!");
};
chrome.webRequest.onBeforeRedirect.addListener(callback);
What am I doing wrong ?
Related
My chrome extension spawns a temp .html page. I want to manipulate the DOM of the sample.html page that was created, but can't. I can manipulate the DOM for any other page without issue. The problem seems to be with the fact my temp .html page resides within chrome-extension://
Error Message:
Unchecked runtime.lastError while running tabs.executeScript: Cannot access contents of url "chrome-extension://123/sample.html?id=100". Extension manifest must request permission to access this host.
Note: for simplicity sake I provided sample code that exhibits the same Error. Once loaded I can use the key combo to inject a div and some text into any webpage (Mac-> Cmd+Shift+P or PC Ctrl+Shift+P)
I've tried adding all possible permissions and even web_accessible_resources to the manifest.json. (I don't believe this to be the issue). I've tried different ways to inject the code into the sample.html by calling out the specific tabId, activeTab or even setting the tabId to null within the background file. I've read through stackoverflow, googled and looked around but came up short.
manifest.json
{
"manifest_version": 2,
"name": "sample1",
"description": "sample1",
"version": "0.0.1",
"browser_action":
{
"default_title": "sample"
},
"commands":
{
"saveImageCommand":
{
"suggested_key":
{
"default": "Ctrl+Shift+Z",
"mac": "Command+Shift+Z"
},
"description": "Toggle Save Image"
},
"playback":
{
"suggested_key":
{
"default": "Ctrl+Shift+P",
"mac": "Command+Shift+P"
},
"description": "load player Image"
}
},
"permissions": [
"tabs",
"activeTab",
"storage",
"<all_urls>",
"*://*/*"
],
"background":
{
"persistent": false,
"scripts": ["background.js"]
}
,
"web_accessible_resources": [
"chrome-extension://*/sample.html?id=*"
]
}
background.js
chrome.commands.onCommand.addListener(function(command) {
if (command === 'saveImageCommand') {
capturecurrent();
}
if (command === 'playback') {
chrome.tabs.executeScript(null, {
code: 'var divNode = document.createElement("div");divNode.setAttribute("id", "video1Div");var instructions = document.createTextNode("testing");divNode.appendChild(instructions);document.body.appendChild(divNode)'
});
}
});
chrome.browserAction.onClicked.addListener(function() {
chrome.tabs.captureVisibleTab(function(screenshotUrl) {
var viewTabUrl = chrome.extension.getURL('sample.html')
chrome.tabs.create({ url: viewTabUrl });
});
});
sample.html
<html>
<head></head>
<body>
<div id="firstDiv">firstDiv</div>
</body>
</html>
Expected Results:
For me to interact directly with the DOM on the temp sample.html page.
Note:
I don't want to build out buttons for DOM manipulation directly within the sample.html page. That defeats the purpose of this exercise. Esp since I want to use shortcut key combos to call this DOM manipulation (Mac-> Cmd+Shift+P or PC Ctrl+Shift+P)
Actual Results:
I am able to interact with the DOM on any normal website using the shortcut key combo but not the sample.html that URL starts with chrome-extension://
Disclaimer: I am new to JavaScript and I have never developed a Chrome extension before.
I am trying to develop a Chrome extension that runs some JavaScript when the user selects some text on a page, right-clicks, then clicks a context menu button. I have determined (based on running it from the Chrome console) that the JavaScript I've written runs as expected. Now all is left is to make an extension.
I can get the extension to load, and I can get it to appear on the page and to appear to run. However, it doesn't seem to do anything, and the console doesn't return any output. (I read that I can't run inline JavaScript with event pages, hence using addListener.) Have I set up the context menu incorrectly? Is there an error (or several) in my script?
manifest.json
{
"name": "My Extension",
"description": "sample",
"version": "0.0.1",
"permissions": ["contextMenus"],
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"manifest_version": 2
}
background.js
chrome.runtime.onInstalled.addListener(function() {
var context = "selection";
var title = "My Extension";
var id = chrome.contextMenus.create({"title": title, "contexts":[context],
"id": "context" + context});
});
chrome.contextMenus.onClicked.addListener(getSHA);
// Get file path of file to be staged
// Get SHA
function getSHA(){
stagedFile = window.getSelection().toString()
console.log(stagedFile)
baseURL = window.location.href.slice(0, -6);
prNumber = baseURL.slice(-4);
xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.github.com/repos/kubernetes/kubernetes.github.io/pulls/"+prNumber, false);
xhr.send();
json_data = JSON.parse(xhr.responseText);
shaValue = (json_data.head.sha)
console.log("SHA: "+shaValue)
getNetlify;
};
// Get Netlify URL
function getNetlify(){
xhr2 = new XMLHttpRequest();
xhr2.open("GET", "https://api.github.com/repos/kubernetes/kubernetes.github.io/commits/"+shaValue+"/status", false);
xhr2.send();
json_data2 = JSON.parse(xhr2.responseText, function(key, value) { if (key == "target_url" && value.includes("netlify")) { netlifyURL = value; }});
openStaging
};
// Stage file
function openStaging(){
window.open(netlifyURL+"/"+stagedFile)
};
You need to add a "content script" to your manifest.json. That is the kind of code that gets injected into the page to run. The background script didn't have access to the page at all. So, check out the documentation on content scripts. https://developer.chrome.com/extensions/content_scripts
You need to add the following piece to your code to your manifest.json:
"content_scripts": [
{
"matches": ["http://www.google.com/*"],
"css": ["mystyles.css"],
"js": ["myscript.js"]
}
]
With this code, any time the user goes to a site that "matches" the url I provided, then the extension will inject into that page mystyles.css and myscript.js. So... your pattern would be something like http*://*/* . That will inject the script onto any page that the user will go to.
Next, to accomplish what you are trying to accomplish, you don't need a background script. So you can remove that from your manifest.json.
So your manifest.json would look like this:
{
"name": "My Extension",
"description": "sample",
"version": "0.0.1",
"permissions": ["contextMenus"],
"content_scripts": [
{
"matches": ["http://www.google.com/*"],
"css": ["mystyles.css"],
"js": ["myscript.js"]
}
],
"manifest_version": 2
}
Then put your code into the myscript.js file (or whatever you want to call yours), and you should see this start to run on the page.
I am trying to create a chrome extension that will notify me of host/domain changes when I'm testing a specific website. Often links will be present that point towards developer or live environments and I'd like to be warned if I follow one of these links as the websites are often identical.
Edit for clarity: I want it to alert me when a link takes me away from http(s)://example.staging.something.com and ends up on the live site http(s)://www.example.com or the dev site http(s)://example.dev.something.com
So far I have managed to create a script that identifies when I am on a staging url (our test environment) however I've been unable to reverse this logic to give me a warning when I navigate to a url that doesn't contain 'staging'.
My manifest.json
{
"manifest_version": 2,
"name": "A What URL",
"description": "This extension monitors and warns you of domain changes",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"background": { "scripts": ["background.js"],
"persistent": false
},
"permissions": [
"activeTab",
"webNavigation"
]
}
my background.js
chrome.webNavigation.onCommitted.addListener(function(e) {
alert ("you are still on staging!");
}, {url: [{hostContains: 'staging'}]});
I'm sure this is simple but it appears my brain is far simpler!
There are multiple ways to solve your problem.
Use the chrome.webRequest.onBeforeSendHeaders (or .onSendHeaders) event to get notified when a request is sent to your production website, and check whether the Referer header is set to your staging site. This only works if the document referrer is set (this won't be the case if you're navigating from https to http, or if the "noreferrer" referrer policy is set).
In the absence of a referer, use the webNavigation, webRequest and/or tabs APIs to track the navigation state of a page, and do whatever you want when you detect that the transition production -> dev occurs. Implementing this correctly is very difficult.
Here is a sample for the first method:
// background.js
chrome.webRequest.onBeforeSendHeaders.addListener(function(details) {
var referer;
for (var i = 0; i < details.requestHeaders.length; ++i) {
var header = details.requestHeaders[i];
if (header.name.toLowerCase() === 'referer' && header.value) {
referer = header.value;
break;
}
}
if (referer && /^https?:\/\/dev\.example\.com(\/|$)/.test(referer)) {
alert('Navigated from dev to production!');
}
}, {
urls: ['*://production.example.com/*', '*://prod.example.com/*'],
types: ['main_frame', 'sub_frame'] // Track navigations, not img/css/etc.
}, ['requestHeaders']);
Example of manifest.json to test the previous logic:
{
"name": "Detect nav from dev to prod",
"version": "1",
"manifest_version": 2,
"background": {
"scripts": ["background.js"],
"persistent": true
},
"permissions": [
"webRequest",
"*://*/*"
]
}
Unfortunately, you can't "invert" the filter, so you'll have to catch all events and filter in the code.
Here come the Chrome Events. Your code suggests you treat them like DOM events (with the e parameter). Instead, they pass arguments depending on the event in question, sometimes several.
If you look at the documentation, you'll see that the expected callback format is:
function(object details) {...};
Where details will contain, among other things, a url property.
So you'll have:
chrome.webNavigation.onCommitted.addListener(function(details) {
// Regexp matches first "//", followed by any number of non-/, followed by "staging"
if(!details.url.match(/[^\/]*\/\/[^\/]*staging/)) {
alert ("This is no longer staging!");
}
});
Note that this is going to be extremely annoying unless you can turn it off - it will match almost any page, after all.
Adding my final solution as an answer as requested in case anyone else is interested in the future.
Many thanks to both Xan and Rob with the help! If I could tick both I would but in the end I ended up ticking the one that led to my implementation.
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
var queryInfo = {
active: true,
currentWindow: true
};
chrome.tabs.query(queryInfo, function(tabs) {
var tab = tabs[0];
var url = tab.url;
if(!url.match(/[^\/]*\/\/[^\/]*staging/) && changeInfo.status=="complete"){
alert ("WTF!!! " +url);
}
});
});
I'm writing a chrome extension and I want to manage all of the data/variables with chrome storage. From what I understand, I should be able to use chrome.storage across my extension.
I want to set something in browser_action script and then access it in the window created by the background script. The HTML and JS files all have corresponding names.
This is what I have tried with no luck:
//manifest.json
{
"manifest_version": 2,
"name": "extension",
"description": "my extension",
"version": "0.1",
"permissions": [
"tabs",
"storage"
],
"background": {
"scripts": ["background.js"],
"persistent": false
},
"browser_action": {
"default_icon": {
"38": "images/icon38.png"
},
"default_popup": "settings.html"
}
}
//background.js
chrome.windows.create({'url': chrome.extension.getURL("newPage.html"),'type': "detached_panel",'focused': true}, function(){
//created newPage.html which has newPage.js
});
//setting.js
document.addEventListener('DOMContentLoaded', function(){
chrome.storage.local.set({'enabled': 'TRUE'});
});
//newPage.js
chrome.storage.local.get('enabled', function(result){
document.getElementById("myId").innerHTML += "<br>script loaded... and status: " + result.enabled;
});
When I do this, newPage.html displays "script loaded... and status: undefined".
Even with it being asyncronous, the storage value should be populated on running the script a second time, right?
I may just be using this incorrectly. If that's the case, what's the correct way to set something with chrome storage to access in my new window?
Any help would be appreciated!
I think that your newPage.html is asking for the value of 'enabled' before it's been set by the event handler in settings.html, which only executes after you've actually opened the browser popup. So this is why it's undefined. Open the popup and you should see that it's defined.
So i'd like to run a script when the tab reloads in a specified URL. It almost works, but actually id doesn't :)
This is my manifest file:
{
"manifest_version": 2,
"name": "Sample Extension",
"description": "Sample Chrome Extension",
"version": "1.0",
"content_scripts":
[
{
"matches": ["http://translate.google.hu/*"],
"js": ["run.js"]
}
],
"permissions":
[
"activeTab",
"tabs"
],
"browser_action":
{
"default_title": "Sample",
"default_icon": "icon.png"
}
}
and this is run.js:
chrome.tabs.onUpdated.addListener(
function ( tabId, changeInfo, tab )
{
if ( changeInfo.status === "complete" )
{
chrome.tabs.executeScript( null, {file: "program.js"} );
}
}
);
The programs.js just alerts some text (yet). When I put an alert to the first line of the run.js, it alerts, but when I put it in the if, it doesn't. I can't find the problem. Did I type something wrong?
Assuming that http://translate.google.hu/* pages are the ones you wish to inject code into on reload, you would have to go about it in a slightly different way. Currently you are always injecting code into those pages (without the permission to do so, no less) and then trying to use the chrome.tabs api inside that content script, which you can't do. Instead, we will put the listener in a background page and inject the code only on a page refresh, like you want. First the manifest:
{
"manifest_version": 2,
"name": "Sample Extension",
"description": "Sample Chrome Extension",
"version": "1.0",
"background": {
"scripts": ["background.js"]
},
"permissions":[
"http://translate.google.hu/*", "tabs"
]
}
background.js
chrome.tabs.onUpdated.addListener(function(tabId,changeInfo,tab){
if (tab.url.indexOf("http://translate.google.hu/") > -1 &&
changeInfo.url === undefined){
chrome.tabs.executeScript(tabId, {file: "program.js"} );
}
});
This will listen for the onUpdated event, checks if it is one of the url's that we want to inject into, and then it checks if the page was reloaded. That last step is accomplished by checking if changeInfo.url exists. If it does, then that means that the url was changed and thus not a refresh. Conversely, if it doesn't exist, then the page must have only been refreshed.
2021
If you want to detect reload from background.js in manifest 3 (maybe also 2), chrome.tabs.onUpdated approach didn't work for me :/ It was invoked too many times.
That what worked for me in the end!
// --- On Reloading or Entering example.com ---
chrome.webNavigation.onCommitted.addListener((details) => {
if (["reload", "link", "typed", "generated"].includes(details.transitionType) &&
details.url === "http://example.com/") {
codeAfterReload();
// If you want to run only when the reload finished (at least the DOM was loaded)
chrome.webNavigation.onCompleted.addListener(function onComplete() {
codeAfterReloadAndFinishSomeLoading();
chrome.webNavigation.onCompleted.removeListener(onComplete);
});
}
});
For more transition types: https://developer.chrome.com/docs/extensions/reference/history/#transition_types
good luck :)
content_scripts are run at every page (re)load, so it's best to just use those to detect it.
This way you also don't risk running any code in the background before your content_script is ready to receive any message.