Reputation: 150674
I am developing a number of Node.js applications that use an https
server. While I am developing them, I run them on localhost
using a self-signed certificate. Basically, everything works, but I have two issues:
When I point my browser to https://localhost:3000
for the first time, it warns me about a non-trusted certificate. This is, of course, true (and important), but it's annyoing while developing. Of course, I could add the certificate as a trusted one, but they change from time to time, and I don't want to clutter the certificate store.
Sometimes I just forget to enter the https
part into the address bar, so Chrome tries to load the website using http
. For whatever reason Chrome does not realize that there is no webserver responding to http
requests, instead it loads and loads and loads and …
What I would like to do to solve both issues is to create a Chrome extension that resides next to the address bar and offers a button with which you can toggle its state:
localhost
(and only then!), it shall do two things:
http
, but the page is still pending
after a few seconds, it shall try using https
instead.To make it explicit: These rules shall only active for localhost
.
So, now my questions are:
Upvotes: 1
Views: 2837
Reputation: 48211
The Google Chrome Extensions Documentation is a great place to start. Everything you describe is possible using a Chrome Extension except for the "certificate accepting" part. (I am not saying it is not possible, I just don't know if it is - but I would be very surprised (and concerned) if it were.)
Of course, there is always the --ignore-certificate-errors
command-line switch, but it will not differentiate between localhost
and other domains.
If you decide to implement the rest of the functionality, I suggest looking into chrome.tabs and/or chrome.webRequest first. (Let me, also, mention "content scripts" are unlikely to be of any use.)
That said, below is some code for a demo extension (just to get you started).
What is does:
When deactivated -> nothing
When activated -> Listens for tabs being directed to URLs like http://localhost[:PORT][/...]
and redirects them to https
(it does not wait for a response or anything, it just redirects them instantly).
How to use:
Click the browser-action icon to activate/deactivate.
It's not perfect/complete, of course, but it's a starting point :)
Extension directory structure:
extention-root-directory/
|_____ manifest.json
|_____ background.js
|_____ img/
|_____ icon19.png
|_____ icon38.png
manifest.json:
(See here for more info on the possible fields.)
{
"manifest_version": 2,
"name": "Test Extension",
"version": "0.0",
"default_locale": "en",
"offline_enabled": true,
"incognito": "split",
// The background-page will listen for
// and handle various types of events
"background": {
"persistent": false, // <-- if you use chrome.webRequest, 'true' is required
"scripts": [
"background.js"
]
},
// Will place a button next to the address-bar
// Click to enable/disable the extension (see 'background.js')
"browser_action": {
"default_title": "Test Extension"
//"default_icon": {
// "19": "img/icon19.png",
// "38": "img/icon38.png"
//},
},
"permissions": [
"tabs", // <-- let me manipulating tab URLs
"http://localhost:*/*" // <-- let me manipulate tabs with such URLs
]
}
background.js:
(Related docs: background pages, event pages, browser actions, chrome.tabs API)
/* Configuration for the Badge to indicate "ENABLED" state */
var enabledBadgeSpec = {
text: " ON ",
color: [0, 255, 0, 255]
};
/* Configuration for the Badge to indicate "DISABLED" state */
var disabledBadgeSpec = {
text: "OFF",
color: [255, 0, 0, 100]
};
/* Return whether the extension is currently enabled or not */
function isEnabled() {
var active = localStorage.getItem("active");
return (active && (active == "true")) ? true : false;
}
/* Store the current state (enabled/disabled) of the extension
* (This is necessary because non-persistent background pages (event-pages)
* do not persist variable values in 'window') */
function storeEnabled(enabled) {
localStorage.setItem("active", (enabled) ? "true" : "false");
}
/* Set the state (enabled/disabled) of the extension */
function setState(enabled) {
var badgeSpec = (enabled) ? enabledBadgeSpec : disabledBadgeSpec;
var ba = chrome.browserAction;
ba.setBadgeText({ text: badgeSpec.text });
ba.setBadgeBackgroundColor({ color: badgeSpec.color });
storeEnabled(enabled);
if (enabled) {
chrome.tabs.onUpdated.addListener(localhostListener);
console.log("Activated... :)");
} else {
chrome.tabs.onUpdated.removeListener(localhostListener);
console.log("Deactivated... :(");
}
}
/* When the URL of a tab is updated, check if the domain is 'localhost'
* and redirect 'http' to 'https' */
var regex = /^http(:\/\/localhost(?::[0-9]+)?(?:\/.*)?)$/i;
function localhostListener(tabId, info, tab) {
if (info.url && regex.test(info.url)) {
var newURL = info.url.replace(regex, "https$1");
chrome.tabs.update(tabId, { url: newURL });
console.log("Tab " + tabId + " is being redirected to: " + newURL);
}
}
/* Listen for 'browserAction.onClicked' events and toggle the state */
chrome.browserAction.onClicked.addListener(function() {
setState(!isEnabled());
});
/* Initially setting the extension's state (upon load) */
setState(isEnabled());
Upvotes: 5