diff options
author | Ruben Rodriguez <ruben@gnu.org> | 2015-07-13 22:53:00 -0500 |
---|---|---|
committer | Ruben Rodriguez <ruben@gnu.org> | 2015-07-13 22:53:00 -0500 |
commit | 23103d7773e24fdf15b79ed69c67089b593fb31a (patch) | |
tree | ee1b744a80dd192e62fefc72ff1f0bf978d0d24c /data/extensions/https-everywhere@eff.org/components | |
parent | 9cb91f8a48f9467e448f88984c20b3429e8a2510 (diff) |
HTTPS-Everywhere updated to 5.0.5
Diffstat (limited to 'data/extensions/https-everywhere@eff.org/components')
-rw-r--r-- | data/extensions/https-everywhere@eff.org/components/https-everywhere.js | 487 | ||||
-rw-r--r-- | data/extensions/https-everywhere@eff.org/components/ssl-observatory.js | 101 |
2 files changed, 329 insertions, 259 deletions
diff --git a/data/extensions/https-everywhere@eff.org/components/https-everywhere.js b/data/extensions/https-everywhere@eff.org/components/https-everywhere.js index c248139..81f6ad6 100644 --- a/data/extensions/https-everywhere@eff.org/components/https-everywhere.js +++ b/data/extensions/https-everywhere@eff.org/components/https-everywhere.js @@ -1,42 +1,31 @@ -// LOG LEVELS --- - -VERB=1; -DBUG=2; -INFO=3; -NOTE=4; -WARN=5; +// LOG LEVELS +let VERB=1; +let DBUG=2; +let INFO=3; +let NOTE=4; +let WARN=5; // PREFERENCE BRANCHES let PREFBRANCH_ROOT=0; let PREFBRANCH_RULE_TOGGLE=1; let PREFBRANCH_NONE=2; -//--------------- - -https_domains = {}; // maps domain patterns (with at most one - // wildcard) to RuleSets - -https_everywhere_blacklist = {}; // URLs we've given up on rewriting because - // of redirection loops - -https_blacklist_domains = {}; // domains for which there is at least one - // blacklisted URL +// maps domain patterns (with at most one wildcard) to RuleSets +let https_domains = {}; +// URLs we've given up on rewriting because of redirection loops +let https_everywhere_blacklist = {}; +// domains for which there is at least one blacklisted URL +let https_blacklist_domains = {}; -// const CI = Components.interfaces; const CC = Components.classes; -const CU = Components.utils; -const CR = Components.results; const Ci = Components.interfaces; const Cc = Components.classes; const Cu = Components.utils; -const Cr = Components.results; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/FileUtils.jsm"); -const CP_SHOULDPROCESS = 4; - const SERVICE_CTRID = "@eff.org/https-everywhere;1"; const SERVICE_ID=Components.ID("{32c165b4-fe5e-4964-9250-603c410631b4}"); const SERVICE_NAME = "Encrypts your communications with a number of major websites"; @@ -136,43 +125,18 @@ INCLUDE('ChannelReplacement', 'IOUtil', 'HTTPSRules', 'HTTPS', 'Thread', 'Applic Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -// This is black magic for storing Expando data w/ an nsIDOMWindow -// See http://pastebin.com/qY28Jwbv , -// https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIControllers - -StorageController.prototype = { - QueryInterface: XPCOMUtils.generateQI( - [ Components.interfaces.nsISupports, - Components.interfaces.nsIController ]), - wrappedJSObject: null, // Initialized by constructor - supportsCommand: function (cmd) {return (cmd == this.command);}, - isCommandEnabled: function (cmd) {return (cmd == this.command);}, - onEvent: function(eventName) {return true;}, - doCommand: function() {return true;} -}; - -function StorageController(command) { - this.command = command; - this.data = {}; - this.wrappedJSObject = this; -}; - -/*var Controller = Class("Controller", XPCOM(CI.nsIController), { - init: function (command, data) { - this.command = command; - this.data = data; - }, - supportsCommand: function (cmd) cmd === this.command -});*/ - function HTTPSEverywhere() { // Set up logging in each component: HTTPS.log = HTTPSRules.log = RuleWriter.log = this.log = https_everywhereLog; + this.expandoMap = new WeakMap(); + this.log = https_everywhereLog; this.wrappedJSObject = this; this.https_rules = HTTPSRules; + this.rw = RuleWriter; // currently used for some file IO helpers, though that + // should probably be refactored this.INCLUDE=INCLUDE; this.ApplicableList = ApplicableList; this.browser_initialised = false; // the browser is completely loaded @@ -218,12 +182,14 @@ function HTTPSEverywhere() { } - /* In recent versions of Firefox and HTTPS Everywhere, the call stack for performing an HTTP -> HTTPS rewrite looks like this: 1. HTTPSEverywhere.observe() gets a callback with the "http-on-modify-request" topic, and the channel as a subject +1. HTTPSEverywhere.shouldIgnoreURI() checks for very quick reasons to ignore a +request, such as redirection loops, non-HTTP[S] URIs, and OCSP + 2. HTTPS.replaceChannel() 3. HTTPSRules.rewrittenURI() @@ -243,8 +209,7 @@ In recent versions of Firefox and HTTPS Everywhere, the call stack for performin In addition, the following other important tasks happen along the way: -HTTPSEverywhere.observe() aborts if there is a redirect loop - finds a reference to the ApplicableList or alist that represents the toolbar context menu +HTTPSEverywhere.observe() finds a reference to the ApplicableList or alist that represents the toolbar context menu HTTPS.replaceChannel() notices redirect loops (and used to do much more complex XPCOM API work in the NoScript-based past) @@ -292,8 +257,6 @@ HTTPSEverywhere.prototype = { [ Components.interfaces.nsIObserver, Components.interfaces.nsISupports, Components.interfaces.nsISupportsWeakReference, - Components.interfaces.nsIWebProgressListener, - Components.interfaces.nsIWebProgressListener2, Components.interfaces.nsIChannelEventSink ]), wrappedJSObject: null, // Initialized by constructor @@ -303,134 +266,229 @@ HTTPSEverywhere.prototype = { }, // An "expando" is an attribute glued onto something. From NoScript. - getExpando: function(domWin, key) { - var c = domWin.controllers.getControllerForCommand("https-everywhere-storage"); - try { - if (c) { - c = c.wrappedJSObject; - //this.log(DBUG, "Found a controller, returning data"); - return c.data[key]; - } else { - this.log(INFO, "No controller attached to " + domWin); - return null; - } - } catch(e) { - // Firefox 3.5 - this.log(WARN,"exception in getExpando"); - this.getExpando = this.getExpando_old; - this.setExpando = this.setExpando_old; - return this.getExpando_old(domWin, key, null); - } - }, - setExpando: function(domWin, key, value) { - var c = domWin.controllers.getControllerForCommand("https-everywhere-storage"); - try { - if (!c) { - this.log(DBUG, "Appending new StorageController for " + domWin); - c = new StorageController("https-everywhere-storage"); - domWin.controllers.appendController(c); - } else { - c = c.wrappedJSObject; + getExpando: function(browser, key) { + let obj = this.expandoMap.get(browser); + if (!obj) { + if (browser.currentURI) { + this.log(NOTE, "No expando for " + browser.currentURI.spec); } - c.data[key] = value; - } catch(e) { - this.log(WARN,"exception in setExpando"); - this.getExpando = this.getExpando_old; - this.setExpando = this.setExpando_old; - this.setExpando_old(domWin, key, value); + return null; } + return obj[key]; }, - // This method is straight out of NoScript... we fall back to it in FF 3.*? - getExpando_old: function(domWin, key, defValue) { - var domObject = domWin.document; - return domObject && domObject.__httpsEStorage && domObject.__httpsEStorage[key] || - (defValue ? this.setExpando(domObject, key, defValue) : null); - }, - setExpando_old: function(domWin, key, value) { - var domObject = domWin.document; - if (!domObject) return null; - if (!domObject.__httpsEStorage) domObject.__httpsEStorage = {}; - if (domObject.__httpsEStorage) domObject.__httpsEStorage[key] = value; - else this.log(WARN, "Warning: cannot set expando " + key + " to value " + value); - return value; + setExpando: function(browser, key, value) { + if (!this.expandoMap.has(browser)) { + this.expandoMap.set(browser, {}); + } + let obj = this.expandoMap.get(browser); + obj[key] = value; }, - // We use onLocationChange to make a fresh list of rulesets that could have + // We use resetApplicableList to make a fresh list of rulesets that could have // applied to the content in the current page (the "applicable list" is used // for the context menu in the UI). This will be appended to as various // content is embedded / requested by JavaScript. - onLocationChange: function(wp, req, uri) { - if (wp instanceof CI.nsIWebProgress) { - if (!this.newApplicableListForDOMWin(wp.DOMWindow)) - this.log(WARN,"Something went wrong in onLocationChange"); - } else { - this.log(WARN,"onLocationChange: no nsIWebProgress"); + resetApplicableList: function(browser) { + if (!this.prefs.getBoolPref("globalEnabled")) { + return; + } + try { + this.newApplicableListForBrowser(browser); + } catch (e) { + this.log(WARN, "Couldn't make applicable list"+e); } }, - getWindowForChannel: function(channel) { - // Obtain an nsIDOMWindow from a channel - let loadContext; + // Given an nsIChannel (essentially, a container for an HTTP or similar + // resource request), try to find the relevant tab if there is one. + // Specifically, find the XUL <browser> element for that tab. Note + // there are multiple meanings for the word 'browser' in Firefox, described at: + // https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Tabbed_browser + // We're looking for this one: + // https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/browser + // Also note some requests, like Safe Browsing requests, will have no + // associated tab. + getBrowserForChannel: function(channel) { + let loadContext, topFrameElement, associatedWindow; + let spec = channel.URI.spec; try { loadContext = channel.notificationCallbacks.getInterface(CI.nsILoadContext); } catch(e) { + } + + if (!loadContext) { try { - loadContext = channel.loadGroup.notificationCallbacks.getInterface(CI.nsILoadContext); + loadContext = channel.loadGroup.notificationCallbacks + .getInterface(CI.nsILoadContext); } catch(e) { - this.log(NOTE, "No loadContext for " + channel.URI.spec); + // Lots of requests have no notificationCallbacks, mostly background + // ones like OCSP checks or smart browsing fetches. + this.log(DBUG, "getBrowserForChannel: no loadContext for " + spec); return null; } } - if (!loadContext) { return null; } + if (loadContext) { + topFrameElement = loadContext.topFrameElement; + try { + // If loadContext is an nsDocShell, associatedWindow is present. + // Otherwise, if it's just a LoadContext, accessing it will throw + // NS_ERROR_UNEXPECTED. + associatedWindow = loadContext.associatedWindow; + } catch (e) { + } + } - let domWin = loadContext.associatedWindow; - if (!domWin) { - this.log(NOTE, "failed to get DOMWin for " + channel.URI.spec); + // On e10s (multiprocess, aka electrolysis) Firefox, + // loadContext.topFrameElement gives us a reference to the XUL <browser> + // element we need. However, on non-e10s Firefox, topFrameElement is null. + if (topFrameElement) { + return topFrameElement; + } else if (associatedWindow) { + // For non-e10s Firefox, get the XUL <browser> element using this rather + // magical / opaque code cribbed from + // https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Tabbed_browser#Getting_the_browser_that_fires_the_http-on-modify-request_notification_(example_code_updated_for_loadContext) + + // this is the HTML DOM window of the page that just loaded + var contentWindow = loadContext.associatedWindow; + // aDOMWindow this is the firefox window holding the tab + var aDOMWindow = contentWindow.top.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShellTreeItem) + .rootTreeItem + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindow); + // this is the gBrowser object of the firefox window this tab is in + var gBrowser = aDOMWindow.gBrowser; + if (gBrowser && gBrowser._getTabForContentWindow) { + var aTab = gBrowser._getTabForContentWindow(contentWindow.top); + // this is the clickable tab xul element, the one found in the tab strip + // of the firefox window, aTab.linkedBrowser is same as browser var above + // this is the browser within the tab + if (aTab) { + return aTab.linkedBrowser; + } else { + this.log(NOTE, "getBrowserForChannel: aTab was null for " + spec); + return null; + } + } else if (aDOMWindow.BrowserApp) { + // gBrowser is unavailable in Firefox for Android, and in some desktop + // contexts, like the fetches for new tab tiles (which have an + // associatedWindow, but no gBrowser)? + // If available, try using the BrowserApp API: + // https://developer.mozilla.org/en-US/Add-ons/Firefox_for_Android/API/BrowserApp + // TODO: We don't get the toolbar icon on android. Probably need to fix + // the gBrowser reference in toolbar_button.js. + // Also TODO: Where are these log messages going? They don't show up in + // remote debug console. + var mTab = aDOMWindow.BrowserApp.getTabForWindow(contentWindow.top); + if (mTab) { + return mTab.browser; + } else { + this.log(WARN, "getBrowserForChannel: mTab was null for " + spec); + return null; + } + } else { + this.log(INFO, "getBrowserForChannel: No gBrowser and no BrowserApp for " + spec); + return null; + } + } else { + this.log(NOTE, "getBrowserForChannel: No loadContext for " + spec); return null; } - - domWin = domWin.top; - return domWin; }, // the lists get made when the urlbar is loading something new, but they // need to be appended to with reference only to the channel getApplicableListForChannel: function(channel) { - var domWin = this.getWindowForChannel(channel); - return this.getApplicableListForDOMWin(domWin, "on-modify-request w " + domWin); + var browser = this.getBrowserForChannel(channel); + return this.getApplicableListForBrowser(browser); }, - newApplicableListForDOMWin: function(domWin) { - if (!domWin || !(domWin instanceof CI.nsIDOMWindow)) { - this.log(WARN, "Get alist without domWin"); + newApplicableListForBrowser: function(browser) { + if (!browser) { + this.log(WARN, "Get alist without browser"); return null; } - var dw = domWin.top; - var alist = new ApplicableList(this.log,dw.document,dw); - this.setExpando(dw,"applicable_rules",alist); + var alist = new ApplicableList(this.log, browser.currentURI); + this.setExpando(browser,"applicable_rules",alist); return alist; }, - getApplicableListForDOMWin: function(domWin, where) { - if (!domWin || !(domWin instanceof CI.nsIDOMWindow)) { - //this.log(WARN, "Get alist without domWin"); + getApplicableListForBrowser: function(browser) { + if (!browser) { + //this.log(WARN, "Get alist without browser"); return null; } - var dw = domWin.top; - var alist= this.getExpando(dw,"applicable_rules"); + var alist= this.getExpando(browser,"applicable_rules"); if (alist) { - //this.log(DBUG,"get AL success in " + where); return alist; } else { - //this.log(DBUG, "Making new AL in getApplicableListForDOMWin in " + where); - alist = new ApplicableList(this.log,dw.document,dw); - this.setExpando(dw,"applicable_rules",alist); + alist = new ApplicableList(this.log, browser.currentURI); + this.setExpando(browser,"applicable_rules",alist); } return alist; }, + // These are the highest level heuristics for figuring out whether + // we should consider rewriting a URI. Everything here should be simple + // and avoid dependence on the ruleset library + shouldIgnoreURI: function(channel, alist) { + var uri = channel.URI; + // Ignore all non-http(s) requests? + if (!(uri.schemeIs("http") || uri.schemeIs("https"))) { return true; } + + // If HTTP Nowhere is enabled, skip the rest of the shouldIgnoreURI checks + if (this.httpNowhereEnabled) { + return false; + } + + // These are URIs we've seen redirecting back in loops after we redirect them + if (uri.spec in https_everywhere_blacklist) { + this.log(DBUG, "Avoiding blacklisted " + uri.spec); + if (alist) { + alist.breaking_rule(https_everywhere_blacklist[uri.spec]); + } else { + this.log(NOTE,"Failed to indicate breakage in content menu"); + } + return true; + } + + // OCSP (currently) needs to be HTTP to avoid cert validation loops + // though someone should rev the spec to allow opportunistic encryption + if ("allowSTS" in channel) { + // Firefox 32+ lets us infer whether this is an OCSP request + if (!channel.allowSTS) { + this.log(INFO, "Channel with HTTPS rewrites forbidden, deeming OCSP, for " + channel.URI.spec); + return true; + } + } else { + // Firefox <32 requires a more hacky estimate + // load the list opportunistically to speed startup & FF 32+ + if (this.ocspList == undefined) { this.loadOCSPList(); } + if (this.ocspList.indexOf(uri.spec.replace(/\/$/,'')) !== -1) { + this.log(INFO, "Known ocsp request "+uri.spec); + return true; + } + } + + return false; + }, + + loadOCSPList: function() { + try { + var loc = "chrome://https-everywhere/content/code/commonOCSP.json"; + var file = CC["@mozilla.org/file/local;1"].createInstance(CI.nsILocalFile); + file.initWithPath(this.rw.chromeToPath(loc)); + var data = this.rw.read(file); + this.ocspList = JSON.parse(data); + } catch(e) { + this.log(WARN, "Failed to load OCSP list: " + e); + this.ocspList = []; + } + }, + observe: function(subject, topic, data) { // Top level glue for the nsIObserver API var channel = subject; @@ -438,15 +496,11 @@ HTTPSEverywhere.prototype = { if (topic == "http-on-modify-request") { if (!(channel instanceof CI.nsIHttpChannel)) return; - + this.log(DBUG,"Got http-on-modify-request: "+channel.URI.spec); - var lst = this.getApplicableListForChannel(channel); // null if no window is associated (ex: xhr) - if (channel.URI.spec in https_everywhere_blacklist) { - this.log(DBUG, "Avoiding blacklisted " + channel.URI.spec); - if (lst) lst.breaking_rule(https_everywhere_blacklist[channel.URI.spec]); - else this.log(NOTE,"Failed to indicate breakage in content menu"); - return; - } + // lst is null if no window is associated (ex: some XHR) + var lst = this.getApplicableListForChannel(channel); + if (this.shouldIgnoreURI(channel, lst)) return; HTTPS.replaceChannel(lst, channel, this.httpNowhereEnabled); } else if (topic == "http-on-examine-response") { this.log(DBUG, "Got http-on-examine-response @ "+ (channel.URI ? channel.URI.spec : '') ); @@ -483,16 +537,13 @@ HTTPSEverywhere.prototype = { Thread.hostRunning = false; } else if (topic == "profile-after-change") { this.log(DBUG, "Got profile-after-change"); - + if(this.prefs.getBoolPref("globalEnabled")){ OS.addObserver(this, "cookie-changed", false); OS.addObserver(this, "http-on-modify-request", false); OS.addObserver(this, "http-on-examine-merged-response", false); OS.addObserver(this, "http-on-examine-response", false); - - var dls = CC['@mozilla.org/docloaderservice;1'] - .getService(CI.nsIWebProgress); - dls.addProgressListener(this, CI.nsIWebProgress.NOTIFY_LOCATION); + this.log(INFO,"ChannelReplacement.supported = "+ChannelReplacement.supported); HTTPSRules.init(); @@ -615,26 +666,26 @@ HTTPSEverywhere.prototype = { return; } var alist = this.juggleApplicableListsDuringRedirection(oldChannel, newChannel); - HTTPS.replaceChannel(alist,newChannel, this.httpNowhereEnabled); + HTTPS.replaceChannel(alist, newChannel, this.httpNowhereEnabled); }, juggleApplicableListsDuringRedirection: function(oldChannel, newChannel) { // If the new channel doesn't yet have a list of applicable rulesets, start // with the old one because that's probably a better representation of how // secure the load process was for this page - var domWin = this.getWindowForChannel(oldChannel); + var browser = this.getBrowserForChannel(oldChannel); var old_alist = null; - if (domWin) - old_alist = this.getExpando(domWin,"applicable_rules"); - domWin = this.getWindowForChannel(newChannel); - if (!domWin) return null; - var new_alist = this.getExpando(domWin,"applicable_rules"); + if (browser) + old_alist = this.getExpando(browser,"applicable_rules"); + browser = this.getBrowserForChannel(newChannel); + if (!browser) return null; + var new_alist = this.getExpando(browser,"applicable_rules"); if (old_alist && !new_alist) { new_alist = old_alist; - this.setExpando(domWin,"applicable_rules",new_alist); + this.setExpando(browser,"applicable_rules",new_alist); } else if (!new_alist) { - new_alist = new ApplicableList(this.log, domWin.document, domWin); - this.setExpando(domWin,"applicable_rules",new_alist); + new_alist = new ApplicableList(this.log, browser.currentURI); + this.setExpando(browser,"applicable_rules",new_alist); } return new_alist; }, @@ -720,62 +771,53 @@ HTTPSEverywhere.prototype = { }, toggleEnabledState: function() { - if(this.prefs.getBoolPref("globalEnabled")){ - try{ - // toggling some of these after startup may be inconsequential... - // this.obsService.removeObserver(this, "sessionstore-windows-restored"); - this.obsService.removeObserver(this, "profile-before-change"); - this.obsService.removeObserver(this, "profile-after-change"); - OS.removeObserver(this, "cookie-changed"); - OS.removeObserver(this, "http-on-modify-request"); - OS.removeObserver(this, "http-on-examine-merged-response"); - OS.removeObserver(this, "http-on-examine-response"); - - var catman = Components.classes["@mozilla.org/categorymanager;1"] - .getService(Components.interfaces.nsICategoryManager); - catman.deleteCategoryEntry("net-channel-event-sinks", SERVICE_CTRID, true); - - var dls = CC['@mozilla.org/docloaderservice;1'] - .getService(CI.nsIWebProgress); - dls.removeProgressListener(this); - - this.prefs.setBoolPref("globalEnabled", false); - } - catch(e){ - this.log(WARN, "Couldn't remove observers: " + e); - } - } - else{ - try{ - this.obsService.addObserver(this, "profile-before-change", false); - this.obsService.addObserver(this, "profile-after-change", false); - // this.obsService.addObserver(this, "sessionstore-windows-restored", false); - OS.addObserver(this, "cookie-changed", false); - OS.addObserver(this, "http-on-modify-request", false); - OS.addObserver(this, "http-on-examine-merged-response", false); - OS.addObserver(this, "http-on-examine-response", false); - - var dls = CC['@mozilla.org/docloaderservice;1'] - .getService(CI.nsIWebProgress); - dls.addProgressListener(this, CI.nsIWebProgress.NOTIFY_LOCATION); - - this.log(INFO,"ChannelReplacement.supported = "+ChannelReplacement.supported); + if (this.prefs.getBoolPref("globalEnabled")) { + try { + this.obsService.removeObserver(this, "profile-before-change"); + this.obsService.removeObserver(this, "profile-after-change"); + this.obsService.removeObserver(this, "sessionstore-windows-restored"); + OS.removeObserver(this, "cookie-changed"); + OS.removeObserver(this, "http-on-modify-request"); + OS.removeObserver(this, "http-on-examine-merged-response"); + OS.removeObserver(this, "http-on-examine-response"); + + var catman = CC["@mozilla.org/categorymanager;1"] + .getService(CI.nsICategoryManager); + catman.deleteCategoryEntry("net-channel-event-sinks", + SERVICE_CTRID, true); + + this.prefs.setBoolPref("globalEnabled", false); + } catch(e) { + this.log(WARN, "Couldn't remove observers: " + e); + } + } else { + try { + this.obsService.addObserver(this, "profile-before-change", false); + this.obsService.addObserver(this, "profile-after-change", false); + this.obsService.addObserver(this, "sessionstore-windows-restored", false); + OS.addObserver(this, "cookie-changed", false); + OS.addObserver(this, "http-on-modify-request", false); + OS.addObserver(this, "http-on-examine-merged-response", false); + OS.addObserver(this, "http-on-examine-response", false); - if(!Thread.hostRunning) - Thread.hostRunning = true; - - var catman = Components.classes["@mozilla.org/categorymanager;1"] - .getService(Components.interfaces.nsICategoryManager); - // hook on redirections (non persistent, otherwise crashes on 1.8.x) - catman.addCategoryEntry("net-channel-event-sinks", SERVICE_CTRID, - SERVICE_CTRID, false, true); - - HTTPSRules.init(); - this.prefs.setBoolPref("globalEnabled", true); - } - catch(e){ - this.log(WARN, "Couldn't add observers: " + e); + this.log(INFO, + "ChannelReplacement.supported = "+ChannelReplacement.supported); + + if (!Thread.hostRunning) { + Thread.hostRunning = true; } + + var catman = CC["@mozilla.org/categorymanager;1"] + .getService(CI.nsICategoryManager); + // hook on redirections (non persistent, otherwise crashes on 1.8.x) + catman.addCategoryEntry("net-channel-event-sinks", SERVICE_CTRID, + SERVICE_CTRID, false, true); + + HTTPSRules.init(); + this.prefs.setBoolPref("globalEnabled", true); + } catch(e) { + this.log(WARN, "Couldn't add observers: " + e); + } } }, @@ -829,8 +871,15 @@ function https_everywhereLog(level, str) { threshold = WARN; } if (level >= threshold) { - dump("HTTPS Everywhere: "+str+"\n"); - econsole.logStringMessage("HTTPS Everywhere: " +str); + var levelName = ["", "VERB", "DBUG", "INFO", "NOTE", "WARN"][level]; + var prefix = "HTTPS Everywhere " + levelName + ": "; + // dump() prints to browser stdout. That's sometimes undesireable, + // so only do it when a pref is set (running from test.sh enables + // this pref). + if (prefs.getBoolPref("log_to_stdout")) { + dump(prefix + str + "\n"); + } + econsole.logStringMessage(prefix + str); } } diff --git a/data/extensions/https-everywhere@eff.org/components/ssl-observatory.js b/data/extensions/https-everywhere@eff.org/components/ssl-observatory.js index a783a72..abcb175 100644 --- a/data/extensions/https-everywhere@eff.org/components/ssl-observatory.js +++ b/data/extensions/https-everywhere@eff.org/components/ssl-observatory.js @@ -7,23 +7,23 @@ const CC = Components.classes; const CR = Components.results; // Log levels -VERB=1; -DBUG=2; -INFO=3; -NOTE=4; -WARN=5; +let VERB=1; +let DBUG=2; +let INFO=3; +let NOTE=4; +let WARN=5; -BASE_REQ_SIZE=4096; -TIMEOUT = 60000; -MAX_OUTSTANDING = 20; // Max # submission XHRs in progress -MAX_DELAYED = 32; // Max # XHRs are waiting around to be sent or retried +let BASE_REQ_SIZE=4096; +let TIMEOUT = 60000; +let MAX_OUTSTANDING = 20; // Max # submission XHRs in progress +let MAX_DELAYED = 32; // Max # XHRs are waiting around to be sent or retried -ASN_PRIVATE = -1; // Do not record the ASN this cert was seen on -ASN_IMPLICIT = -2 // ASN can be learned from connecting IP -ASN_UNKNOWABLE = -3; // Cert was seen in the absence of [trustworthy] Internet access +let ASN_PRIVATE = -1; // Do not record the ASN this cert was seen on +let ASN_IMPLICIT = -2; // ASN can be learned from connecting IP +let ASN_UNKNOWABLE = -3; // Cert was seen in the absence of [trustworthy] Internet access // XXX: We should make the _observatory tree relative. -LLVAR="extensions.https_everywhere.LogLevel"; +let LLVAR="extensions.https_everywhere.LogLevel"; Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); Components.utils.import("resource://gre/modules/ctypes.jsm"); @@ -64,13 +64,20 @@ function SSLObservatory() { try { // Check for torbutton - this.tor_logger = CC["@torproject.org/torbutton-logger;1"] - .getService(CI.nsISupports).wrappedJSObject; - this.torbutton_installed = true; + var tor_logger_component = CC["@torproject.org/torbutton-logger;1"]; + if (tor_logger_component) { + this.tor_logger = + tor_logger_component.getService(CI.nsISupports).wrappedJSObject; + this.torbutton_installed = true; + } } catch(e) { this.torbutton_installed = false; } + this.HTTPSEverywhere = CC["@eff.org/https-everywhere;1"] + .getService(Components.interfaces.nsISupports) + .wrappedJSObject; + /* The proxy test result starts out null until the test is attempted. * This is for UI notification purposes */ this.proxy_test_successful = null; @@ -344,10 +351,10 @@ SSLObservatory.prototype = { var host_ip = "-1"; var httpchannelinternal = subject.QueryInterface(Ci.nsIHttpChannelInternal); - try { + try { host_ip = httpchannelinternal.remoteAddress; } catch(e) { - this.log(INFO, "Could not get server IP address."); + this.log(INFO, "Could not get server IP address."); } subject.QueryInterface(Ci.nsIHttpChannel); var certchain = this.getSSLCert(subject); @@ -378,16 +385,16 @@ SSLObservatory.prototype = { } if (subject.URI.port == -1) { - this.submitChain(chainArray, fps, new String(subject.URI.host), subject, host_ip, false); + this.submitChain(chainArray, fps, new String(subject.URI.host), subject, host_ip, false); } else { - this.submitChain(chainArray, fps, subject.URI.host+":"+subject.URI.port, subject, host_ip, false); + this.submitChain(chainArray, fps, subject.URI.host+":"+subject.URI.port, subject, host_ip, false); } } } }, observatoryActive: function() { - + if (!this.myGetBoolPref("enabled")) return false; @@ -416,7 +423,7 @@ SSLObservatory.prototype = { var pbs = CC["@mozilla.org/privatebrowsing;1"].getService(CI.nsIPrivateBrowsingService); if (pbs.privateBrowsingEnabled) return false; } catch (e) { /* seamonkey or old firefox */ } - + return true; } @@ -475,7 +482,7 @@ SSLObservatory.prototype = { if (!convergence || !convergence.enabled) return null; this.log(INFO, "Convergence uses its own internal root certs; not submitting those"); - + //this.log(WARN, convergence.certificateStatus.getVerificiationStatus(chain.certArray[0])); try { var certInfo = this.extractRealLeafFromConveregenceLeaf(chain.certArray[0]); @@ -633,7 +640,13 @@ SSLObservatory.prototype = { var HTTPSEverywhere = CC["@eff.org/https-everywhere;1"] .getService(Components.interfaces.nsISupports) .wrappedJSObject; - var win = channel ? HTTPSEverywhere.getWindowForChannel(channel) : null; + var win = null; + if (channel) { + var browser = this.HTTPSEverywhere.getBrowserForChannel(channel); + if (browser) { + var win = browser.contentWindow; + } + } var req = this.buildRequest(params); req.timeout = TIMEOUT; @@ -645,10 +658,11 @@ SSLObservatory.prototype = { if (req.status == 200) { that.log(INFO, "Successful cert submission"); - if (!that.prefs.getBoolPref("extensions.https_everywhere._observatory.cache_submitted")) - if (c.fps[0] in that.already_submitted) - delete that.already_submitted[c.fps[0]]; - + if (!that.prefs.getBoolPref("extensions.https_everywhere._observatory.cache_submitted") && + c.fps[0] in that.already_submitted) { + delete that.already_submitted[c.fps[0]]; + } + // Retry up to two previously failed submissions let n = 0; for (let fp in that.delayed_submissions) { @@ -668,8 +682,9 @@ SSLObservatory.prototype = { } } else { // Submission failed - if (c.fps[0] in that.already_submitted) + if (c.fps[0] in that.already_submitted) { delete that.already_submitted[c.fps[0]]; + } try { that.log(WARN, "Cert submission failure "+req.status+": "+req.responseText); } catch(e) { @@ -677,13 +692,12 @@ SSLObservatory.prototype = { } // If we don't have too many delayed submissions, and this isn't // (somehow?) one of them, then plan to retry this submission later - if (Object.keys(that.delayed_submissions).length < MAX_DELAYED) - if (!(c.fps[0] in that.delayed_submissions)) { - that.log(WARN, "Planning to retry submission..."); - let retry = function() { that.submitChain(certArray, fps, domain, channel, host_ip, true); }; - that.delayed_submissions[c.fps[0]] = retry; - } - + if (Object.keys(that.delayed_submissions).length < MAX_DELAYED && + c.fps[0] in that.delayed_submissions) { + that.log(WARN, "Planning to retry submission..."); + let retry = function() { that.submitChain(certArray, fps, domain, channel, host_ip, true); }; + that.delayed_submissions[c.fps[0]] = retry; + } } } }; @@ -707,7 +721,7 @@ SSLObservatory.prototype = { // Send the proper header information along with the request // Do not set gzip header.. It will ruin the padding - req.setRequestHeader("X-Privacy-Info", "EFF SSL Observatory: https://eff.org/r.22c"); + req.setRequestHeader("X-Privacy-Info", "EFF SSL Observatory: https://www.eff.org/r.22c"); req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); req.setRequestHeader("Content-length", params.length); req.setRequestHeader("Connection", "close"); @@ -895,7 +909,7 @@ SSLObservatory.prototype = { encString: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', encStringS: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', - + log: function(level, str) { var econsole = CC["@mozilla.org/consoleservice;1"] .getService(CI.nsIConsoleService); @@ -906,8 +920,15 @@ SSLObservatory.prototype = { threshold = WARN; } if (level >= threshold) { - dump("SSL Observatory: "+str+"\n"); - econsole.logStringMessage("SSL Observatory: " +str); + var levelName = ["", "VERB", "DBUG", "INFO", "NOTE", "WARN"][level]; + var prefix = "SSL Observatory " + levelName + ": "; + // dump() prints to browser stdout. That's sometimes undesireable, + // so only do it when a pref is set (running from test.sh enables + // this pref). + if (this.prefs.getBoolPref("extensions.https_everywhere.log_to_stdout")) { + dump(prefix + str + "\n"); + } + econsole.logStringMessage(prefix + str); } } }; |