... |
... |
@@ -58,7 +58,11 @@ let tor = {}; |
58
|
58
|
|
59
|
59
|
// __tor.noncesForDomains__.
|
60
|
60
|
// A mutable map that records what nonce we are using for each domain.
|
61
|
|
-tor.noncesForDomains = {};
|
|
61
|
+tor.noncesForDomains = new Map();
|
|
62
|
+
|
|
63
|
+// __tor.noncesForUserContextId__.
|
|
64
|
+// A mutable map that records what nonce we are using for each tab container.
|
|
65
|
+tor.noncesForUserContextId = new Map();
|
62
|
66
|
|
63
|
67
|
// __tor.isolationEabled__.
|
64
|
68
|
// A bool that controls if we use SOCKS auth for isolation or not.
|
... |
... |
@@ -68,23 +72,37 @@ tor.isolationEnabled = true; |
68
|
72
|
// Specifies when the current catch-all circuit was first used
|
69
|
73
|
tor.unknownDirtySince = Date.now();
|
70
|
74
|
|
71
|
|
-// __tor.socksProxyCredentials(originalProxy, domain)__.
|
72
|
|
-// Takes a proxyInfo object (originalProxy) and returns a new proxyInfo
|
73
|
|
-// object with the same properties, except the username is set to the
|
74
|
|
-// the domain, and the password is a nonce.
|
75
|
|
-tor.socksProxyCredentials = function(originalProxy, domain) {
|
|
75
|
+tor.passwordForDomainAndUserContextId = function(domain, userContextId) {
|
76
|
76
|
// Check if we already have a nonce. If not, create
|
77
|
|
- // one for this domain.
|
78
|
|
- if (!tor.noncesForDomains.hasOwnProperty(domain)) {
|
79
|
|
- tor.noncesForDomains[domain] = tor.nonce();
|
|
77
|
+ // one for this domain and userContextId.
|
|
78
|
+ if (!tor.noncesForDomains.has(domain)) {
|
|
79
|
+ tor.noncesForDomains.set(domain, tor.nonce());
|
|
80
|
+ }
|
|
81
|
+ if (!tor.noncesForUserContextId.has(userContextId)) {
|
|
82
|
+ tor.noncesForUserContextId.set(userContextId, tor.nonce());
|
80
|
83
|
}
|
|
84
|
+ return (
|
|
85
|
+ tor.noncesForDomains.get(domain) +
|
|
86
|
+ tor.noncesForUserContextId.get(userContextId)
|
|
87
|
+ );
|
|
88
|
+};
|
|
89
|
+
|
|
90
|
+// __tor.socksProxyCredentials(originalProxy, domain, userContextId)__.
|
|
91
|
+// Takes a proxyInfo object (originalProxy) and returns a new proxyInfo
|
|
92
|
+// object with the same properties, except the username is set to the
|
|
93
|
+// the domain and userContextId, and the password is a nonce.
|
|
94
|
+tor.socksProxyCredentials = function(originalProxy, domain, userContextId) {
|
81
|
95
|
let proxy = originalProxy.QueryInterface(Ci.nsIProxyInfo);
|
|
96
|
+ let proxyPassword = tor.passwordForDomainAndUserContextId(
|
|
97
|
+ domain,
|
|
98
|
+ userContextId
|
|
99
|
+ );
|
82
|
100
|
return mozilla.protocolProxyService.newProxyInfoWithAuth(
|
83
|
101
|
"socks",
|
84
|
102
|
proxy.host,
|
85
|
103
|
proxy.port,
|
86
|
|
- domain, // username
|
87
|
|
- tor.noncesForDomains[domain], // password
|
|
104
|
+ `${domain}:${userContextId}`, // username
|
|
105
|
+ proxyPassword,
|
88
|
106
|
"", // aProxyAuthorizationHeader
|
89
|
107
|
"", // aConnectionIsolationKey
|
90
|
108
|
proxy.flags,
|
... |
... |
@@ -116,10 +134,21 @@ tor.newCircuitForDomain = function(domain) { |
116
|
134
|
if (domain === "") {
|
117
|
135
|
domain = "--unknown--";
|
118
|
136
|
}
|
119
|
|
- tor.noncesForDomains[domain] = tor.nonce();
|
|
137
|
+ tor.noncesForDomains.set(domain, tor.nonce());
|
|
138
|
+ logger.eclog(
|
|
139
|
+ 3,
|
|
140
|
+ `New domain isolation for ${domain}: ${tor.noncesForDomains.get(domain)}`
|
|
141
|
+ );
|
|
142
|
+};
|
|
143
|
+
|
|
144
|
+tor.newCircuitForUserContextId = function(userContextId) {
|
|
145
|
+ // Re-generate the nonce for the context.
|
|
146
|
+ tor.noncesForUserContextId.set(userContextId, tor.nonce());
|
120
|
147
|
logger.eclog(
|
121
|
148
|
3,
|
122
|
|
- "New domain isolation for " + domain + ": " + tor.noncesForDomains[domain]
|
|
149
|
+ `New container isolation for ${userContextId}: ${tor.noncesForUserContextId.get(
|
|
150
|
+ userContextId
|
|
151
|
+ )}`
|
123
|
152
|
);
|
124
|
153
|
};
|
125
|
154
|
|
... |
... |
@@ -127,8 +156,9 @@ tor.newCircuitForDomain = function(domain) { |
127
|
156
|
// Clear the isolation state cache, forcing new circuits to be used for all
|
128
|
157
|
// subsequent requests.
|
129
|
158
|
tor.clearIsolation = function() {
|
130
|
|
- // Per-domain nonces are stored in a map, so simply re-initialize the map.
|
131
|
|
- tor.noncesForDomains = {};
|
|
159
|
+ // Per-domain and per contextId nonces are stored in maps, so simply clear them.
|
|
160
|
+ tor.noncesForDomains.clear();
|
|
161
|
+ tor.noncesForUserContextId.clear();
|
132
|
162
|
|
133
|
163
|
// Force a rotation on the next catch-all circuit use by setting the creation
|
134
|
164
|
// time to the epoch.
|
... |
... |
@@ -137,9 +167,9 @@ tor.clearIsolation = function() { |
137
|
167
|
|
138
|
168
|
// __tor.isolateCircuitsByDomain()__.
|
139
|
169
|
// For every HTTPChannel, replaces the default SOCKS proxy with one that authenticates
|
140
|
|
-// to the SOCKS server (the tor client process) with a username (the first party domain)
|
141
|
|
-// and a nonce password. Tor provides a separate circuit for each username+password
|
142
|
|
-// combination.
|
|
170
|
+// to the SOCKS server (the tor client process) with a username (the first party domain
|
|
171
|
+// and userContextId) and a nonce password. Tor provides a separate circuit for each
|
|
172
|
+// username+password combination.
|
143
|
173
|
tor.isolateCircuitsByDomain = function() {
|
144
|
174
|
mozilla.registerProxyChannelFilter(function(aChannel, aProxy) {
|
145
|
175
|
if (!tor.isolationEnabled) {
|
... |
... |
@@ -147,7 +177,8 @@ tor.isolateCircuitsByDomain = function() { |
147
|
177
|
}
|
148
|
178
|
try {
|
149
|
179
|
let channel = aChannel.QueryInterface(Ci.nsIChannel),
|
150
|
|
- firstPartyDomain = channel.loadInfo.originAttributes.firstPartyDomain;
|
|
180
|
+ firstPartyDomain = channel.loadInfo.originAttributes.firstPartyDomain,
|
|
181
|
+ userContextId = channel.loadInfo.originAttributes.userContextId;
|
151
|
182
|
if (firstPartyDomain === "") {
|
152
|
183
|
firstPartyDomain = "--unknown--";
|
153
|
184
|
if (Date.now() - tor.unknownDirtySince > 1000 * 10 * 60) {
|
... |
... |
@@ -161,7 +192,8 @@ tor.isolateCircuitsByDomain = function() { |
161
|
192
|
}
|
162
|
193
|
let replacementProxy = tor.socksProxyCredentials(
|
163
|
194
|
aProxy,
|
164
|
|
- firstPartyDomain
|
|
195
|
+ firstPartyDomain,
|
|
196
|
+ userContextId
|
165
|
197
|
);
|
166
|
198
|
logger.eclog(
|
167
|
199
|
3,
|
... |
... |
@@ -206,6 +238,9 @@ DomainIsolator.prototype = { |
206
|
238
|
newCircuitForDomain(domain) {
|
207
|
239
|
tor.newCircuitForDomain(domain);
|
208
|
240
|
},
|
|
241
|
+ newCircuitForUserContextId(userContextId) {
|
|
242
|
+ tor.newCircuitForUserContextId(userContextId);
|
|
243
|
+ },
|
209
|
244
|
|
210
|
245
|
enableIsolation() {
|
211
|
246
|
tor.isolationEnabled = true;
|