Skip to content

Commit b3896f5

Browse files
diracdeltassemenko
authored andcommitted
Add HTTP Nowhere mode to Chromium
Adds mode for blocking HTTP requests entirely after HTTPS Everywhere rewrites. Switches UI button from PageAction to BrowserAction, because why was it a PageAction in the first place?
1 parent 6bb52b5 commit b3896f5

File tree

6 files changed

+82
-30
lines changed

6 files changed

+82
-30
lines changed

chromium/background.js

Lines changed: 45 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,26 @@ var switchPlannerEnabledFor = {};
2929
// rw / nrw stand for "rewritten" versus "not rewritten"
3030
var switchPlannerInfo = {};
3131

32+
// Load prefs about whether http nowhere is on. Structure is:
33+
// { httpNowhere: true/false }
34+
var httpNowhereOn = false;
35+
chrome.storage.sync.get({httpNowhere: false}, function(item) {
36+
httpNowhereOn = item.httpNowhere;
37+
setIconColor();
38+
});
39+
chrome.storage.onChanged.addListener(function(changes, areaName) {
40+
if (areaName === 'sync') {
41+
for (key in changes) {
42+
if (key !== 'httpNowhere') {
43+
return;
44+
} else {
45+
httpNowhereOn = changes[key].newValue;
46+
setIconColor();
47+
}
48+
}
49+
}
50+
});
51+
3252
var getStoredUserRules = function() {
3353
var oldUserRuleString = localStorage.getItem(USER_RULE_KEY);
3454
var oldUserRules = [];
@@ -48,6 +68,15 @@ var loadStoredUserRules = function() {
4868
};
4969

5070
loadStoredUserRules();
71+
72+
// Set the icon color correctly
73+
var setIconColor = function() {
74+
var newIconPath = httpNowhereOn ? './icon38-red.png' : './icon38.png';
75+
chrome.browserAction.setIcon({
76+
path: newIconPath
77+
});
78+
}
79+
5180
/*
5281
for (var v in localStorage) {
5382
log(DBUG, "localStorage["+v+"]: "+localStorage[v]);
@@ -124,6 +153,9 @@ function onBeforeRequest(details) {
124153
// todo: check that this is enough
125154
var uri = new URI(details.url);
126155

156+
// Should the request be canceled?
157+
var shouldCancel = (httpNowhereOn && uri.protocol() === 'http');
158+
127159
// Normalise hosts such as "www.example.com."
128160
var canonical_host = uri.hostname();
129161
if (canonical_host.charAt(canonical_host.length - 1) == ".") {
@@ -145,7 +177,7 @@ function onBeforeRequest(details) {
145177
" changed before processing to " + canonical_url);
146178
}
147179
if (canonical_url in urlBlacklist) {
148-
return null;
180+
return {cancel: shouldCancel};
149181
}
150182

151183
if (details.type == "main_frame") {
@@ -162,7 +194,7 @@ function onBeforeRequest(details) {
162194
var hostname = uri.hostname();
163195
domainBlacklist[hostname] = true;
164196
log(WARN, "Domain blacklisted " + hostname);
165-
return null;
197+
return {cancel: shouldCancel};
166198
}
167199

168200
var newuristr = null;
@@ -174,10 +206,11 @@ function onBeforeRequest(details) {
174206
}
175207
}
176208

209+
var finaluri = newuristr ? new URI(newuristr) : null;
210+
177211
if (newuristr && tmpuserinfo !== "") {
178212
// re-insert userpass info which was stripped temporarily
179213
// while rules were applied
180-
var finaluri = new URI(newuristr);
181214
finaluri.userinfo(tmpuserinfo);
182215
newuristr = finaluri.toString();
183216
}
@@ -192,20 +225,25 @@ function onBeforeRequest(details) {
192225
newuristr);
193226
}
194227

228+
if (httpNowhereOn) {
229+
if (finaluri && finaluri.protocol() === "http") {
230+
// Abort early if we're about to redirect to HTTP in HTTP Nowhere mode
231+
return {cancel: true};
232+
}
233+
}
234+
195235
if (newuristr) {
196-
log(DBUG, "Redirecting from "+details.url+" to "+newuristr);
197236
return {redirectUrl: newuristr};
198237
} else {
199-
return null;
238+
return {cancel: shouldCancel};
200239
}
201240
}
202241

203242

204243
// Map of which values for the `type' enum denote active vs passive content.
205244
// https://developer.chrome.com/extensions/webRequest.html#event-onBeforeRequest
206245
var activeTypes = { stylesheet: 1, script: 1, object: 1, other: 1};
207-
// We consider sub_frame to be passive even though it can contain JS or Flash.
208-
// This is because code running the sub_frame cannot access the main frame's
246+
209247
// content, by same-origin policy. This is true even if the sub_frame is on the
210248
// same domain but different protocol - i.e. HTTP while the parent is HTTPS -
211249
// because same-origin policy includes the protocol. This also mimics Chrome's
@@ -402,27 +440,6 @@ wr.onBeforeRequest.addListener(onBeforeRequest, {urls: ["https://*/*", "http://*
402440
wr.onBeforeRedirect.addListener(onBeforeRedirect, {urls: ["https://*/*"]});
403441

404442

405-
// Add the small HTTPS Everywhere icon in the address bar.
406-
// Note: We can't use any other hook (onCreated, onActivated, etc.) because Chrome resets the
407-
// pageActions on URL change. We should strongly consider switching from pageAction to browserAction.
408-
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
409-
if (changeInfo.status === "loading") {
410-
chrome.pageAction.show(tabId);
411-
}
412-
});
413-
414-
// Pre-rendered tabs / instant experiments sometimes skip onUpdated.
415-
// See http://crbug.com/109557
416-
chrome.tabs.onReplaced.addListener(function(addedTabId, removedTabId) {
417-
chrome.tabs.get(addedTabId, function(tab) {
418-
if(typeof(tab) === "undefined") {
419-
log(DBUG, "Not a real tab. Skipping showing pageAction.");
420-
} else {
421-
chrome.pageAction.show(addedTabId);
422-
}
423-
});
424-
});
425-
426443
// Listen for cookies set/updated and secure them if applicable. This function is async/nonblocking.
427444
chrome.cookies.onChanged.addListener(onCookieChanged);
428445

chromium/icon38-red.png

2.73 KB
Loading

chromium/icon38.png

2.7 KB
Loading

chromium/manifest.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@
2525
"manifest_version": 2,
2626
"minimum_chrome_version": "18",
2727
"name": "__MSG_about_ext_name__",
28-
"page_action": {
29-
"default_icon": "icon48.png",
28+
"browser_action": {
29+
"default_icon": {
30+
"38": "icon38.png"
31+
},
3032
"default_popup": "popup.html",
3133
"default_title": "__MSG_about_ext_name__"
3234
},
@@ -35,6 +37,7 @@
3537
"webRequestBlocking",
3638
"tabs",
3739
"cookies",
40+
"storage",
3841
"<all_urls>"
3942
],
4043
"update_url": "https://www.eff.org/files/https-everywhere-chrome-updates.xml",

chromium/popup.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
<header>
1515
<h1 i18n="about_ext_name"></h1>
1616
</header>
17+
<section id="HttpNowhere" class="options">
18+
<input id="http-nowhere-checkbox" type="checkbox" value="httpNowhere"/>
19+
<label for="http-nowhere-checkbox">Turn on HTTP Nowhere</label>
20+
</section>
1721
<section>
1822
<a href="#" id="add-rule-link">Add a rule for this site</a>
1923
<div id="add-new-rule-div" style="display:none">

chromium/popup.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,16 @@ document.addEventListener("DOMContentLoaded", function () {
9090
unstableRules = document.getElementById("UnstableRules");
9191
chrome.tabs.getSelected(null, gotTab);
9292

93+
// Set up toggle checkbox for HTTP nowhere mode
94+
getOption_('httpNowhere', false, function(item) {
95+
var httpNowhereCheckbox = document.getElementById('http-nowhere-checkbox');
96+
httpNowhereCheckbox.addEventListener('click', toggleHttpNowhere, false);
97+
var httpNowhereEnabled = item.httpNowhere;
98+
if (httpNowhereEnabled) {
99+
httpNowhereCheckbox.setAttribute('checked', '');
100+
}
101+
});
102+
93103
// auto-translate all elements with i18n attributes
94104
var elem = document.querySelectorAll("[i18n]");
95105
for (var i=0; i < elem.length; i++) {
@@ -153,3 +163,21 @@ function addManualRule() {
153163
});
154164
});
155165
}
166+
167+
function toggleHttpNowhere() {
168+
getOption_('httpNowhere', false, function(item) {
169+
setOption_('httpNowhere', !item.httpNowhere);
170+
});
171+
}
172+
173+
function getOption_(opt, defaultOpt, callback) {
174+
var details = {};
175+
details[opt] = defaultOpt;
176+
return chrome.storage.sync.get(details, callback);
177+
}
178+
179+
function setOption_(opt, value) {
180+
var details = {};
181+
details[opt] = value;
182+
return chrome.storage.sync.set(details);
183+
}

0 commit comments

Comments
 (0)