diff options
Diffstat (limited to 'helpers/DATA/firefox/gnu/extensions/https-everywhere@eff.org/components')
2 files changed, 0 insertions, 1858 deletions
diff --git a/helpers/DATA/firefox/gnu/extensions/https-everywhere@eff.org/components/https-everywhere.js b/helpers/DATA/firefox/gnu/extensions/https-everywhere@eff.org/components/https-everywhere.js deleted file mode 100644 index 90f55e2..0000000 --- a/helpers/DATA/firefox/gnu/extensions/https-everywhere@eff.org/components/https-everywhere.js +++ /dev/null @@ -1,832 +0,0 @@ -// LOG LEVELS --- - -VERB=1; -DBUG=2; -INFO=3; -NOTE=4; -WARN=5; - -// PREFERENCE BRANCHES -PREFBRANCH_ROOT=0; -PREFBRANCH_RULE_TOGGLE=1; - -//--------------- - -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 - -// -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"; - -const LLVAR = "LogLevel"; - -const IOS = CC["@mozilla.org/network/io-service;1"].getService(CI.nsIIOService); -const OS = CC['@mozilla.org/observer-service;1'].getService(CI.nsIObserverService); -const LOADER = CC["@mozilla.org/moz/jssubscript-loader;1"].getService(CI.mozIJSSubScriptLoader); -const _INCLUDED = {}; - -// NoScript uses this blob to include js constructs that stored in the chrome/ -// directory, but are not attached to the Firefox UI (normally, js located -// there is attached to an Overlay and therefore is part of the UI). - -// Reasons for this: things in components/ directory cannot be split into -// separate files; things in chrome/ can be - -const INCLUDE = function(name) { - if (arguments.length > 1) - for (var j = 0, len = arguments.length; j < len; j++) - INCLUDE(arguments[j]); - else if (!_INCLUDED[name]) { - // we used to try/catch here, but that was less useful because it didn't - // produce line numbers for syntax errors - LOADER.loadSubScript("chrome://https-everywhere/content/code/" - + name + ".js"); - _INCLUDED[name] = true; - } -}; - -const WP_STATE_START = CI.nsIWebProgressListener.STATE_START; -const WP_STATE_STOP = CI.nsIWebProgressListener.STATE_STOP; -const WP_STATE_DOC = CI.nsIWebProgressListener.STATE_IS_DOCUMENT; -const WP_STATE_START_DOC = WP_STATE_START | WP_STATE_DOC; -const WP_STATE_RESTORING = CI.nsIWebProgressListener.STATE_RESTORING; - -const LF_VALIDATE_ALWAYS = CI.nsIRequest.VALIDATE_ALWAYS; -const LF_LOAD_BYPASS_ALL_CACHES = CI.nsIRequest.LOAD_BYPASS_CACHE | CI.nsICachingChannel.LOAD_BYPASS_LOCAL_CACHE; - -const NS_OK = 0; -const NS_BINDING_ABORTED = 0x804b0002; -const NS_BINDING_REDIRECTED = 0x804b0003; -const NS_ERROR_UNKNOWN_HOST = 0x804b001e; -const NS_ERROR_REDIRECT_LOOP = 0x804b001f; -const NS_ERROR_CONNECTION_REFUSED = 0x804b000e; -const NS_ERROR_NOT_AVAILABLE = 0x804b0111; - -const LOG_CONTENT_BLOCK = 1; -const LOG_CONTENT_CALL = 2; -const LOG_CONTENT_INTERCEPT = 4; -const LOG_CHROME_WIN = 8; -const LOG_XSS_FILTER = 16; -const LOG_INJECTION_CHECK = 32; -const LOG_DOM = 64; -const LOG_JS = 128; -const LOG_LEAKS = 1024; -const LOG_SNIFF = 2048; -const LOG_CLEARCLICK = 4096; -const LOG_ABE = 8192; - -const HTML_NS = "http://www.w3.org/1999/xhtml"; - -const WHERE_UNTRUSTED = 1; -const WHERE_TRUSTED = 2; -const ANYWHERE = 3; - -const N_COHORTS = 1000; - -const DUMMY_OBJ = {}; -DUMMY_OBJ.wrappedJSObject = DUMMY_OBJ; -const DUMMY_FUNC = function() {}; -const DUMMY_ARRAY = []; - -const EARLY_VERSION_CHECK = !("nsISessionStore" in CI && typeof(/ /) === "object"); - -// This is probably obsolete since the switch to the channel.redirectTo API -const OBSERVER_TOPIC_URI_REWRITE = "https-everywhere-uri-rewrite"; - -// XXX: Better plan for this? -// We need it to exist to make our updates of ChannelReplacement.js easier. -var ABE = { - consoleDump: false, - log: function(str) { - https_everywhereLog(WARN, str); - } -}; - -function xpcom_generateQI(iids) { - var checks = []; - for each (var iid in iids) { - checks.push("CI." + iid.name + ".equals(iid)"); - } - var src = checks.length - ? "if (" + checks.join(" || ") + ") return this;\n" - : ""; - return new Function("iid", src + "throw Components.results.NS_ERROR_NO_INTERFACE;"); -} - -function xpcom_checkInterfaces(iid,iids,ex) { - for (var j = iids.length; j-- >0;) { - if (iid.equals(iids[j])) return true; - } - throw ex; -} - -INCLUDE('ChannelReplacement', 'IOUtil', 'HTTPSRules', 'HTTPS', 'Thread', 'ApplicableList'); - -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.log = https_everywhereLog; - this.wrappedJSObject = this; - this.https_rules = HTTPSRules; - this.INCLUDE=INCLUDE; - this.ApplicableList = ApplicableList; - this.browser_initialised = false; // the browser is completely loaded - - this.prefs = this.get_prefs(); - this.rule_toggle_prefs = this.get_prefs(PREFBRANCH_RULE_TOGGLE); - - // We need to use observers instead of categories for FF3.0 for these: - // https://developer.mozilla.org/en/Observer_Notifications - // https://developer.mozilla.org/en/nsIObserverService. - // https://developer.mozilla.org/en/nsIObserver - // We also use the observer service to let other extensions know about URIs - // we rewrite. - this.obsService = CC["@mozilla.org/observer-service;1"] - .getService(Components.interfaces.nsIObserverService); - - if(this.prefs.getBoolPref("globalEnabled")){ - this.obsService.addObserver(this, "profile-before-change", false); - this.obsService.addObserver(this, "profile-after-change", false); - this.obsService.addObserver(this, "sessionstore-windows-restored", false); - this.obsService.addObserver(this, "browser:purge-session-history", false); - } - - var pref_service = Components.classes["@mozilla.org/preferences-service;1"] - .getService(Components.interfaces.nsIPrefBranchInternal); - var branch = pref_service.QueryInterface(Components.interfaces.nsIPrefBranchInternal); - - branch.addObserver("extensions.https_everywhere.enable_mixed_rulesets", - this, false); - branch.addObserver("security.mixed_content.block_active_content", - this, false); - - return; -} - - -// nsIContentPolicy interface -// we use numeric constants for performance sake: -const TYPE_OTHER = 1; -const TYPE_SCRIPT = 2; -const TYPE_IMAGE = 3; -const TYPE_STYLESHEET = 4; -const TYPE_OBJECT = 5; -const TYPE_DOCUMENT = 6; -const TYPE_SUBDOCUMENT = 7; -const TYPE_REFRESH = 8; -const TYPE_XBL = 9; -const TYPE_PING = 10; -const TYPE_XMLHTTPREQUEST = 11; -const TYPE_OBJECT_SUBREQUEST = 12; -const TYPE_DTD = 13; -const TYPE_FONT = 14; -const TYPE_MEDIA = 15; -// -------------- -// REJECT_SERVER = -3 -// ACCEPT = 1 - - -// Some of these types are known by arbitrary assertion at -// https://bugzilla.mozilla.org/show_bug.cgi?id=677643#c47 -// TYPE_FONT was required to fix https://trac.torproject.org/projects/tor/ticket/4194 -// TYPE_SUBDOCUMENT was required to fix https://trac.torproject.org/projects/tor/ticket/4149 -// I have NO IDEA why JS won't let me use the constants above in defining this -const shouldLoadTargets = { - 1 : true, - 3 : true, - 5 : true, - 12 : true, - 14 : true, - 7 : true -}; - - - -/* -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 - - 2. HTTPS.replaceChannel() - - 3. HTTPSRules.rewrittenURI() - - 4. HTTPSRules.potentiallyApplicableRulesets uses <target host=""> elements to identify relevant rulesets - - foreach RuleSet: - - 4. RuleSet.transformURI() - - 5. RuleSet.apply() does the tests and rewrites with RegExps, returning a string - - 4. RuleSet.transformURI() makes a new uri object for the destination string, if required - - 2. HTTPS.replaceChannel() calls channel.redirectTo() if a redirect is needed - - -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 - -HTTPS.replaceChannel() notices redirect loops (and used to do much more complex XPCOM API work in the NoScript-based past) - -HTTPSRules.rewrittenURI() works around weird URI types like about: and http://user:pass@example.com/ - and notifies the alist of what it should display for each ruleset - -*/ - -// This defines for Mozilla what stuff HTTPSEverywhere will implement. - -// ChannelEventSink used to be necessary in order to handle redirects (eg -// HTTP redirects) correctly. It may now be obsolete? XXX - -HTTPSEverywhere.prototype = { - prefs: null, - // properties required for XPCOM registration: - classDescription: SERVICE_NAME, - classID: SERVICE_ID, - contractID: SERVICE_CTRID, - - _xpcom_factory: { - createInstance: function (outer, iid) { - if (outer != null) - throw Components.results.NS_ERROR_NO_AGGREGATION; - if (!HTTPSEverywhere.instance) - HTTPSEverywhere.instance = new HTTPSEverywhere(); - return HTTPSEverywhere.instance.QueryInterface(iid); - }, - - QueryInterface: XPCOMUtils.generateQI( - [ Components.interfaces.nsISupports, - Components.interfaces.nsIModule, - Components.interfaces.nsIFactory ]) - }, - - // [optional] an array of categories to register this component in. - _xpcom_categories: [ - { - category: "app-startup", - }, - ], - - // QueryInterface implementation, e.g. using the generateQI helper - QueryInterface: XPCOMUtils.generateQI( - [ Components.interfaces.nsIObserver, - Components.interfaces.nsISupports, - Components.interfaces.nsISupportsWeakReference, - Components.interfaces.nsIWebProgressListener, - Components.interfaces.nsIWebProgressListener2, - Components.interfaces.nsIChannelEventSink ]), - - wrappedJSObject: null, // Initialized by constructor - - getWeakReference: function () { - return Components.utils.getWeakReference(this); - }, - - // 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; - } - 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); - } - }, - - // 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; - }, - - // We use onLocationChange 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"); - } - }, - - getWindowForChannel: function(channel) { - // Obtain an nsIDOMWindow from a channel - let loadContext; - try { - loadContext = channel.notificationCallbacks.getInterface(CI.nsILoadContext); - } catch(e) { - try { - loadContext = channel.loadGroup.notificationCallbacks.getInterface(CI.nsILoadContext); - } catch(e) { - this.log(NOTE, "No loadContext for " + channel.URI.spec); - return null; - } - } - - let domWin = loadContext.associatedWindow; - if (!domWin) { - this.log(NOTE, "failed to get DOMWin for " + channel.URI.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); - }, - - newApplicableListForDOMWin: function(domWin) { - if (!domWin || !(domWin instanceof CI.nsIDOMWindow)) { - this.log(WARN, "Get alist without domWin"); - return null; - } - var dw = domWin.top; - var alist = new ApplicableList(this.log,dw.document,dw); - this.setExpando(dw,"applicable_rules",alist); - return alist; - }, - - getApplicableListForDOMWin: function(domWin, where) { - if (!domWin || !(domWin instanceof CI.nsIDOMWindow)) { - //this.log(WARN, "Get alist without domWin"); - return null; - } - var dw = domWin.top; - var alist= this.getExpando(dw,"applicable_rules",null); - 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); - } - return alist; - }, - - observe: function(subject, topic, data) { - // Top level glue for the nsIObserver API - var channel = subject; - //this.log(VERB,"Got observer topic: "+topic); - - 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; - } - HTTPS.replaceChannel(lst, channel); - } else if (topic == "http-on-examine-response") { - this.log(DBUG, "Got http-on-examine-response @ "+ (channel.URI ? channel.URI.spec : '') ); - HTTPS.handleSecureCookies(channel); - } else if (topic == "http-on-examine-merged-response") { - this.log(DBUG, "Got http-on-examine-merged-response "); - HTTPS.handleSecureCookies(channel); - } else if (topic == "cookie-changed") { - // Javascript can add cookies via document.cookie that are insecure. - if (data == "added" || data == "changed") { - // subject can also be an nsIArray! bleh. - try { - subject.QueryInterface(CI.nsIArray); - var elems = subject.enumerate(); - while (elems.hasMoreElements()) { - var cookie = elems.getNext() - .QueryInterface(CI.nsICookie2); - if (!cookie.isSecure) { - HTTPS.handleInsecureCookie(cookie); - } - } - } catch(e) { - subject.QueryInterface(CI.nsICookie2); - if(!subject.isSecure) { - HTTPS.handleInsecureCookie(subject); - } - } - } - } else if (topic == "profile-before-change") { - this.log(INFO, "Got profile-before-change"); - var catman = Components.classes["@mozilla.org/categorymanager;1"] - .getService(Components.interfaces.nsICategoryManager); - catman.deleteCategoryEntry("net-channel-event-sinks", SERVICE_CTRID, true); - 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(); - - 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); - } - } else if (topic == "sessionstore-windows-restored") { - this.log(DBUG,"Got sessionstore-windows-restored"); - this.maybeShowObservatoryPopup(); - this.browser_initialised = true; - } else if (topic == "nsPref:changed") { - // If the user toggles the Mixed Content Blocker settings, reload the rulesets - // to enable/disable the mixedcontent ones - - // this pref gets set to false and then true during FF 26 startup! - // so do nothing if we're being notified during startup - if (!this.browser_initialised) - return; - switch (data) { - case "security.mixed_content.block_active_content": - case "extensions.https_everywhere.enable_mixed_rulesets": - var p = CC["@mozilla.org/preferences-service;1"].getService(CI.nsIPrefBranch); - var val = p.getBoolPref("security.mixed_content.block_active_content"); - this.log(INFO,"nsPref:changed for "+data + " to " + val); - HTTPSRules.init(); - break; - } - } else if (topic == "browser:purge-session-history") { - // The list of rulesets that have been loaded from the sqlite DB - // constitutes a parallel history store, so we have to clear it. - this.log(DBUG, "History cleared, reloading HTTPSRules to avoid information leak."); - HTTPSRules.init(); - } - return; - }, - - maybeShowObservatoryPopup: function() { - // Show the popup at most once. Users who enabled the Observatory before - // a version that would have shown it to them, don't need to see it - // again. - var ssl_observatory = CC["@eff.org/ssl-observatory;1"] - .getService(Components.interfaces.nsISupports) - .wrappedJSObject; - var shown = ssl_observatory.myGetBoolPref("popup_shown"); - var enabled = ssl_observatory.myGetBoolPref("enabled"); - var that = this; - var obs_popup_callback = function(result) { - if (result) that.log(INFO, "Got positive proxy test."); - else that.log(INFO, "Got negative proxy text."); - // We are now ready to show the popup in its most informative state - that.chrome_opener("chrome://https-everywhere/content/observatory-popup.xul"); - }; - if (!shown && !enabled) - ssl_observatory.registerProxyTestNotification(obs_popup_callback); - - if (shown && enabled) - this.maybeCleanupObservatoryPrefs(ssl_observatory); - }, - - maybeCleanupObservatoryPrefs: function(ssl_observatory) { - // Recover from a past UI processing bug that would leave the Obsevatory - // accidentally disabled for some users - // https://trac.torproject.org/projects/tor/ticket/10728 - var clean = ssl_observatory.myGetBoolPref("clean_config"); - if (clean) return; - - // unchanged: returns true if a pref has not been modified - var unchanged = function(p){return !ssl_observatory.prefs.prefHasUserValue("extensions.https_everywhere._observatory."+p)}; - var cleanup_obsprefs_callback = function(tor_avail) { - // we only run this once - ssl_observatory.prefs.setBoolPref("extensions.https_everywhere._observatory.clean_config", true); - if (!tor_avail) { - // use_custom_proxy is the variable that is often false when it should be true; - if (!ssl_observatory.myGetBoolPref("use_custom_proxy")) { - // however don't do anything if any of the prefs have been set by the user - if (unchanged("alt_roots") && unchanged("self_signed") && unchanged ("send_asn") && unchanged("priv_dns")) { - ssl_observatory.prefs.setBoolPref("extensions.https_everywhere._observatory.use_custom_proxy", true); - } - } - } - } - ssl_observatory.registerProxyTestNotification(cleanup_obsprefs_callback); - }, - - - getExperimentalFeatureCohort: function() { - // This variable is used for gradually turning on features for testing and - // scalability purposes. It is a random integer [0,N_COHORTS) generated - // once and stored thereafter. - // - // This is not currently used/called in the development branch - var cohort; - try { - cohort = this.prefs.getIntPref("experimental_feature_cohort"); - } catch(e) { - cohort = Math.round(Math.random() * N_COHORTS); - this.prefs.setIntPref("experimental_feature_cohort", cohort); - } - return cohort; - }, - - // nsIChannelEventSink implementation - // XXX This was here for rewrites in the past. Do we still need it? - onChannelRedirect: function(oldChannel, newChannel, flags) { - const uri = newChannel.URI; - this.log(DBUG,"Got onChannelRedirect to "+uri.spec); - if (!(newChannel instanceof CI.nsIHttpChannel)) { - this.log(DBUG, newChannel + " is not an instance of nsIHttpChannel"); - return; - } - var alist = this.juggleApplicableListsDuringRedirection(oldChannel, newChannel); - HTTPS.replaceChannel(alist,newChannel); - }, - - 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 old_alist = null; - if (domWin) - old_alist = this.getExpando(domWin,"applicable_rules", null); - domWin = this.getWindowForChannel(newChannel); - if (!domWin) return null; - var new_alist = this.getExpando(domWin,"applicable_rules", null); - if (old_alist && !new_alist) { - new_alist = old_alist; - this.setExpando(domWin,"applicable_rules",new_alist); - } else if (!new_alist) { - new_alist = new ApplicableList(this.log, domWin.document, domWin); - this.setExpando(domWin,"applicable_rules",new_alist); - } - return new_alist; - }, - - asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback) { - this.onChannelRedirect(oldChannel, newChannel, flags); - callback.onRedirectVerifyCallback(0); - }, - - get_prefs: function(prefBranch) { - if(!prefBranch) prefBranch = PREFBRANCH_ROOT; - - // get our preferences branch object - // FIXME: Ugly hack stolen from https - var branch_name; - if(prefBranch == PREFBRANCH_RULE_TOGGLE) - branch_name = "extensions.https_everywhere.rule_toggle."; - else - branch_name = "extensions.https_everywhere."; - var o_prefs = false; - var o_branch = false; - // this function needs to be called from inside https_everywhereLog, so - // it needs to do its own logging... - var econsole = Components.classes["@mozilla.org/consoleservice;1"] - .getService(Components.interfaces.nsIConsoleService); - - o_prefs = Components.classes["@mozilla.org/preferences-service;1"] - .getService(Components.interfaces.nsIPrefService); - - if (!o_prefs) - { - econsole.logStringMessage("HTTPS Everywhere: Failed to get preferences-service!"); - return false; - } - - o_branch = o_prefs.getBranch(branch_name); - if (!o_branch) - { - econsole.logStringMessage("HTTPS Everywhere: Failed to get prefs branch!"); - return false; - } - - if(prefBranch == PREFBRANCH_ROOT) { - // make sure there's an entry for our log level - try { - o_branch.getIntPref(LLVAR); - } catch (e) { - econsole.logStringMessage("Creating new about:config https_everywhere.LogLevel variable"); - o_branch.setIntPref(LLVAR, WARN); - } - } - - return o_branch; - }, - - chrome_opener: function(uri, args) { - // we don't use window.open, because we need to work around TorButton's - // state control - args = args || 'chrome,centerscreen'; - return CC['@mozilla.org/appshell/window-mediator;1'] - .getService(CI.nsIWindowMediator) - .getMostRecentWindow('navigator:browser') - .open(uri,'', args ); - }, - - tab_opener: function(uri) { - var gb = CC['@mozilla.org/appshell/window-mediator;1'] - .getService(CI.nsIWindowMediator) - .getMostRecentWindow('navigator:browser') - .gBrowser; - var tab = gb.addTab(uri); - gb.selectedTab = tab; - return tab; - }, - - toggleEnabledState: function() { - 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 = 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(!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); - } - } - } -}; - -var prefs = 0; -var econsole = 0; -function https_everywhereLog(level, str) { - if (prefs == 0) { - prefs = HTTPSEverywhere.instance.get_prefs(); - econsole = Components.classes["@mozilla.org/consoleservice;1"] - .getService(Components.interfaces.nsIConsoleService); - } - try { - var threshold = prefs.getIntPref(LLVAR); - } catch (e) { - econsole.logStringMessage( "HTTPS Everywhere: Failed to read about:config LogLevel"); - threshold = WARN; - } - if (level >= threshold) { - dump("HTTPS Everywhere: "+str+"\n"); - econsole.logStringMessage("HTTPS Everywhere: " +str); - } -} - -/** -* XPCOMUtils.generateNSGetFactory was introduced in Mozilla 2 (Firefox 4). -* XPCOMUtils.generateNSGetModule is for Mozilla 1.9.2 (Firefox 3.6). -*/ -if (XPCOMUtils.generateNSGetFactory) - var NSGetFactory = XPCOMUtils.generateNSGetFactory([HTTPSEverywhere]); -else - var NSGetModule = XPCOMUtils.generateNSGetModule([HTTPSEverywhere]); - -/* vim: set tabstop=4 expandtab: */ diff --git a/helpers/DATA/firefox/gnu/extensions/https-everywhere@eff.org/components/ssl-observatory.js b/helpers/DATA/firefox/gnu/extensions/https-everywhere@eff.org/components/ssl-observatory.js deleted file mode 100644 index 7b301d1..0000000 --- a/helpers/DATA/firefox/gnu/extensions/https-everywhere@eff.org/components/ssl-observatory.js +++ /dev/null @@ -1,1026 +0,0 @@ -const Ci = Components.interfaces; -const Cc = Components.classes; -const Cr = Components.results; - -const CI = Components.interfaces; -const CC = Components.classes; -const CR = Components.results; -const CU = Components.utils; - -// Log levels -VERB=1; -DBUG=2; -INFO=3; -NOTE=4; -WARN=5; - -BASE_REQ_SIZE=4096; -MAX_OUTSTANDING = 20; // Max # submission XHRs in progress -MAX_DELAYED = 32; // Max # XHRs are waiting around to be sent or retried -TIMEOUT = 60000; - -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 - -// XXX: We should make the _observatory tree relative. -LLVAR="extensions.https_everywhere.LogLevel"; - -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -Components.utils.import("resource://gre/modules/ctypes.jsm"); - - -const OS = Cc['@mozilla.org/observer-service;1'].getService(CI.nsIObserverService); - -const SERVICE_CTRID = "@eff.org/ssl-observatory;1"; -const SERVICE_ID=Components.ID("{0f9ab521-986d-4ad8-9c1f-6934e195c15c}"); -const SERVICE_NAME = "Anonymously Submits SSL certificates to EFF for security auditing."; -const LOADER = CC["@mozilla.org/moz/jssubscript-loader;1"].getService(CI.mozIJSSubScriptLoader); - -const _INCLUDED = {}; - -const INCLUDE = function(name) { - if (arguments.length > 1) - for (var j = 0, len = arguments.length; j < len; j++) - INCLUDE(arguments[j]); - else if (!_INCLUDED[name]) { - try { - LOADER.loadSubScript("chrome://https-everywhere/content/code/" - + name + ".js"); - _INCLUDED[name] = true; - } catch(e) { - dump("INCLUDE " + name + ": " + e + "\n"); - } - } -}; - -INCLUDE('Root-CAs'); -INCLUDE('sha256'); -INCLUDE('X509ChainWhitelist'); -INCLUDE('NSS'); - -function SSLObservatory() { - this.prefs = CC["@mozilla.org/preferences-service;1"] - .getService(CI.nsIPrefBranch); - - try { - // Check for torbutton - this.tor_logger = CC["@torproject.org/torbutton-logger;1"] - .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; - this.proxy_test_callback = null; - this.cto_url = "https://check.torproject.org/?TorButton=true"; - // a regexp to match the above URL - this.cto_regexp = RegExp("^https://check\\.torproject\\.org/"); - - this.public_roots = root_ca_hashes; - - // Clear these on cookies-cleared observer event - this.already_submitted = {}; - this.delayed_submissions = {}; - - // Figure out the url to submit to - this.submit_host = null; - this.findSubmissionTarget(); - - // Used to track current number of pending requests to the server - this.current_outstanding_requests = 0; - - // We can't always know private browsing state per request, sometimes - // we have to guess based on what we've seen in the past - this.everSeenPrivateBrowsing = false; - - // Generate nonce to append to url, to catch in nsIProtocolProxyFilter - // and to protect against CSRF - this.csrf_nonce = "#"+Math.random().toString()+Math.random().toString(); - - this.compatJSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON); - - var pref_service = Components.classes["@mozilla.org/preferences-service;1"] - .getService(Components.interfaces.nsIPrefBranchInternal); - var branch = pref_service.QueryInterface(Components.interfaces.nsIPrefBranchInternal); - - branch.addObserver("extensions.https_everywhere._observatory.enabled", - this, false); - - if (this.myGetBoolPref("enabled")) { - OS.addObserver(this, "cookie-changed", 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_STATE_REQUEST); - } - - // Register protocolproxyfilter - this.pps = CC["@mozilla.org/network/protocol-proxy-service;1"] - .getService(CI.nsIProtocolProxyService); - - this.pps.registerFilter(this, 0); - this.wrappedJSObject = this; - - this.client_asn = ASN_PRIVATE; - if (this.myGetBoolPref("send_asn")) - this.setupASNWatcher(); - - try { - NSS.initialize(""); - } catch(e) { - this.log(WARN, "Failed to initialize NSS component:" + e); - } - - this.testProxySettings(); - - this.log(DBUG, "Loaded observatory component!"); -} - -SSLObservatory.prototype = { - // QueryInterface implementation, e.g. using the generateQI helper - QueryInterface: XPCOMUtils.generateQI( - [ CI.nsIObserver, - CI.nsIProtocolProxyFilter, - //CI.nsIWifiListener, - CI.nsIWebProgressListener, - CI.nsISupportsWeakReference, - CI.nsIInterfaceRequestor]), - - wrappedJSObject: null, // Initialized by constructor - - // properties required for XPCOM registration: - classDescription: SERVICE_NAME, - classID: SERVICE_ID, - contractID: SERVICE_CTRID, - - // https://developer.mozilla.org/En/How_to_check_the_security_state_of_an_XMLHTTPRequest_over_SSL - getSSLCertChain: function(channel) { - try { - // Do we have a valid channel argument? - if (!channel instanceof Ci.nsIChannel) { - return null; - } - var secInfo = channel.securityInfo; - - // Print general connection security state - if (secInfo instanceof Ci.nsITransportSecurityInfo) { - secInfo.QueryInterface(Ci.nsITransportSecurityInfo); - } else { - return null; - } - - if (secInfo instanceof Ci.nsISSLStatusProvider) { - return secInfo.QueryInterface(Ci.nsISSLStatusProvider). - SSLStatus.QueryInterface(Ci.nsISSLStatus).serverCert; - } - return null; - } catch(err) { - return null; - } - }, - - findSubmissionTarget: function() { - // Compute the URL that the Observatory will currently submit to - var host = this.prefs.getCharPref("extensions.https_everywhere._observatory.server_host"); - // Rebuild the regexp iff the host has changed - if (host != this.submit_host) { - this.submit_host = host; - this.submit_url = "https://" + host + "/submit_cert"; - this.submission_regexp = RegExp("^" + this.regExpEscape(this.submit_url)); - } - }, - - regExpEscape: function(s) { - // Borrowed from the Closure Library, - // https://closure-library.googlecode.com/svn/docs/closure_goog_string_string.js.source.html - return String(s).replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').replace(/\x08/g, '\\x08'); - }, - - notifyCertProblem: function(socketInfo, status, targetSite) { - this.log(NOTE, "cert warning for " + targetSite); - if (targetSite == "observatory.eff.org") { - this.log(WARN, "Surpressing observatory warning"); - return true; - } - return false; - }, - - setupASNWatcher: function() { - this.getClientASN(); - this.max_ap = null; - - // we currently do not actually do *any* ASN watching from the client - // (in other words, the db will not have ASNs for certs submitted - // through Tor, even if the user checks the "send ASN" option) - // all of this code for guessing at changes in our public IP via WiFi hints - // is therefore disabled - /* - // Observe network changes to get new ASNs - OS.addObserver(this, "network:offline-status-changed", false); - var pref_service = Cc["@mozilla.org/preferences-service;1"] - .getService(Ci.nsIPrefBranchInternal); - var proxy_branch = pref_service.QueryInterface(Ci.nsIPrefBranchInternal); - proxy_branch.addObserver("network.proxy", this, false); - - try { - var wifi_service = Cc["@mozilla.org/wifi/monitor;1"].getService(Ci.nsIWifiMonitor); - wifi_service.startWatching(this); - } catch(e) { - this.log(INFO, "Failed to register ASN change monitor: "+e); - }*/ - }, - - stopASNWatcher: function() { - this.client_asn = ASN_PRIVATE; - /* - // unhook the observers we registered above - OS.removeObserver(this, "network:offline-status-changed"); - var pref_service = Cc["@mozilla.org/preferences-service;1"] - .getService(Ci.nsIPrefBranchInternal); - var proxy_branch = pref_service.QueryInterface(Ci.nsIPrefBranchInternal); - proxy_branch.removeObserver(this, "network.proxy"); - try { - var wifi_service = Cc["@mozilla.org/wifi/monitor;1"].getService(Ci.nsIWifiMonitor); - wifi_service.stopWatching(this); - } catch(e) { - this.log(WARN, "Failed to stop wifi state monitor: "+e); - }*/ - }, - - getClientASN: function() { - // Fetch a new client ASN.. - if (!this.myGetBoolPref("send_asn")) { - this.client_asn = ASN_PRIVATE; - return; - } - else if (!this.torbutton_installed) { - this.client_asn = ASN_IMPLICIT; - return; - } - // XXX As a possible base case: the user is running Tor, is not using - // bridges, and has send_asn enabled: should we ping an eff.org URL to - // learn our ASN? - return; - }, - - /* - // Wifi status listener - onChange: function(accessPoints) { - try { - var max_ap = accessPoints[0].mac; - } catch(e) { - return null; // accessPoints[0] is undefined - } - var max_signal = accessPoints[0].signal; - var old_max_present = false; - for (var i=0; i<accessPoints.length; i++) { - if (accessPoints[i].mac == this.max_ap) { - old_max_present = true; - } - if (accessPoints[i].signal > max_signal) { - max_ap = accessPoints[i].mac; - max_signal = accessPoints[i].signal; - } - } - this.max_ap = max_ap; - if (!old_max_present) { - this.log(INFO, "Old access point is out of range. Getting new ASN"); - this.getClientASN(); - } else { - this.log(DBUG, "Old access point is still in range."); - } - }, - - // Wifi status listener - onError: function(value) { - // XXX: Do we care? - this.log(NOTE, "ASN change observer got an error: "+value); - this.getClientASN(); - }, - */ - - ourFingerprint: function(cert) { - // Calculate our custom fingerprint from an nsIX509Cert - return (cert.md5Fingerprint+cert.sha1Fingerprint).replace(":", "", "g"); - }, - - // onSecurity is used to listen for bad cert warnings - // There is also onSecurityStateChange, but it does not handle subdocuments. See git - // history for an implementation stub. - onStateChange: function(aProgress, aRequest, aState, aStatus) { - if (!aRequest) return; - var chan = null; - try { - chan = aRequest.QueryInterface(Ci.nsIHttpChannel); - } catch(e) { - return; - } - if (chan) { - if (!this.observatoryActive(chan)) return; - var certchain = this.getSSLCertChain(chan); - if (certchain) { - this.log(INFO, "Got state cert chain for " - + chan.originalURI.spec + "->" + chan.URI.spec + ", state: " + aState); - var warning = true; - this.submitCertChainForChannel(certchain, chan, warning); - } - } - }, - - observe: function(subject, topic, data) { - if (topic == "cookie-changed" && data == "cleared") { - this.already_submitted = {}; - this.delayed_submissions = {}; - this.log(INFO, "Cookies were cleared. Purging list of pending and already submitted certs"); - return; - } - - if ("http-on-examine-response" == topic) { - var channel = subject; - if (!this.observatoryActive(channel)) return; - - var certchain = this.getSSLCertChain(subject); - var warning = false; - this.submitCertChainForChannel(certchain, channel, warning); - } - - if (topic == "network:offline-status-changed" && data == "online") { - this.log(INFO, "Browser back online. Getting new ASN."); - this.getClientASN(); - return; - } - - if (topic == "nsPref:changed") { - // If the user toggles the SSL Observatory settings, we need to add or remove - // our observers - switch (data) { - case "network.proxy.ssl": - case "network.proxy.ssl_port": - case "network.proxy.socks": - case "network.proxy.socks_port": - // XXX: We somehow need to only call this once. Right now, we'll make - // like 3 calls to getClientASN().. The only thing I can think - // of is a timer... - this.log(INFO, "Proxy settings have changed. Getting new ASN"); - this.getClientASN(); - break; - case "extensions.https_everywhere._observatory.enabled": - if (this.myGetBoolPref("enabled")) { - this.pps.registerFilter(this, 0); - OS.addObserver(this, "cookie-changed", 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_STATE_REQUEST); - this.log(INFO,"SSL Observatory is now enabled via pref change!"); - } else { - try { - this.pps.unregisterFilter(this); - OS.removeObserver(this, "cookie-changed"); - OS.removeObserver(this, "http-on-examine-response"); - - var dls = CC['@mozilla.org/docloaderservice;1'] - .getService(CI.nsIWebProgress); - dls.removeProgressListener(this); - this.log(INFO,"SSL Observatory is now disabled via pref change!"); - } catch(e) { - this.log(WARN, "Removing SSL Observatory observers failed: "+e); - } - } - break; - } - return; - } - - }, - - submitCertChainForChannel: function(certchain, channel, warning) { - if (!certchain) { - return; - } - var host_ip = "-1"; - var httpchannelinternal = channel.QueryInterface(Ci.nsIHttpChannelInternal); - try { - host_ip = httpchannelinternal.remoteAddress; - } catch(e) { - this.log(INFO, "Could not get server IP address."); - } - - channel.QueryInterface(Ci.nsIHttpChannel); - var chainEnum = certchain.getChain(); - var chainArray = []; - var chainArrayFpStr = ''; - var fps = []; - for(var i = 0; i < chainEnum.length; i++) { - var cert = chainEnum.queryElementAt(i, Ci.nsIX509Cert); - chainArray.push(cert); - var fp = this.ourFingerprint(cert); - fps.push(fp); - chainArrayFpStr = chainArrayFpStr + fp; - } - var chain_hash = sha256_digest(chainArrayFpStr).toUpperCase(); - this.log(INFO, "SHA-256 hash of cert chain for "+new String(channel.URI.host)+" is "+ chain_hash); - - if(!this.myGetBoolPref("use_whitelist")) { - this.log(WARN, "Not using whitelist to filter cert chains."); - } - else if (this.isChainWhitelisted(chain_hash)) { - this.log(INFO, "This cert chain is whitelisted. Not submitting."); - return; - } - else { - this.log(INFO, "Cert chain is NOT whitelisted. Proceeding with submission."); - } - - if (channel.URI.port == -1) { - this.submitChainArray(chainArray, fps, new String(channel.URI.host), channel, host_ip, warning, false); - } else { - this.submitChainArray(chainArray, fps, channel.URI.host+":"+channel.URI.port, channel, host_ip, warning, false); - } - }, - - observatoryActive: function(channel) { - - if (!this.myGetBoolPref("enabled")) - return false; - - if (this.torbutton_installed && this.proxy_test_successful) { - // Allow Tor users to choose if they want to submit - // during tor and/or non-tor - if (this.myGetBoolPref("submit_during_tor") && - this.prefs.getBoolPref("extensions.torbutton.tor_enabled")) - return true; - - if (this.myGetBoolPref("submit_during_nontor") && - !this.prefs.getBoolPref("extensions.torbutton.tor_enabled")) - return true; - - return false; - } - - if (this.proxy_test_successful) { - return true; - } else if (this.myGetBoolPref("use_custom_proxy")) { - // no torbutton; the custom proxy is probably the user opting to - // submit certs without strong anonymisation. Because the - // anonymisation is weak, we avoid submitting during private browsing - // mode. - var pbm = this.inPrivateBrowsingMode(channel); - this.log(DBUG, "Private browsing mode: " + pbm); - return !pbm; - } - }, - - inPrivateBrowsingMode: function(channel) { - // In classic firefox fashion, there are multiple versions of this API - // https://developer.mozilla.org/EN/docs/Supporting_per-window_private_browsing - try { - // Firefox 20+, this state is per-window; - // should raise an exception on FF < 20 - CU.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); - if (!(channel instanceof CI.nsIHttpChannel)) { - this.log(NOTE, "observatoryActive() without a channel"); - // This is a windowless request. We cannot tell if private browsing - // applies. Conservatively, if we have ever seen PBM, it might be - // active now - return this.everSeenPrivateBrowsing; - } - var win = this.HTTPSEverywhere.getWindowForChannel(channel); - if (!win) return this.everSeenPrivateBrowsing; // windowless request - - if (PrivateBrowsingUtils.isWindowPrivate(win)) { - this.everSeenPrivateBrowsing = true; - return true; - } - } catch (e) { - // Firefox < 20, this state is global - try { - var pbs = CC["@mozilla.org/privatebrowsing;1"].getService(CI.nsIPrivateBrowsingService); - if (pbs.privateBrowsingEnabled) { - this.everSeenPrivateBrowsing = true; - return true; - } - } catch (e) { /* seamonkey or very old firefox */ } - } - return false; - }, - - myGetBoolPref: function(prefstring) { - // syntactic sugar - return this.prefs.getBoolPref ("extensions.https_everywhere._observatory." + prefstring); - }, - - isChainWhitelisted: function(chainhash) { - if (X509ChainWhitelist == null) { - this.log(WARN, "Could not find whitelist of popular certificate chains, so ignoring whitelist"); - return false; - } - if (X509ChainWhitelist[chainhash] != null) { - return true; - } - return false; - }, - - findRootInChain: function(certArray) { - // Return the position in the chain Array of the/a root CA - var rootidx = -1; - var nextInChain = certArray[0].issuer; - for (var i = 0; i < certArray.length; i++) { - // Find the next cert in the valid chain - if (certArray[i].equals(nextInChain)) { - if (certArray[i].issuerName == certArray[i].subjectName) { - // All X509 root certs are self-signed - this.log(INFO, "Got root cert at position: "+i); - rootidx = i; - break; - } else { - // This is an intermediate CA cert; keep looking for the root - nextInChain = certArray[i].issuer; - } - } - } - return rootidx; - }, - - processConvergenceChain: function(chain) { - // Make sure the chain we're working with is sane, even if Convergence is - // present. - - // Convergence currently performs MITMs against the Firefox in order to - // get around https://bugzilla.mozilla.org/show_bug.cgi?id=644640. The - // end-entity cert produced by Convergence contains a copy of the real - // end-entity cert inside an X509v3 extension. We extract this and send - // it rather than the Convergence certs. - var convergence = Components.classes['@thoughtcrime.org/convergence;1']; - if (!convergence) return null; - convergence = convergence.getService().wrappedJSObject; - 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]); - var b64Cert = certInfo["certificate"]; - var certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB); - chain.leaf = certDB.constructX509FromBase64(b64Cert); - chain.certArray = [chain.leaf]; - chain.fps = [this.ourFingerprint(chain.leaf)]; - } catch (e) { - this.log(WARN, "Failed to extract leaf cert from Convergence cert " + e); - chain.certArray = chain.certArray.slice(0,1); - chain.fps = chain.fps.slice(0,1); - } - - }, - - extractRealLeafFromConveregenceLeaf: function(certificate) { - // Copied from Convergence's CertificateStatus.getVerificiationStatus - var len = {}; - var derEncoding = certificate.getRawDER(len); - - var derItem = NSS.types.SECItem(); - derItem.data = NSS.lib.ubuffer(derEncoding); - derItem.len = len.value; - - var completeCertificate = NSS.lib.CERT_DecodeDERCertificate(derItem.address(), 1, null); - - var extItem = NSS.types.SECItem(); - var status = NSS.lib.CERT_FindCertExtension(completeCertificate, - NSS.lib.SEC_OID_NS_CERT_EXT_COMMENT, - extItem.address()); - if (status != -1) { - var encoded = ''; - var asArray = ctypes.cast(extItem.data, ctypes.ArrayType(ctypes.unsigned_char, extItem.len).ptr).contents; - var marker = false; - - for (var i=0;i<asArray.length;i++) { - if (marker) { - encoded += String.fromCharCode(asArray[i]); - } else if (asArray[i] == 0x00) { - marker = true; - } - } - - return JSON.parse(encoded); - } - }, - - shouldSubmit: function(chain, domain) { - // Return true if we should submit this chain to the SSL Observatory - var rootidx = this.findRootInChain(chain.certArray); - var ss = false; // ss: self-signed - - if (chain.leaf.issuerName == chain.leaf.subjectName) - ss = true; - - if (!this.myGetBoolPref("self_signed") && ss) { - this.log(INFO, "Not submitting self-signed cert for " + domain); - return false; - } - - if (!ss && !this.myGetBoolPref("alt_roots")) { - if (rootidx == -1) { - // A cert with an unknown/absent Issuer. Out of caution, don't submit these - this.log(INFO, "Cert for " + domain + " issued by unknown CA " + - chain.leaf.issuerName + " (not submitting due to settings)"); - return false; - } else if (!(chain.fps[rootidx] in this.public_roots)) { - // A cert with a known but non-public Issuer - this.log(INFO, "Got a private root cert. Ignoring domain " - +domain+" with root "+chain.fps[rootidx]); - return false; - } - } - - if (chain.fps[0] in this.already_submitted) { - this.log(INFO, "Already submitted cert for "+domain+". Ignoring"); - return false; - } - return true; - }, - - submitChainArray: function(certArray, fps, domain, channel, host_ip, warning, resubmitting) { - var base64Certs = []; - // Put all this chain data in one object so that it can be modified by - // subroutines if required - var c = {}; c.certArray = certArray; c.fps = fps; c.leaf = certArray[0]; - this.processConvergenceChain(c); - if (!this.shouldSubmit(c,domain)) return; - - // only try to submit now if there aren't too many outstanding requests - if (this.current_outstanding_requests > MAX_OUTSTANDING) { - this.log(WARN, "Too many outstanding requests ("+this.current_outstanding_requests+"), not submitting"); - - // if there are too many current requests but not too many - // delayed/pending ones, then delay this one - if (Object.keys(this.delayed_submissions).length < MAX_DELAYED) - if (!(c.fps[0] in this.delayed_submissions)) { - this.log(WARN, "Planning to retry submission..."); - let retry = function() { this.submitChainArray(certArray, fps, domain, channel, host_ip, warning, true); }; - this.delayed_submissions[c.fps[0]] = retry; - } - return; - } - - for (var i = 0; i < c.certArray.length; i++) { - var len = new Object(); - var derData = c.certArray[i].getRawDER(len); - let result = ""; - for (let j = 0, dataLength = derData.length; j < dataLength; ++j) - result += String.fromCharCode(derData[j]); - base64Certs.push(btoa(result)); - } - - var reqParams = []; - reqParams.push("domain="+domain); - reqParams.push("server_ip="+host_ip); - if (this.myGetBoolPref("testing")) { - reqParams.push("testing=1"); - // The server can compute these, but they're a nice test suite item! - reqParams.push("fplist="+this.compatJSON.encode(c.fps)); - } - reqParams.push("certlist="+this.compatJSON.encode(base64Certs)); - - if (resubmitting) { - reqParams.push("client_asn="+ASN_UNKNOWABLE); - } else { - reqParams.push("client_asn="+this.client_asn); - } - - if (this.myGetBoolPref("priv_dns")) { - reqParams.push("private_opt_in=1"); - } else { - reqParams.push("private_opt_in=0"); - } - - if (warning) { - reqParams.push("browser_warning=1"); - } else { - reqParams.push("browser_warning=0"); - } - - var params = reqParams.join("&") + "&padding=0"; - var tot_len = BASE_REQ_SIZE; - - this.log(INFO, "Submitting cert for "+domain); - this.log(DBUG, "submit_cert params: "+params); - - // Pad to exp scale. This is done because the distribution of cert sizes - // is almost certainly pareto, and definitely not uniform. - for (tot_len = BASE_REQ_SIZE; tot_len < params.length; tot_len*=2); - - while (params.length != tot_len) { - params += "0"; - } - - var that = this; // We have neither SSLObservatory nor this in scope in the lambda - - var win = channel ? this.HTTPSEverywhere.getWindowForChannel(channel) : null; - var req = this.buildRequest(params); - req.timeout = TIMEOUT; - - req.onreadystatechange = function(evt) { - if (req.readyState == 4) { - // pop off one outstanding request - that.current_outstanding_requests -= 1; - that.log(DBUG, "Popping one off of outstanding requests, current num is: "+that.current_outstanding_requests); - - 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]]; - - // Retry up to two previously failed submissions - let n = 0; - for (let fp in that.delayed_submissions) { - that.log(WARN, "Retrying a submission..."); - that.delayed_submissions[fp](); - delete that.delayed_submissions[fp]; - if (++n >= 2) break; - } - } else if (req.status == 403) { - that.log(WARN, "The SSL Observatory has issued a warning about this certificate for " + domain); - try { - var warningObj = JSON.parse(req.responseText); - if (win) that.warnUser(warningObj, win, c.certArray[0]); - } catch(e) { - that.log(WARN, "Failed to process SSL Observatory cert warnings :( " + e); - that.log(WARN, req.responseText); - } - } else { - // Submission failed - 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) { - that.log(WARN, "Cert submission failure and exception: "+e); - } - // 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.submitChainArray(certArray, fps, domain, channel, host_ip, warning, true); }; - that.delayed_submissions[c.fps[0]] = retry; - } - - } - } - }; - - // Cache this here to prevent multiple submissions for all the content elements. - that.already_submitted[c.fps[0]] = true; - - // add one to current outstanding request number - that.current_outstanding_requests += 1; - that.log(DBUG, "Adding outstanding request, current num is: "+that.current_outstanding_requests); - req.send(params); - }, - - buildRequest: function(params) { - var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"] - .createInstance(Ci.nsIXMLHttpRequest); - - // We do this again in case the user altered about:config - this.findSubmissionTarget(); - req.open("POST", this.submit_url+this.csrf_nonce, true); - - // 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("Content-type", "application/x-www-form-urlencoded"); - req.setRequestHeader("Content-length", params.length); - req.setRequestHeader("Connection", "close"); - // Need to clear useragent and other headers.. - req.setRequestHeader("User-Agent", ""); - req.setRequestHeader("Accept", ""); - req.setRequestHeader("Accept-Language", ""); - req.setRequestHeader("Accept-Encoding", ""); - req.setRequestHeader("Accept-Charset", ""); - return req; - }, - - warnUser: function(warningObj, win, cert) { - var aWin = CC['@mozilla.org/appshell/window-mediator;1'] - .getService(CI.nsIWindowMediator) - .getMostRecentWindow('navigator:browser'); - aWin.openDialog("chrome://https-everywhere/content/observatory-warning.xul", - "","chrome,centerscreen", warningObj, win, cert); - }, - - registerProxyTestNotification: function(callback_fcn) { - if (this.proxy_test_successful != null) { - /* Proxy test already ran. Callback immediately. */ - callback_fcn(this.proxy_test_successful); - this.proxy_test_callback = null; - return; - } else { - this.proxy_test_callback = callback_fcn; - } - }, - - testProxySettings: function() { - /* Plan: - * 1. Launch an async XMLHttpRequest to check.tp.o with magic nonce - * 3. Filter the nonce in protocolProxyFilter to use proxy settings - * 4. Async result function sets test result status based on check.tp.o - */ - this.proxy_test_successful = null; - - try { - var req = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"] - .createInstance(Components.interfaces.nsIXMLHttpRequest); - var url = this.cto_url + this.csrf_nonce; - req.open('GET', url, true); - req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE; - req.overrideMimeType("text/xml"); - var that = this; // Scope gymnastics for async callback - req.onreadystatechange = function (oEvent) { - if (req.readyState === 4) { - that.proxy_test_successful = false; - - if(req.status == 200) { - if(!req.responseXML) { - that.log(INFO, "Tor check failed: No XML returned by check service."); - that.proxyTestFinished(); - return; - } - - var result = req.responseXML.getElementById('TorCheckResult'); - if(result===null) { - that.log(INFO, "Tor check failed: Non-XML returned by check service."); - } else if(typeof(result.target) == 'undefined' - || result.target === null) { - that.log(INFO, "Tor check failed: Busted XML returned by check service."); - } else if(result.target === "success") { - that.log(INFO, "Tor check succeeded."); - that.proxy_test_successful = true; - } else { - that.log(INFO, "Tor check failed: "+result.target); - } - } else { - that.log(INFO, "Tor check failed: HTTP Error "+req.status); - } - - /* Notify the UI of the test result */ - if (that.proxy_test_callback) { - that.proxy_test_callback(that.proxy_test_successful); - that.proxy_test_callback = null; - } - that.proxyTestFinished(); - } - }; - req.send(null); - } catch(e) { - this.proxy_test_successful = false; - if(e.result == 0x80004005) { // NS_ERROR_FAILURE - this.log(INFO, "Tor check failed: Proxy not running."); - } - this.log(INFO, "Tor check failed: Internal error: "+e); - if (this.proxy_test_callback) { - this.proxy_test_callback(this.proxy_test_successful); - this.proxy_test_callback = null; - } - that.proxyTestFinished(); - } - }, - - proxyTestFinished: function() { - if (!this.myGetBoolPref("enabled")) { - this.pps.unregisterFilter(this); - } - }, - - getProxySettings: function(testingForTor) { - // This may be called either for an Observatory submission, or during a test to see if Tor is - // present. The testingForTor argument is true in the latter case. - var proxy_settings = ["direct", "", 0]; - this.log(INFO,"in getProxySettings()"); - var custom_proxy_type = this.prefs.getCharPref("extensions.https_everywhere._observatory.proxy_type"); - if (this.torbutton_installed && this.myGetBoolPref("use_tor_proxy")) { - this.log(INFO,"CASE: use_tor_proxy"); - // extract torbutton proxy settings - proxy_settings[0] = "http"; - proxy_settings[1] = this.prefs.getCharPref("extensions.torbutton.https_proxy"); - proxy_settings[2] = this.prefs.getIntPref("extensions.torbutton.https_port"); - - if (proxy_settings[2] == 0) { - proxy_settings[0] = "socks"; - proxy_settings[1] = this.prefs.getCharPref("extensions.torbutton.socks_host"); - proxy_settings[2] = this.prefs.getIntPref("extensions.torbutton.socks_port"); - } - /* Regarding the test below: - * - * custom_proxy_type == "direct" is indicative of the user having selected "submit certs even if - * Tor is not available", rather than true custom Tor proxy settings. So in that case, there's - * not much point probing to see if the direct proxy is actually a Tor connection, and - * localhost:9050 is a better bet. People whose networks send all traffc through Tor can just - * tell the Observatory to submit certs without Tor. - */ - } else if (this.myGetBoolPref("use_custom_proxy") && !(testingForTor && custom_proxy_type == "direct")) { - this.log(INFO,"CASE: use_custom_proxy"); - proxy_settings[0] = custom_proxy_type; - proxy_settings[1] = this.prefs.getCharPref("extensions.https_everywhere._observatory.proxy_host"); - proxy_settings[2] = this.prefs.getIntPref("extensions.https_everywhere._observatory.proxy_port"); - } else { - /* Take a guess at default tor proxy settings */ - this.log(INFO,"CASE: try localhost:9050"); - proxy_settings[0] = "socks"; - proxy_settings[1] = "localhost"; - proxy_settings[2] = 9050; - } - this.log(INFO, "Using proxy: " + proxy_settings); - return proxy_settings; - }, - - applyFilter: function(aProxyService, inURI, aProxy) { - - try { - if (inURI instanceof Ci.nsIURI) { - var aURI = inURI.QueryInterface(Ci.nsIURI); - if (!aURI) this.log(WARN, "Failed to QI to nsIURI!"); - } else { - this.log(WARN, "applyFilter called without URI"); - } - } catch (e) { - this.log(WARN, "EXPLOSION: " + e); - } - - var isSubmission = this.submission_regexp.test(aURI.spec); - var testingForTor = this.cto_regexp.test(aURI.spec); - - if (isSubmission || testingForTor) { - if (aURI.path.search(this.csrf_nonce+"$") != -1) { - - this.log(INFO, "Got observatory url + nonce: "+aURI.spec); - var proxy_settings = null; - var proxy = null; - - // Send it through tor by creating an nsIProxy instance - // for the torbutton proxy settings. - try { - proxy_settings = this.getProxySettings(testingForTor); - proxy = this.pps.newProxyInfo(proxy_settings[0], proxy_settings[1], - proxy_settings[2], - Ci.nsIProxyInfo.TRANSPARENT_PROXY_RESOLVES_HOST, - 0xFFFFFFFF, null); - } catch(e) { - this.log(WARN, "Error specifying proxy for observatory: "+e); - } - - this.log(INFO, "Specifying proxy: "+proxy); - - // TODO: Use new identity or socks u/p to ensure we get a unique - // tor circuit for this request - return proxy; - } - } - return aProxy; - }, - - // [optional] an array of categories to register this component in. - // Hack to cause us to get instantiate early - _xpcom_categories: [ { category: "profile-after-change" }, ], - - encString: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', - encStringS: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', - - log: function(level, str) { - var econsole = CC["@mozilla.org/consoleservice;1"] - .getService(CI.nsIConsoleService); - try { - var threshold = this.prefs.getIntPref(LLVAR); - } catch (e) { - econsole.logStringMessage( "SSL Observatory: Failed to read about:config LogLevel"); - threshold = WARN; - } - if (level >= threshold) { - dump("SSL Observatory: "+str+"\n"); - econsole.logStringMessage("SSL Observatory: " +str); - } - } -}; - -/** -* XPCOMUtils.generateNSGetFactory was introduced in Mozilla 2 (Firefox 4). -* XPCOMUtils.generateNSGetModule is for Mozilla 1.9.2 (Firefox 3.6). -*/ -if (XPCOMUtils.generateNSGetFactory) - var NSGetFactory = XPCOMUtils.generateNSGetFactory([SSLObservatory]); -else - var NSGetModule = XPCOMUtils.generateNSGetModule([SSLObservatory]); |