Skip to content
This repository has been archived by the owner on Nov 6, 2023. It is now read-only.

Commit

Permalink
Creating the ability to disable and enable HTTPS Everywhere for speci…
Browse files Browse the repository at this point in the history
…fic sites within popup.
  • Loading branch information
Hainish committed Sep 17, 2018
1 parent 558f7dc commit dc04b6d
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 29 deletions.
150 changes: 128 additions & 22 deletions chromium/background-scripts/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,23 @@ async function initializeAllRules() {
var httpNowhereOn = false;
var showCounter = true;
var isExtensionEnabled = true;
let disabledList = new Set();

function initializeStoredGlobals(){
return new Promise(resolve => {
store.get({
httpNowhere: false,
showCounter: true,
globalEnabled: true,
enableMixedRulesets: false
enableMixedRulesets: false,
disabledList: [],
}, function(item) {
httpNowhereOn = item.httpNowhere;
showCounter = item.showCounter;
isExtensionEnabled = item.globalEnabled;
for (let disabledSite of item.disabledList) {
disabledList.add(disabledSite);
}
updateState();

rules.settings.enableMixedRulesets = item.enableMixedRulesets;
Expand Down Expand Up @@ -147,14 +152,6 @@ function updateState () {
iconState = 'blocking';
}

if ('setIcon' in chrome.browserAction) {
chrome.browserAction.setIcon({
path: {
38: 'images/icons/icon-' + iconState + '-38.png'
}
});
}

chrome.browserAction.setTitle({
title: 'HTTPS Everywhere' + ((iconState === 'active') ? '' : ' (' + iconState + ')')
});
Expand All @@ -164,16 +161,37 @@ function updateState () {
return;
}
const tabId = tabs[0].id;
const activeCount = appliedRulesets.getActiveRulesetCount(tabId);
const tabUrl = new URL(tabs[0].url);

if ('setBadgeBackgroundColor' in chrome.browserAction) {
chrome.browserAction.setBadgeBackgroundColor({ color: '#666666', tabId });
}
if (disabledList.has(tabUrl.host) || iconState == "disabled") {
if ('setIcon' in chrome.browserAction) {
chrome.browserAction.setIcon({
path: {
38: 'images/icons/icon-disabled-38.png'
}
});
}
} else {

const showBadge = activeCount > 0 && isExtensionEnabled && showCounter;
if ('setIcon' in chrome.browserAction) {
chrome.browserAction.setIcon({
path: {
38: 'images/icons/icon-' + iconState + '-38.png'
}
});
}

const activeCount = appliedRulesets.getActiveRulesetCount(tabId);

if ('setBadgeBackgroundColor' in chrome.browserAction) {
chrome.browserAction.setBadgeBackgroundColor({ color: '#666666', tabId });
}

const showBadge = activeCount > 0 && isExtensionEnabled && showCounter;

if ('setBadgeText' in chrome.browserAction) {
chrome.browserAction.setBadgeText({ text: showBadge ? String(activeCount) : '', tabId });
if ('setBadgeText' in chrome.browserAction) {
chrome.browserAction.setBadgeText({ text: showBadge ? String(activeCount) : '', tabId });
}
}
});
}
Expand Down Expand Up @@ -277,10 +295,18 @@ var urlBlacklist = new Set();
// TODO: Remove this code if they ever give us a real counter
var redirectCounter = new Map();

// Create a map to indicate whether a given request has been subject to a simple
// HTTP Nowhere redirect.
let simpleHTTPNowhereRedirect = new Map();

const cancelUrl = chrome.extension.getURL("/pages/cancel/index.html");

function redirectOnCancel(shouldCancel){
return shouldCancel ? {redirectUrl: cancelUrl} : {cancel: false};
function redirectOnCancel(shouldCancel, originURL){
return shouldCancel ? {redirectUrl: newCancelUrl(originURL)} : {cancel: false};
}

function newCancelUrl(originURL){
return cancelUrl + "?originURL=" + encodeURI(originURL);
}

/**
Expand All @@ -296,6 +322,27 @@ function onBeforeRequest(details) {

let uri = new URL(details.url);

// Check if a user has disabled HTTPS Everywhere on this site. We should
// ensure that all subresources are not run through HTTPS Everywhere as well.
let firstPartyHost;
if (details.type == "main_frame") {
firstPartyHost = uri.host;
} else {
// In Firefox, documentUrl is preferable here, since it will always be the
// URL in the URL bar, but it was only introduced in FF 54. We should get
// rid of `originUrl` at some point.
if ('documentUrl' in details) { // Firefox 54+
firstPartyHost = new URL(details.documentUrl).host;
} else if ('originUrl' in details) { // Firefox < 54
firstPartyHost = new URL(details.originUrl).host;
} else if('initiator' in details) { // Chrome
firstPartyHost = new URL(details.initiator).host;
}
}
if (disabledList.has(firstPartyHost)) {
return;
}

// Normalise hosts with tailing dots, e.g. "www.example.com."
while (uri.hostname[uri.hostname.length - 1] === '.' && uri.hostname !== '.') {
uri.hostname = uri.hostname.slice(0, -1);
Expand Down Expand Up @@ -330,7 +377,7 @@ function onBeforeRequest(details) {
" changed before processing to " + uri.href);
}
if (urlBlacklist.has(uri.href)) {
return redirectOnCancel(shouldCancel);
return redirectOnCancel(shouldCancel, details.url);
}

if (details.type == "main_frame") {
Expand All @@ -344,7 +391,7 @@ function onBeforeRequest(details) {
urlBlacklist.add(uri.href);
rules.settings.domainBlacklist.add(uri.hostname);
util.log(util.WARN, "Domain blacklisted " + uri.hostname);
return redirectOnCancel(shouldCancel);
return redirectOnCancel(shouldCancel, details.url);
}

// whether to use mozilla's upgradeToSecure BlockingResponse if available
Expand Down Expand Up @@ -398,6 +445,7 @@ function onBeforeRequest(details) {
if (shouldCancel) {
if (!newuristr) {
newuristr = uri.href.replace(/^http:/, "https:");
simpleHTTPNowhereRedirect.set(details.requestId, true);
upgradeToSecure = true;
} else {
newuristr = newuristr.replace(/^http:/, "https:");
Expand All @@ -411,7 +459,7 @@ function onBeforeRequest(details) {
)
) {
// Abort early if we're about to redirect to HTTP or FTP in HTTP Nowhere mode
return {redirectUrl: cancelUrl};
return {redirectUrl: newCancelUrl(newuristr)};
}
}

Expand All @@ -423,7 +471,7 @@ function onBeforeRequest(details) {
return {redirectUrl: newuristr};
} else {
util.log(util.INFO, 'onBeforeRequest returning shouldCancel: ' + shouldCancel);
return redirectOnCancel(shouldCancel);
return redirectOnCancel(shouldCancel, details.url);
}
}

Expand Down Expand Up @@ -579,16 +627,54 @@ function onCompleted(details) {
if (redirectCounter.has(details.requestId)) {
redirectCounter.delete(details.requestId);
}
if (simpleHTTPNowhereRedirect.has(details.requestId)) {
simpleHTTPNowhereRedirect.delete(details.requestId);
}
}

/**
* handle webrequest.onErrorOccurred, cleanup redirectCounter
* @param details details for the chrome.webRequest (see chrome doc)
*/
function onErrorOccurred(details) {
if (httpNowhereOn &&
details.type == "main_frame" &&
simpleHTTPNowhereRedirect.get(details.requestId) &&
( // Enumerate a class of errors that are likely due to HTTPS misconfigurations
details.error.indexOf("net::ERR_SSL_") == 0 ||
details.error.indexOf("net::ERR_CERT_") == 0 ||
details.error.indexOf("net::ERR_CONNECTION_") == 0 ||
details.error.indexOf("net::ERR_ABORTED") == 0 ||
details.error.indexOf("NS_ERROR_CONNECTION_REFUSED") == 0 ||
details.error.indexOf("NS_ERROR_UNKNOWN_HOST") == 0 ||
details.error.indexOf("NS_ERROR_NET_TIMEOUT") == 0 ||
details.error.indexOf("NS_ERROR_NET_ON_TLS_HANDSHAKE_ENDED") == 0 ||
details.error.indexOf("NS_BINDING_ABORTED") == 0 ||
details.error.indexOf("SSL received a record that exceeded the maximum permissible length.") == 0 ||
details.error.indexOf("Peer’s Certificate has expired.") == 0 ||
details.error.indexOf("Unable to communicate securely with peer: requested domain name does not match the server’s certificate.") == 0 ||
details.error.indexOf("Peer’s Certificate issuer is not recognized.") == 0 ||
details.error.indexOf("Peer’s Certificate has been revoked.") == 0 ||
details.error.indexOf("The server uses key pinning (HPKP) but no trusted certificate chain could be constructed that matches the pinset. Key pinning violations cannot be overridden.") == 0 ||
details.error.indexOf("SSL received a weak ephemeral Diffie-Hellman key in Server Key Exchange handshake message.") == 0 ||
details.error.indexOf("The certificate was signed using a signature algorithm that is disabled because it is not secure.") == 0 ||
details.error.indexOf("Unable to communicate securely with peer: requested domain name does not match the server’s certificate.") == 0 ||
details.error.indexOf("Cannot communicate securely with peer: no common encryption algorithm(s).") == 0
))
{
let url = new URL(details.url);
if (url.protocol == "https:") {
url.protocol = "http:";
}
chrome.tabs.update(details.tabId, {url: newCancelUrl(url.toString())});
}

if (redirectCounter.has(details.requestId)) {
redirectCounter.delete(details.requestId);
}
if (simpleHTTPNowhereRedirect.has(details.requestId)) {
simpleHTTPNowhereRedirect.delete(details.requestId);
}
}

/**
Expand Down Expand Up @@ -744,6 +830,14 @@ chrome.runtime.onMessage.addListener(function(message, sender, sendResponse){
});
}

function storeDisabledList() {
const disabledListArray = Array.from(disabledList);
store.set({disabledList: disabledListArray}, () => {
sendResponse(true);
});
return true;
}

const responses = {
get_option: () => {
store.get(message.object, sendResponse);
Expand Down Expand Up @@ -890,6 +984,18 @@ chrome.runtime.onMessage.addListener(function(message, sender, sendResponse){
sendResponse(item['last-checked']);
});
return true;
},
disable_on_site: () => {
disabledList.add(message.object);
return storeDisabledList();
},
enable_on_site: () => {
disabledList.delete(message.object);
return storeDisabledList();
},
check_if_site_disabled: () => {
sendResponse(disabledList.has(message.object));
return true;
}
};
if (message.type in responses) {
Expand Down
2 changes: 2 additions & 0 deletions chromium/pages/cancel/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
<body>
<h1 id="https-everywhere"><img src="../../images/banner-red.png" alt="HTTPS Everywhere" /></h1>
<p data-i18n="cancel_he_blocking_explainer"></p>
<p id="url-paragraph"><span id="url-label">URL: </span><a href="#" id="originURL"></a></p>
<script src="../translation.js"></script>
<script src="../send-message.js"></script>
<script src="ux.js"></script>
</body>
</html>
19 changes: 19 additions & 0 deletions chromium/pages/cancel/ux.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* global sendMessage */

"use strict";

let observer;
Expand All @@ -9,6 +11,7 @@ document.addEventListener("DOMContentLoaded", () => {
} else {
observer.observe(explainer, {childList: true});
}
displayURL();
});

function replaceLink(explainer){
Expand All @@ -19,3 +22,19 @@ function replaceLink(explainer){
link.innerText = linkText;
explainer.innerHTML = explainer.innerHTML.replace(linkText, link.outerHTML);
}

function displayURL() {
const cancelURL = new URL(window.location.href);
const originURL = decodeURI(cancelURL.searchParams.get('originURL'));
const originURLLink = document.getElementById('originURL');
originURLLink.innerText = originURL;

originURLLink.addEventListener("click", function() {
if (confirm(chrome.i18n.getMessage("chrome_disable_on_this_site"))) {
const url = new URL(originURL);
sendMessage("disable_on_site", url.host, () => {
window.location = originURL;
});
}
});
}
7 changes: 6 additions & 1 deletion chromium/pages/popup/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ <h1 data-i18n="about_ext_name"></h1>
</section>

<div id="RuleManagement">
<section>
<section id="disableEnableSection">
<a href="javascript:void 0" id="disable-on-this-site" data-i18n="chrome_disable_on_this_site"></a>
<a href="javascript:void 0" id="enable-on-this-site" data-i18n="chrome_enable_on_this_site"></a>
</section>

<section id="addRuleSection">
<a href="javascript:void 0" id="add-rule-link" data-i18n="chrome_add_rule"></a>
<div id="add-new-rule-div" style="display: none">
<h3 data-i18n="about_add_new_rule"></h3>
Expand Down
4 changes: 2 additions & 2 deletions chromium/pages/popup/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ body {
margin-right: 1em;
margin-top: 0;
margin-bottom: 0;
min-width: 20em;
min-width: 23em;
font-family: 'Lucida Grande', 'Segoe UI', Tahoma, 'DejaVu Sans', Arial, sans-serif;
font-size: 75%;
color: #303942;
Expand Down Expand Up @@ -114,7 +114,7 @@ footer {
}

/* By default the "Add a rule" link is hidden. It's shown on HTTPS sites only. */
#add-rule-link {
#addRuleSection {
display: none;
}

Expand Down
Loading

0 comments on commit dc04b6d

Please sign in to comment.