[tbb-commits] [torbutton/master] Bug #3455.3: Add DomainIsolator, for isolating circuit by domain.
mikeperry at torproject.org
mikeperry at torproject.org
Thu Oct 30 21:06:24 UTC 2014
commit 59445b7baed58e712bd38c02e6dc75882ff0c997
Author: Arthur Edelstein <arthuredelstein at gmail.com>
Date: Mon Jul 14 00:40:13 2014 -0700
Bug #3455.3: Add DomainIsolator, for isolating circuit by domain.
An XPCOM component that registers a ProtocolProxyChannelFilter
which sets the username/password for each web request according to
url bar domain.
---
src/chrome.manifest | 5 +-
src/components/domain-isolator.js | 128 +++++++++++++++++++++++++++++++++++++
2 files changed, 132 insertions(+), 1 deletion(-)
diff --git a/src/chrome.manifest b/src/chrome.manifest
index af44862..d211984 100644
--- a/src/chrome.manifest
+++ b/src/chrome.manifest
@@ -155,7 +155,10 @@ contract @torproject.org/torbutton-torCheckService;1 {5d57312b-5d8c-4169-b4af-e8
component {f36d72c9-9718-4134-b550-e109638331d7} components/torbutton-logger.js
contract @torproject.org/torbutton-logger;1 {f36d72c9-9718-4134-b550-e109638331d7}
+component {e33fd6d4-270f-475f-a96f-ff3140279f68} components/domain-isolator.js
+contract @torproject.org/domain-isolator;1 {e33fd6d4-270f-475f-a96f-ff3140279f68}
+
category profile-after-change CookieJarSelector @torproject.org/cookie-jar-selector;1
-# category profile-after-change RefSpoofer @torproject.org/torRefSpoofer;1
category profile-after-change TBSessionBlocker @torproject.org/torbutton-ss-blocker;1
category profile-after-change StartupObserver @torproject.org/startup-observer;1
+category profile-after-change DomainIsolator @torproject.org/domain-isolator;1
\ No newline at end of file
diff --git a/src/components/domain-isolator.js b/src/components/domain-isolator.js
new file mode 100644
index 0000000..e8e6bfa
--- /dev/null
+++ b/src/components/domain-isolator.js
@@ -0,0 +1,128 @@
+// # domain-isolator.js
+// A component for TorBrowser that puts requests from different
+// first party domains on separate tor circuits.
+
+// This file is written in call stack order (later functions
+// call earlier functions). The code file can be processed
+// with docco.js to provide clear documentation.
+
+/* jshint moz: true */
+/* global Components, console, XPCOMUtils */
+
+// ### Abbreviations
+const Cc = Components.classes, Ci = Components.interfaces, Cu = Components.utils;
+
+// Make the logger available.
+let logger = Cc["@torproject.org/torbutton-logger;1"]
+ .getService(Components.interfaces.nsISupports).wrappedJSObject;
+
+// ## mozilla namespace.
+// Useful functionality for interacting with Mozilla services.
+let mozilla = mozilla || {};
+
+// __mozilla.protocolProxyService__.
+// Mozilla's protocol proxy service, useful for managing proxy connections made
+// by the browser.
+mozilla.protocolProxyService = Cc["@mozilla.org/network/protocol-proxy-service;1"]
+ .getService(Ci.nsIProtocolProxyService);
+
+// __mozilla.thirdPartyUtil__.
+// Mozilla's Thirdy Party Utilities, for figuring out first party domain.
+mozilla.thirdPartyUtil = Cc["@mozilla.org/thirdpartyutil;1"]
+ .getService(Ci.mozIThirdPartyUtil);
+
+// __mozilla.registerProxyChannelFilter(filterFunction, positionIndex)__.
+// Registers a proxy channel filter with the Mozilla Protocol Proxy Service,
+// which will help to decide the proxy to be used for a given channel.
+// The filterFunction should expect two arguments, (aChannel, aProxy),
+// where aProxy is the proxy or list of proxies that would be used by default
+// for the given channel, and should return a new Proxy or list of Proxies.
+mozilla.registerProxyChannelFilter = function (filterFunction, positionIndex) {
+ let proxyFilter = {
+ applyFilter : function (aProxyService, aChannel, aProxy) {
+ return filterFunction(aChannel, aProxy);
+ }
+ };
+ mozilla.protocolProxyService.registerChannelFilter(proxyFilter, positionIndex);
+};
+
+// ## tor functionality.
+let tor = tor || {};
+
+// __tor.noncesForDomains__.
+// A mutable map that records what nonce we are using for each domain.
+tor.noncesForDomains = {};
+
+// __tor.socksProxyCredentials(originalProxy, domain)__.
+// Takes a proxyInfo object (originalProxy) and returns a new proxyInfo
+// object with the same properties, except the username is set to the
+// the domain, and the password is a nonce.
+tor.socksProxyCredentials = function (originalProxy, domain) {
+ // Check if we already have a nonce. If not, create
+ // one for this domain.
+ if (!tor.noncesForDomains.hasOwnProperty(domain)) {
+ tor.noncesForDomains[domain] = 0;
+ }
+ let proxy = originalProxy.QueryInterface(Ci.nsIProxyInfo);
+ return mozilla.protocolProxyService
+ .newSOCKSProxyInfo(proxy.host,
+ proxy.port,
+ domain, // username
+ tor.noncesForDomains[domain].toString(), // password
+ proxy.flags,
+ proxy.failoverTimeout,
+ proxy.failoverProxy);
+};
+
+// __tor.isolateCircuitsByDomain()__.
+// For every HTTPChannel, replaces the default SOCKS proxy with one that authenticates
+// to the SOCKS server (the tor client process) with a username (the first party domain)
+// and a nonce password. Tor provides a separate circuit for each username+password
+// combination.
+tor.isolateCircuitsByDomain = function () {
+ mozilla.registerProxyChannelFilter(function (aChannel, aProxy) {
+ try {
+ let channel = aChannel.QueryInterface(Ci.nsIHttpChannel),
+ firstPartyURI = mozilla.thirdPartyUtil.getFirstPartyURIFromChannel(channel, true)
+ .QueryInterface(Ci.nsIURI),
+ firstPartyDomain = mozilla.thirdPartyUtil
+ .getFirstPartyHostForIsolation(firstPartyURI),
+ proxy = aProxy.QueryInterface(Ci.nsIProxyInfo),
+ replacementProxy = tor.socksProxyCredentials(aProxy, firstPartyDomain);
+ logger.eclog(3, "tor SOCKS: " + channel.URI.spec + " via " +
+ replacementProxy.username + ":" + replacementProxy.password);
+ return replacementProxy;
+ } catch (err) {
+ // If we fail, then just use the default proxyInfo.
+ return aProxy;
+ }
+ }, 0);
+};
+
+// ## XPCOM component construction.
+// Module specific constants
+const kMODULE_NAME = "TorBrowser Domain Isolator";
+const kMODULE_CONTRACTID = "@torproject.org/domain-isolator;1";
+const kMODULE_CID = Components.ID("e33fd6d4-270f-475f-a96f-ff3140279f68");
+
+// Import XPCOMUtils object.
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+// DomainIsolator object. Constructor does nothing.
+function DomainIsolator() { }
+// Firefox component requirements
+DomainIsolator.prototype = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
+ classDescription: kMODULE_NAME,
+ classID: kMODULE_CID,
+ contractID: kMODULE_CONTRACTID,
+ observe: function (subject, topic, data) {
+ if (topic === "profile-after-change") {
+ logger.eclog(3, "domain isolator: set up isolating circuits by domain");
+ tor.isolateCircuitsByDomain();
+ }
+ }
+};
+
+// Assign factory to global object.
+const NSGetFactory = XPCOMUtils.generateNSGetFactory([DomainIsolator]);
More information about the tbb-commits
mailing list