diff --git a/README.md b/README.md index 39e2bd8..966bed5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Smart-HTTPS +# Smart-HTTPS with Mixed Content Upgrade Automatically changes HTTP addresses to the secure HTTPS, and if loading encounters error, reverts it back to HTTP. * Firefox: https://addons.mozilla.org/en-US/firefox/addon/smart-https/ diff --git a/lib/chrome/MixedContentUpgrade.js b/lib/chrome/MixedContentUpgrade.js new file mode 100644 index 0000000..f1d2bb6 --- /dev/null +++ b/lib/chrome/MixedContentUpgrade.js @@ -0,0 +1,49 @@ +/* + Modify the CSP + Copyright (C) 2016 Pascal Ernster + Copyright (C) 2017 ghost + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +'use strict'; +let blacklist = localStorage; +function modifyCSP(e) { + //Look up backlist + let uri = document.createElement('a'); + uri.href = e.url; + + if (Number(blacklist[uri.hostname]) === 1) { + return; + } + + let CSPMissing = true; + for (let header of e.responseHeaders) { + if (header.name.toLowerCase() === 'content-security-policy') { + if (typeof header.value === 'string') { + if (header.value.search('upgrade-insecure-requests') === -1) { + header.value += ';upgrade-insecure-requests'; + CSPMissing = false; + } + } + } + } + if (CSPMissing) { + e.responseHeaders.push({name: 'content-security-policy', value: 'upgrade-insecure-requests'}); + } + return {responseHeaders: e.responseHeaders}; +} + +chrome.webRequest.onHeadersReceived.addListener(modifyCSP, + {urls: ['https://*/*'], types: ['main_frame', 'sub_frame']}, + ['blocking', 'responseHeaders']); diff --git a/lib/chrome/background.html b/lib/chrome/background.html index 017e571..1fe1b63 100644 --- a/lib/chrome/background.html +++ b/lib/chrome/background.html @@ -10,7 +10,8 @@ - + + \ No newline at end of file diff --git a/lib/chrome/chrome.js b/lib/chrome/chrome.js index 2ec090d..3694bfb 100644 --- a/lib/chrome/chrome.js +++ b/lib/chrome/chrome.js @@ -11,8 +11,6 @@ app.loadReason = "startup"; var onBeforeRequest, onHeadersReceived, onCompleted; app.XMLHttpRequest = function () {return new XMLHttpRequest()}; app.version = function () {return chrome.runtime.getManifest().version}; -if (chrome.runtime.onInstalled) chrome.runtime.onInstalled.addListener(function (e) {app.loadReason = e.reason}); -if (chrome.runtime.setUninstallURL) chrome.runtime.setUninstallURL(config.welcome.url + "?v=" + app.version() + "&type=uninstall", function () {}); app.storage = (function () { var objs = {}; diff --git a/lib/common.js b/lib/common.js index 377d46c..bc9f94a 100644 --- a/lib/common.js +++ b/lib/common.js @@ -5,19 +5,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +const HTTP_PROTOCOL="http:" +const HTTPS_PROTOCOL="https:" + var httpObject = config.http.object, httpsObject = config.https.object; -window.setTimeout(function () { - var version = config.welcome.version; - if (version !== app.version()) { - if (app.loadReason === "install" || app.loadReason === "startup") { - if (config.welcome.open) { - app.tabs.open(config.welcome.url + "?version=" + app.version() + (version ? "&p=" + version + "&type=upgrade" : "&type=install")); - } - config.welcome.version = app.version(); - } - } -}, config.welcome.timeout); var setToolbarIcon = function (state) { app.button.label = 'Smart HTTPS is ' + state.toUpperCase(); @@ -58,36 +50,34 @@ app.popup.receive("type", function (type) { if (type === "whitelist") { app.tabs.getActive(function (tab) { if (tab.url.indexOf("http://") === 0 || tab.url.indexOf("https://") === 0) { - var OLD = tab.url.replace("https://", "http://"); - var domain = app.toHostname(OLD); + var domain = new URL(tab.url).hostname; /* */ httpObject = config.http.object; - config.http.proxy[domain] = {"url": OLD, "error": true, "smart": false}; + config.http.proxy[domain] = {"url": domain, "error": true, "smart": false}; config.http.object = httpObject; /* */ httpsObject = config.https.object; delete config.https.proxy[domain]; config.https.object = httpsObject; /* */ - app.tabs.update(tab, OLD, true); + app.tabs.update(tab, domain, true); } }); } if (type === "blacklist") { app.tabs.getActive(function (tab) { if (tab.url.indexOf("http://") === 0 || tab.url.indexOf("https://") === 0) { - var OLD = tab.url.replace("http://", "https://"); - var domain = app.toHostname(OLD); + var domain = new URL(tab.url).hostname; /* */ httpsObject = config.https.object; - config.https.proxy[domain] = {"url": OLD, "error": true, "smart": false}; + config.https.proxy[domain] = {"url": domain, "error": true, "smart": false}; config.https.object = httpsObject; /* */ httpObject = config.http.object; delete config.http.proxy[domain]; config.http.object = httpObject; /* */ - app.tabs.update(tab, OLD, true); + app.tabs.update(tab, domain, true); } }); } @@ -169,12 +159,12 @@ var errorHandler = function (error, details, force, host) { window.setTimeout(function () { app.tabQuery(details, function (tab) { if (tab) { - if (force || /^https:\/\//i.test(details.url)) { + if (force || new URL(details.url).protocol==HTTPS_PROTOCOL) { config.http.proxy[domain].error = true; config.http.proxy[domain].incognito = tab.incognito; config.http.object = httpObject; if (config.log.print) console.error(error + " - Reverting back to HTTP: ", config.http.proxy[domain].url); - app.tabs.update(tab, config.http.proxy[domain].url, false); + app.tabs.update(tab, top, false); } } else if (config.log.print) console.error(" - Couldn't find tab with url: ", details.url); }); @@ -211,7 +201,7 @@ var handleExtraErrors = function (top, details) { else callback({"error": ('net::ERR_XHR_STATUS_' + xhr.status), "details": xhr._details}); } else { /* if the response URL is HTTP, we still have the error */ - if (/^http:\/\//i.test(xhr.responseURL)) callback({"error": 'net::ERR_XHR_REDIRECT', "details": xhr._details}); + if (new URL(xhr.responseURL).protocol==HTTP_PROTOCOL) callback({"error": 'net::ERR_XHR_REDIRECT', "details": xhr._details}); else callback({"error": '', "details": xhr._details}); } } @@ -234,16 +224,19 @@ var handleExtraErrors = function (top, details) { }; app.onBeforeRequest(function (details) { - var top = details.url; - if (/^http:\/\//i.test(top)) { - var newURL = top.replace(/^http:\/\//i, 'https://'); + let top = details.url; + let urlObj=new URL(details.url); + if (urlObj.protocol==HTTP_PROTOCOL) { + urlObj.protocol=HTTPS_PROTOCOL; + let newURL= urlObj.toString(); + // var newURL = top.replace(/^http:\/\//i, 'https://'); httpObject = config.http.object; httpsObject = config.https.object; var domain = app.toHostname(top); /* */ if (!config.http.proxy[domain]) { if (!config.https.proxy[domain]) { - config.http.proxy[domain] = {"url": top, "error": false, "smart": true}; + config.http.proxy[domain] = {"url": domain, "error": false, "smart": true}; config.http.object = httpObject; if (config.log.print) console.error(" - Smart switch to HTTPS: ", newURL); } else { @@ -259,7 +252,8 @@ app.onBeforeRequest(function (details) { app.onHeadersReceived(function (domain, details) { if (config.addon.typemissmatch) { - if (/^http:\/\//i.test(details.url)) { + let urlObj=new URL(details.url); + if (urlObj.protocol==HTTP_PROTOCOL) { if (config.http.proxy[domain]) { if (!config.http.proxy[domain].error) { errorHandler("net::ERR_TYPE_MISMATCH", details, true, domain); @@ -272,6 +266,7 @@ app.onHeadersReceived(function (domain, details) { app.onCompleted(function (e) { var _check = function (details) { var top = details.url; + let urlObj = new URL(details.url); var domain = app.toHostname(top); var msg1 = " - HTTPS is OK (" + domain + "), cleaning whitelist table"; var msg2 = " - HTTPS had Error (" + domain + "), but removed from whitelist because whitelisting is disabled"; @@ -289,7 +284,7 @@ app.onCompleted(function (e) { httpsObject = config.https.object; if (config.http.proxy[domain]) { if (!details.error || config.https.proxy[domain]) { - var flag = /^https:\/\//i.test(details.url) && !config.http.proxy[domain].error; + var flag = urlObj.protocol==HTTPS_PROTOCOL && !config.http.proxy[domain].error; if (flag) _clean(domain, msg1); else if (config.addon.dwhitelisting) _clean(domain, msg2); else if (config.http.proxy[domain].incognito && config.addon.incognito) _clean(domain, msg4); diff --git a/lib/config.js b/lib/config.js index bb3e649..87e5a6a 100644 --- a/lib/config.js +++ b/lib/config.js @@ -28,7 +28,7 @@ config.addon = { set dwhitelisting (val) {app.storage.write('dwhitelisting', val)}, set typemissmatch (val) {app.storage.write('typemissmatch', val)}, get regexp () {return app.storage.read('regexp') === "true" ? true : false}, - get incognito () {return app.storage.read('incognito') === "true" ? true : false}, + get incognito () {return true}, get dwhitelisting () {return app.storage.read('dwhitelisting') === "true" ? true : false}, get typemissmatch () {return app.storage.read('typemissmatch') === "true" ? true : false} }; diff --git a/manifest.json b/manifest.json index 91957d2..a4cb089 100644 --- a/manifest.json +++ b/manifest.json @@ -1,11 +1,11 @@ { - "version": "0.2.0", - "name": "Smart HTTPS", + "version": "0.2.1.3", + "name": "Smart HTTPS with Mixed Content Upgrade", "manifest_version": 2, "short_name": "smarthttps", "background": {"page": "lib/chrome/background.html"}, "homepage_url": "http://mybrowseraddon.com/smart-https.html", - "options_ui": {"chrome_style": true, "page": "data/options/options.html"}, + "options_ui": {"chrome_style": true, "page": "data/options/options.html", "open_in_tab": true}, "description": "Automatically changes HTTP addresses to the secure HTTPS, and if loading encounters error, reverts it back to HTTP.", "permissions": [ "tabs", @@ -15,6 +15,11 @@ "webNavigation", "webRequestBlocking" ], + "applications": { + "gecko": { + "id": "{f6c29eb6-2588-4872-a80a-5eff0d801e9c}" + } + }, "browser_action": { "default_title": "Smart HTTPS", "default_popup": "data/popup/popup.html", @@ -30,4 +35,4 @@ "64": "data/icons/enabled/64.png", "128": "data/icons/enabled/128.png" } -} \ No newline at end of file +}