This is my first time ever touching any sort of client sided web programming language, and, I'm attempting to make my first chrome addon. Basically what I want to do is code something which redirects from:-
ABC.com/ID
to
A.ABC.com/ID
So far I have it all coded, however, what it does is it loads ABC.com/ID, waits for it to complete, then injects my content script and re-loads A.ABC.com/ID. This is obviously a huge waste of time. Is there any way I can tell chrome to load this script either before the DNS lookup (Because that's useless, because it's on a new subdomain), or, before opening a connection to the site (Because this isn't the page we're looking for)? I understand a content script may not be the best idea, if it's not, then what would be?
Yes, you can achieve with web request API without any content scripts. The following demonstration blocks all Facebook URL's and redirects them to Google, similarly use ABC.com/ID instead of Facebook and use A.ABC.com/ID instead of Google for this use case.
References
Web request
Background Page
Manifest File
manifest.json
Ensure all permissions are available and register background page with extension.
{
"name": "Hanlder for Navigation",
"description": "http://stackoverflow.com/questions/14050467",
"version": "1",
"manifest_version": 2,
"background": {
"scripts": ["background.js"]
},
"permissions":["https://www.facebook.com/*","webRequest","webRequestBlocking"]
}
background.js
This code blocks all URL request to Facebook and redirects them to Google.
// Register an event listener which
//traces all requests before being fired
chrome.webRequest.onBeforeRequest.addListener(function (details) {
return {
redirectUrl: "http://www.google.co.in/" /*Redirection URL*/
};
}, {
urls: ["*://www.facebook.com/*"] /* List of URL's */
}, ["blocking"]); // Block intercepted requests until this handler has finished
Output
All request(s) to Facebook are redirected to Google.
Related
i'm trying to design a chrome extension, it has to inject a script into a web page, this script intercepts json responses, and send them to the background script.
Keep in mind i'm not used to js i might be doing this wrong, so, in my manifest i have :
"background": {
"scripts": ["background.js"],
"persistent": true
},
"content_scripts": [
{
"matches": ["*://url*"],
"run_at": "document_start",
"js": ["inject.js"]
}
],
"web_accessible_resources": ["injected.js"],
in my background script i handle the messages that way :
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.type) {
switch(request.type) {
case "THIS_REQUEST_TYPE":
do_stuff(request.foo, request.bar);
break;
...................
inject.js's purpose is to inject injected.js into a webpage, and now it's also doing relay for messages that goes from injected.js to background.js, i inject injected.js that way :
var s = document.createElement('script');
s.src = chrome.extension.getURL('injected.js');
s.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(s);
Now, to get messages from injected.js to my background script i basically use :
window.postMessage(msgdata, "*");
This send messages from injected.js to inject.js, then in inject.js i'm able to get those messages with :
window.addEventListener("message", function(event) {
Then i can finally send those messages to my background script, this time using :
chrome.runtime.sendMessage(
I found no possible way to directly send messages from injected.js to background.js, the informations available on chrome's documentation are perfectly fine to send messages from inject.js to background.js, but aren't working otherwise, i tried several online solutions and the one i use is the only one i was able to get working.
Anyway, this works, i'm able to send json responses from injected.js to inject.js to background.js and parse them in my background script.
The thing is, i hate having to do it that way, json responses can be really long, i'm already filtering responses in injected.js so that only those who are useful are getting sent, but still sometimes i have to send copy of responses that are 591109 characters long !
So, having to send twice responses that long is kinda ugly, i want this to be efficient and fast.
Anyone have an idea about this ?
Your injected.js is running in a script DOM element so it's just an unprivileged web page script. To use chrome.runtime.sendMessage directly from a web page script you would have to declare the allowed URL patterns in externally_connectable but you can't allow all URLs indiscriminately so I would use your approach, although with a CustomEvent (and a random event name most likely) instead of message which can be intercepted by the page scripts or other extensions - it's not security that I'm concerned with here, but rather a possibility of breaking some site that assumes the message data is in a certain format (e.g. string), not compatible with the one you use (e.g. object).
You can also use chrome.debugger API to attach to the tab and intercept the JSON response in your background script, but that will show a notification above the tab about it being debugged.
Anyway, unless you see your extension slowing down the page (in devtools profiler or by manually measuring the time spent in your code), there's no need to worry.
FWIW, in Firefox you can read the response directly via browser.webRequest.filterResponseData.
I am developing a Chrome extension for work, and one of the things it needs to do is to read (only read, not modify) an object that we send back to the website after it makes an asynchronous request to our servers. Basically I need to read the window.<our object name> object and get what's in there.
Now, I know this is possible, because I did this in a Tampermonkey script that I wrote. I was able to console.log(window.<our object name>) and it came in.
Tampermonkey is a Chrome extension, so there's no intrinsic reason why it can access something and another extension can't.
But when I try to access this object, both from content scripts and from injected code, I get nothing. When I get the window object only, it comes up only partially, as if the extension were blind to certain parts of it. But if I'm in the console on the page, and I call window, I get a full window object back. Infuriating.
So if content scripts don't work, and injected scripts don't work, and there's no reason why popup scripts would be any good here, how does one do this?
Many thanks!
UPDATE: As requested, here is the manifest.json (I took the page_redder example and worked off that to make sure I wasn't making any weird mistakes):
{
"name": "Page Redder",
"description": "Make the current page red",
"version": "2.0",
"permissions": [
"activeTab"
],
"background": {
"scripts": ["background.js"],
"persistent": false
},
"browser_action": {
"default_title": "get my object"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
],
"manifest_version": 2
}
And here is content.js:
var getWindow = window.setTimeout(function() { console.log("From content script: " + window.<OBJECT NAME>); }, 5000);
And here is background.js:
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Called when the user clicks on the browser action.
chrome.browserAction.onClicked.addListener(function(tab) {
// No tabs or host permissions needed!
chrome.tabs.executeScript({
code: 'console.log("From injected script:" + window.<OBJECT NAME>);'
});
});
When run, I get:
From content script: undefined
From injected script: undefined
But if I do window. from the console, I get it. I even added a timeout to make sure that the content script wasn't trying to get something that hadn't loaded in yet. But I can retrieve the object manually before the script runs, and it still gives me undefined.
Soo, this is kind of hacky, but I was able to do it and it worked.
To gain access to everything available to the host window, I had to create a script element, put all the code I wanted in there, and add document.body.appendChild(script) for it to work.
Not the sexiest way of doing things, but it will get the job done for small tasks.
Interesting question. Here is a quick and probably incomplete answer :
each tab has its own private separate window object
background.js also has its own
content scripts are a bit tricky in that while they nominally live inside the page, they actually keep a respectful distance : see isolated worlds
I am not familiar with chrome.tabs.executeScript but somehow I would'nt trust it with anything beyond basics
One approach could be as follow :
Open the relevant page from the background script with chrome.tabs.create : hence the backgound will have complete control and dominance over said tab and the window, document and your_object therein. It will also be easier to handle the asynchronous side of thing : you'll learn to love callbacks.
Depending on what is required regarding the UX, another option would be to handle the async request, and fetch your_object, entirely in background.js
One last hint : extensions you download from the store are just zipped files in your Chrome profile. Find tapermonkey.crx or whatever, unzip it and read the sources to figure out what it does.
And oh, relying on timeout to handle asynchronicity is bound to random results.
According to documentation in https://developer.chrome.com/extensions/content_scripts
However, content scripts have some limitations. They cannot:
Use variables or functions defined by web pages or by other content scripts.
So you can access the common window variables from the content script, but not the variables created from the webpage's javascript, another content script or, as in your case, an object you have sent to the website.
I am trying to create a small chrome extension to help find where cookies are using in websites. The extension is SUPPOSE to work by setting the getter method for the cookie on the document.
Like so:
document.__defineGetter__('cookie',function(){
alert("test");
});
When manually put into chrome's javascript console on a website and then trying to access a cookie (simply typing "document.cookie") it results in the expected behavior where it will pop up the test prompt.
However when I put this into a chrome extension and have it load before the rest of the page it will fail to work.
Here is the manifest.json (I was just using soundcloud as a test website):
{
"name": "Cookie Auditor",
"version": "0.1",
"manifest_version": 2,
"description": "An extension to help examine where cookies are being used in websites.",
"content_scripts": [
{
"matches": ["*://*.soundcloud.com/*"],
"js": ["content.js"],
"run_at": "document_start"
}
]
}
and here is the content.js:
console.log(document.location);
document.__defineGetter__('cookie',function(){
alert("test");
});
console.log(document.__lookupGetter__('cookie'));
When attempting to manually trigger it (document.cookie) it simply returns the normal value and fails to execute the javascript. When it failed to work here I put in the checks for the document location to make sure it was executing on the right domain and was even loading at all.
The weird part is when you load the page with this extension it will print out that it is on the right domain and it even shows that the cookie getter method was overwritten correctly (it print the function in the console).
However when you lookup the getter method it has been reset (document.__lookupGetter__('cookie')).
My last thought was that it was being reset sometime between my content.js script running and the rest of the page initializing. However when I change the "run_at" field in the manifest.json file to "document_end" in an attempt to make it run later and potentually after any sort of re initialization of the document then soundcloud's stuff will start printing on the console showing that it has properly loaded the page however my script still fails to have made an effect.
EDIT: Before it is suggested. I can't use chrome's cookie API because it doesn't provide a way of actually listening to when a cookie is retrieved which is the main thing I care about.
After some digging around I found out why it was failing. Chrome extensions are executed in their own javascript space but with the same DOM as the site they run on. See https://developer.chrome.com/extensions/content_scripts#execution-environment. This causes them to have seperate global variables and thus my script's attempts to change them would only affect itself. For anyone looking at how to get around this limitation all you have to do is add a script tag with your code onto the document from your extension.
I am writing a Chrome extension which recognizes certain URL pattern and perform further DOM manipulation. The content script has to get the current URL and matches with the predefined list of URL patterns.
There are two ways I could think of achieving the goal:
The first one would be using location.href
manifest.json
...
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"run_at": "document_end"
}
],
...
content.js
console.log(location.href);
This method works fine. However, across other similar questions on StackOverflow, they usually suggests using chrome.tabs and message sending from background script to content script as follow:
manifest.json
...
"background" : {
"scripts": ["background.js"]
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"run_at": "document_end"
}
],
...
background.js
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
chrome.tabs.get(tab.id, function(tabInfo) {
chrome.tabs.sendMessage(tab.id, {
url: tabInfo.url
}, function(response) {
});
})
});
content.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.url) {
console.log(request.url)
sendResponse(true);
}
return true;
});
Both methods can have the URL correctly. And for the background script, it requires extra memory to keep the background script running in background, compared with content script which is only injected when loading the page.
On the other hand, using background script has benefit as the background script is said to be privileged, it can execute privileged Chrome APIs like the chrome.tabs API.
So as far as I am not using any privileged APIs, should I use the location.href or is there any particular reason most developers suggest using the chrome.tabs and message sending?
Advantages of a background page script:
Complex checks using additional information from the Tab object (N.B. add "tabs" permissions to access url, title, favIconUrl), whereas manifest.json-based injection is limited to URL wildcards/globs.
chrome.declarativeContent API with RequestContentScript action is an example of advanced filtering, it injects the content script(s) based on URL checks and DOM content (only simple selectors as noted in the documentation).
chrome.tabs.executeScript inside chrome.tabs.onUpdated or chrome.webNavigation or chrome.browserAction.onClicked listener to inject the content script(s) only when needed.
Changing the toolbar icon or the browser context menu to reflect change of state; content scripts can't do that, the background page script can.
Accessing privileged API like most of chrome.*, extension's internal storage such as IndexedDB, WebSQL, HTML5 FileSystem, localStorage (the latter is not a good choice though as it's not available in a content script directly, moreover it's synchronous and thus blocks execution).
In all the above cases it makes sense to pass data to content script using messages if that data was used while checking the conditions or it's only available in the background script. Otherwise chrome.storage API inside the content script is as good or could be even better readability-wise.
"Backgroundless" content script is better when all these conditions are met:
URLs to process can be set entirely with wildcards/globs or it really really must be <all_urls>
all required parameters are accessible via chrome.storage API or no parameters needed
no privileged chrome.* APIs are used as those aren't available in content scripts, in other words when the background page is not actually needed.
As for memory consumption: either method may be better or worse depending on how it's used.
If the content script is injected on all pages then each instance will consume memory (some people open 100 tabs so beware!). The worst case case is obviously when both persistent background page and content script on all URLs are used. Non-persistent event page might help but in a limited fashion because chrome.tabs.onUpdated is likely to run pretty frequently forcing the event page to reload (which also takes some time).
I'm making a content script extension for Google Chrome, it adds functionality to a website's page. I want to add a couple of options, not big deal really, I'd just need two strings (none of which are sensitive user data).
From this answer, I assume I need a background page, which I'd rather not add to my extension - I don't want it to gain unnecessary weight.
Do I really need a background page, or I could have an options page without it (and which storage could I use)?
UPDATE
As of Chrome 20 you can now use the Storage api.....
http://code.google.com/chrome/extensions/storage.html
Old way
What I do is create an iframe that points to a page in my extension that has a script that gets the settings I need from local storage and then sends that to its parent in a message which the content script then gets.....well that was a crap explanation, the code says it better ;).......
Content Script
// create the iframe for our page that sends the settings
var el = document.createElement("iframe");
el.setAttribute('src', chrome.extension.getURL("gimmeSettings.html"));
el.style.visibility="hidden";
document.body.appendChild(el);
// create the listner that listens for a message from our page that sends the settings
window.addEventListener("message", receiveSettings, false);
// function that gets called when we recieve a message from the page that sends the settings
function receiveSettings(event) {
//check to make sure the message came from our page
if (event.origin !== "chrome-extension://"+chrome.i18n.getMessage("##extension_id")) return;
//message came from our extension, do stuff with it
console.debug(event.data);
// clean up
window.removeEventListener("message", receiveSettings, false);
el.parentNode.removeChild(el);
}
gimmeSettings.html's JS
// post the message with our settings
parent.postMessage( localStorage.getItem("testing"), "*" );
Options.html's JS
localStorage.setItem("testing","bleh");
Manifest
{
"name": "Getting at an extensions local storage from a content script",
"description" : "Getting at an extensions local storage from a content script. Be aware that other pages/extensions can use this to get at your settings, but not change them...so dont include sensitvie data.",
"content_scripts": [
{
"matches": ["<all_urls>"],
"js" : ["myscript.js"],
"run_at":"document_idle"
}
],
"permissions": [
"tabs", "<all_urls>"
],
"manifest_version": 2,
"web_accessible_resources": [
"gimmeSettings.html"
],
"options_page": "options.html",
"version":"1.0"
}
Some things to note....
Other pages and extensions can easily use this to also get the settings from your extension, so dont use any sensitive data with this method.
From the best I can tell there is no way for them to alter your settings through that page tho, if anyone knows different please explain.
Im using manifest version 2 and have set the page gimmeSettings to be accessible. If you dont know the differences manifest version 2 add you really should read up on it.... http://code.google.com/chrome/extensions/trunk/manifestVersion.html
And if you want a working example then go here.....
http://forum.valorsolo.com/viewtopic.php?f=36&t=375
I just had an idea, but I don't know if it's sound or makes sense.
I believe I can access HTML5 localStorage from my content_script, and store the two strings there. Through Message Passing I should be able to tell the content_script that one of them changed (from the options page) and then have it update its localStorage.
Would this be the only option? It doesn't sound too bad if it works...