Golo Roden
Golo Roden

Reputation: 150674

Redirecting http to https using a Chrome extension

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:

  1. 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.

  2. 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 httprequests, 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:

To make it explicit: These rules shall only active for localhost.

So, now my questions are:

Upvotes: 1

Views: 2837

Answers (1)

gkalpak
gkalpak

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

Related Questions