Commits:
-
9d6ca8ac
by Pier Angelo Vendrame at 2023-12-05T11:00:25+01:00
fixup! Bug 3455: Add DomainIsolator, for isolating circuit by domain.
Collect the browsers also on Android.
-
9e239230
by Pier Angelo Vendrame at 2023-12-05T11:08:42+01:00
fixup! Bug 40597: Implement TorSettings module
Moved the creation of Meek credentials to a function on its own that we
will reuse also with the Android version of MeekTransport.
-
6a649d7f
by Pier Angelo Vendrame at 2023-12-05T11:25:06+01:00
fixup! Bug 40933: Add tor-launcher functionality
Store the SOCKS settings as a member, so that we can customize them if
needed before applying them.
Also, cleanup the public interface of TorProcess.
E.g., removed TorProcess.connectionWorked, since we do not use this
information anymore.
Finally, added a TorLauncherUtil.isAndroid.
-
1ad1d839
by Pier Angelo Vendrame at 2023-12-05T13:48:35+01:00
fixup! Bug 27476: Implement about:torconnect captive portal within Tor Browser
HTML-ize about:torconnect.
Changed file extension, updated the HTML tag, removed short-tags on tags
that are expected to have a closing tag.
Also, removed the preprocessor and moved the onion pattern to this
commit, since it is used only here.
-
fbd5b4bb
by Pier Angelo Vendrame at 2023-12-05T13:48:42+01:00
fixup! Bug 2176: Rebrand Firefox to TorBrowser
Move the onion pattern files to the commit of about:torconnect.
-
3649cc3f
by Pier Angelo Vendrame at 2023-12-05T18:48:25+01:00
Temporary changes to about:torconnect for Android.
We are planning of tempoorarily using about:torconnect on Android, until
the native UX is ready.
14 changed files:
Changes:
docshell/base/nsAboutRedirector.cpp
... |
... |
@@ -169,7 +169,7 @@ static const RedirEntry kRedirMap[] = { |
169
|
169
|
#endif
|
170
|
170
|
{"telemetry", "chrome://global/content/aboutTelemetry.xhtml",
|
171
|
171
|
nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::IS_SECURE_CHROME_UI},
|
172
|
|
- {"torconnect", "chrome://global/content/torconnect/aboutTorConnect.xhtml",
|
|
172
|
+ {"torconnect", "chrome://global/content/torconnect/aboutTorConnect.html",
|
173
|
173
|
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
174
|
174
|
nsIAboutModule::URI_CAN_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT |
|
175
|
175
|
nsIAboutModule::HIDE_FROM_ABOUTABOUT |
|
toolkit/components/tor-launcher/TorDomainIsolator.sys.mjs
... |
... |
@@ -475,9 +475,19 @@ class TorDomainIsolatorImpl { |
475
|
475
|
* @returns {MozBrowser?} The browser the channel is associated to
|
476
|
476
|
*/
|
477
|
477
|
#getBrowserForChannel(channel) {
|
|
478
|
+ const currentBrowser =
|
|
479
|
+ channel.loadInfo.browsingContext?.topChromeWindow?.browser;
|
|
480
|
+ if (
|
|
481
|
+ channel.loadInfo.browsingContext &&
|
|
482
|
+ currentBrowser?.browsingContext === channel.loadInfo.browsingContext
|
|
483
|
+ ) {
|
|
484
|
+ // Android has only one browser, and does not have the browsers property.
|
|
485
|
+ return currentBrowser;
|
|
486
|
+ }
|
478
|
487
|
const browsers =
|
479
|
488
|
channel.loadInfo.browsingContext?.topChromeWindow?.gBrowser?.browsers;
|
480
|
489
|
if (!browsers || !channel.loadInfo.browsingContext?.browserId) {
|
|
490
|
+ logger.debug("Missing data to associate to a browser", channel.loadInfo);
|
481
|
491
|
return null;
|
482
|
492
|
}
|
483
|
493
|
for (const browser of browsers) {
|
toolkit/components/tor-launcher/TorLauncherUtil.sys.mjs
... |
... |
@@ -325,6 +325,10 @@ class TorFile { |
325
|
325
|
}
|
326
|
326
|
|
327
|
327
|
export const TorLauncherUtil = Object.freeze({
|
|
328
|
+ get isAndroid() {
|
|
329
|
+ return Services.appinfo.OS === "Android";
|
|
330
|
+ },
|
|
331
|
+
|
328
|
332
|
get isMac() {
|
329
|
333
|
return Services.appinfo.OS === "Darwin";
|
330
|
334
|
},
|
toolkit/components/tor-launcher/TorProcess.sys.mjs
... |
... |
@@ -33,8 +33,6 @@ export class TorProcess { |
33
|
33
|
#args = [];
|
34
|
34
|
#subprocess = null;
|
35
|
35
|
#status = TorProcessStatus.Unknown;
|
36
|
|
- // Have we ever made a connection on the control port?
|
37
|
|
- #didConnectToTorControlPort = false;
|
38
|
36
|
|
39
|
37
|
onExit = exitCode => {};
|
40
|
38
|
|
... |
... |
@@ -69,10 +67,6 @@ export class TorProcess { |
69
|
67
|
}
|
70
|
68
|
}
|
71
|
69
|
|
72
|
|
- get status() {
|
73
|
|
- return this.#status;
|
74
|
|
- }
|
75
|
|
-
|
76
|
70
|
get isRunning() {
|
77
|
71
|
return (
|
78
|
72
|
this.#status === TorProcessStatus.Starting ||
|
... |
... |
@@ -102,7 +96,6 @@ export class TorProcess { |
102
|
96
|
}
|
103
|
97
|
|
104
|
98
|
this.#status = TorProcessStatus.Starting;
|
105
|
|
- this.#didConnectToTorControlPort = false;
|
106
|
99
|
|
107
|
100
|
// useful for simulating slow tor daemon launch
|
108
|
101
|
const kPrefTorDaemonLaunchDelay = "extensions.torlauncher.launch_delay";
|
... |
... |
@@ -155,13 +148,6 @@ export class TorProcess { |
155
|
148
|
this.#status = TorProcessStatus.Exited;
|
156
|
149
|
}
|
157
|
150
|
|
158
|
|
- // The owner of the process can use this function to tell us that they
|
159
|
|
- // successfully connected to the control port. This information will be used
|
160
|
|
- // only to decide which text to show in the confirmation dialog if tor exits.
|
161
|
|
- connectionWorked() {
|
162
|
|
- this.#didConnectToTorControlPort = true;
|
163
|
|
- }
|
164
|
|
-
|
165
|
151
|
async #dumpStdout() {
|
166
|
152
|
let string;
|
167
|
153
|
while (
|
... |
... |
@@ -201,20 +187,6 @@ export class TorProcess { |
201
|
187
|
#processExitedUnexpectedly(exitCode) {
|
202
|
188
|
this.#subprocess = null;
|
203
|
189
|
this.#status = TorProcessStatus.Exited;
|
204
|
|
- // FIXME: We can probably drop #didConnectToTorControlPort and use only one
|
205
|
|
- // callback. Then we can let the provider actually distinguish between the
|
206
|
|
- // cases.
|
207
|
|
- if (!this.#didConnectToTorControlPort) {
|
208
|
|
- logger.warn("Tor exited before we could connect to its control port.");
|
209
|
|
- // tor might be misconfigured, because we could never connect to it.
|
210
|
|
- // Two instances of Tor Browser trying to use the same port numbers is
|
211
|
|
- // also a typical scenario for this.
|
212
|
|
- // This might happen very early, before the browser UI is actually
|
213
|
|
- // available. So, we will tell the process owner that the process exited,
|
214
|
|
- // without trying to restart it.
|
215
|
|
- this.onExit(exitCode);
|
216
|
|
- return;
|
217
|
|
- }
|
218
|
190
|
logger.warn("Tor exited suddenly.");
|
219
|
191
|
this.onExit(exitCode);
|
220
|
192
|
}
|
toolkit/components/tor-launcher/TorProvider.sys.mjs
... |
... |
@@ -35,6 +35,15 @@ const logger = new ConsoleAPI({ |
35
|
35
|
* @property {string=} host The host to connect for a TCP control port
|
36
|
36
|
* @property {number=} port The port number to use for a TCP control port
|
37
|
37
|
*/
|
|
38
|
+/**
|
|
39
|
+ * @typedef {object} SocksSettings An object that includes the proxy settings to
|
|
40
|
+ * be configured in the browser.
|
|
41
|
+ * @property {boolean=} transproxy If true, no proxy is configured
|
|
42
|
+ * @property {nsIFile=} ipcFile The nsIFile object with the path to a Unix
|
|
43
|
+ * socket to use for an IPC proxy
|
|
44
|
+ * @property {string=} host The host to connect for a TCP proxy
|
|
45
|
+ * @property {number=} port The port number to use for a TCP proxy
|
|
46
|
+ */
|
38
|
47
|
/**
|
39
|
48
|
* @typedef {object} LogEntry An object with a log message
|
40
|
49
|
* @property {Date} date The date at which we received the message
|
... |
... |
@@ -111,6 +120,13 @@ export class TorProvider { |
111
|
120
|
*/
|
112
|
121
|
#torProcess = null;
|
113
|
122
|
|
|
123
|
+ /**
|
|
124
|
+ * The settings for the SOCKS proxy.
|
|
125
|
+ *
|
|
126
|
+ * @type {SocksSettings?}
|
|
127
|
+ */
|
|
128
|
+ #socksSettings = null;
|
|
129
|
+
|
114
|
130
|
/**
|
115
|
131
|
* The logs we received over the control port.
|
116
|
132
|
* We store a finite number of log entries which can be configured with
|
... |
... |
@@ -165,8 +181,9 @@ export class TorProvider { |
165
|
181
|
async init() {
|
166
|
182
|
logger.debug("Initializing the Tor provider.");
|
167
|
183
|
|
168
|
|
- const socksSettings = TorLauncherUtil.getPreferredSocksConfiguration();
|
169
|
|
- logger.debug("Requested SOCKS configuration", socksSettings);
|
|
184
|
+ // These settings might be customized in the following steps.
|
|
185
|
+ this.#socksSettings = TorLauncherUtil.getPreferredSocksConfiguration();
|
|
186
|
+ logger.debug("Requested SOCKS configuration", this.#socksSettings);
|
170
|
187
|
|
171
|
188
|
try {
|
172
|
189
|
await this.#setControlPortConfiguration();
|
... |
... |
@@ -175,11 +192,11 @@ export class TorProvider { |
175
|
192
|
throw e;
|
176
|
193
|
}
|
177
|
194
|
|
178
|
|
- if (socksSettings.transproxy) {
|
|
195
|
+ if (this.#socksSettings.transproxy) {
|
179
|
196
|
logger.info("Transparent proxy required, not starting a Tor daemon.");
|
180
|
197
|
} else if (this.ownsTorDaemon) {
|
181
|
198
|
try {
|
182
|
|
- await this.#startDaemon(socksSettings);
|
|
199
|
+ await this.#startDaemon();
|
183
|
200
|
} catch (e) {
|
184
|
201
|
logger.error("Failed to start the tor daemon", e);
|
185
|
202
|
throw e;
|
... |
... |
@@ -197,8 +214,7 @@ export class TorProvider { |
197
|
214
|
throw e;
|
198
|
215
|
}
|
199
|
216
|
|
200
|
|
- // We do not customize SOCKS settings, at least for now.
|
201
|
|
- TorLauncherUtil.setProxyConfiguration(socksSettings);
|
|
217
|
+ TorLauncherUtil.setProxyConfiguration(this.#socksSettings);
|
202
|
218
|
|
203
|
219
|
logger.info("The Tor provider is ready.");
|
204
|
220
|
|
... |
... |
@@ -464,7 +480,7 @@ export class TorProvider { |
464
|
480
|
|
465
|
481
|
// Process management
|
466
|
482
|
|
467
|
|
- async #startDaemon(socksSettings) {
|
|
483
|
+ async #startDaemon() {
|
468
|
484
|
// TorProcess should be instanced once, then always reused and restarted
|
469
|
485
|
// only through the prompt it exposes when the controlled process dies.
|
470
|
486
|
if (this.#torProcess) {
|
... |
... |
@@ -476,7 +492,7 @@ export class TorProvider { |
476
|
492
|
|
477
|
493
|
this.#torProcess = new lazy.TorProcess(
|
478
|
494
|
this.#controlPortSettings,
|
479
|
|
- socksSettings
|
|
495
|
+ this.#socksSettings
|
480
|
496
|
);
|
481
|
497
|
// Use a closure instead of bind because we reassign #cancelConnection.
|
482
|
498
|
// Also, we now assign an exit handler that cancels the first connection,
|
... |
... |
@@ -619,7 +635,6 @@ export class TorProvider { |
619
|
635
|
}
|
620
|
636
|
this.#openControlPort()
|
621
|
637
|
.then(controller => {
|
622
|
|
- this.#torProcess?.connectionWorked();
|
623
|
638
|
this.#cancelConnection = () => {};
|
624
|
639
|
// The cancel function should have already called reject.
|
625
|
640
|
if (!canceled) {
|
toolkit/components/torconnect/content/aboutTorConnect.css
... |
... |
@@ -10,6 +10,11 @@ |
10
|
10
|
--onion-radius: 75px;
|
11
|
11
|
}
|
12
|
12
|
|
|
13
|
+html {
|
|
14
|
+ width: 100%;
|
|
15
|
+ height: 100%;
|
|
16
|
+}
|
|
17
|
+
|
13
|
18
|
input[type="checkbox"]:focus, select:focus {
|
14
|
19
|
outline: none!important;
|
15
|
20
|
box-shadow: 0 0 0 3px var(--purple-30) !important;
|
... |
... |
@@ -330,3 +335,166 @@ body { |
330
|
335
|
background-image: url("chrome://global/content/torconnect/connection-location.svg");
|
331
|
336
|
stroke: var(--warning-color);
|
332
|
337
|
}
|
|
338
|
+
|
|
339
|
+.onion-pattern-container {
|
|
340
|
+ flex: auto; /* grow to consume remaining space on the page */
|
|
341
|
+ display: flex;
|
|
342
|
+ margin: 0 auto;
|
|
343
|
+ width: 100%;
|
|
344
|
+ /* two onions tall, 4x the radius */
|
|
345
|
+ height: calc(4 * var(--onion-radius));
|
|
346
|
+ max-height: calc(4 * var(--onion-radius));
|
|
347
|
+ min-height: calc(4 * var(--onion-radius));
|
|
348
|
+ direction: ltr;
|
|
349
|
+}
|
|
350
|
+
|
|
351
|
+.onion-pattern-crop {
|
|
352
|
+ height: 100%;
|
|
353
|
+ width: 100%;
|
|
354
|
+
|
|
355
|
+ -moz-context-properties: fill;
|
|
356
|
+ fill: var(--onion-color, currentColor);
|
|
357
|
+ /* opacity of the entire div, not context-opacity */
|
|
358
|
+ opacity: var(--onion-opacity, 1);
|
|
359
|
+
|
|
360
|
+ background-image: url("chrome://global/content/torconnect/onion-pattern.svg");
|
|
361
|
+ background-repeat: repeat;
|
|
362
|
+ background-attachment: local;
|
|
363
|
+ background-position: center;
|
|
364
|
+ /* svg source is 6 onions wide and 2 onions tall */
|
|
365
|
+ background-size: calc(6 * 2 * var(--onion-radius)) calc(2 * 2 * var(--onion-radius));;
|
|
366
|
+}
|
|
367
|
+
|
|
368
|
+:root {
|
|
369
|
+ --android-dark-accents-buttons: #9059FF;
|
|
370
|
+ --android-dark-background-secondary: #E1E0E7;
|
|
371
|
+ --android-dark-text-primary: #FBFBFE;
|
|
372
|
+ --android-light-text-primary: #15141A;
|
|
373
|
+}
|
|
374
|
+
|
|
375
|
+[hidden=true] {
|
|
376
|
+ display: none !important;
|
|
377
|
+}
|
|
378
|
+
|
|
379
|
+body.android {
|
|
380
|
+ --onion-color: var(--android-dark-text-primary);
|
|
381
|
+ width: 100%;
|
|
382
|
+ height: 100%;
|
|
383
|
+ box-sizing: border-box;
|
|
384
|
+ margin: 0;
|
|
385
|
+ padding: 0 24px !important;
|
|
386
|
+ color: var(--onion-color);
|
|
387
|
+ background: linear-gradient(194deg, #692E9D -0.93%, #393270 48.91%);
|
|
388
|
+ font: menu;
|
|
389
|
+ font-size: 14px;
|
|
390
|
+ display: flex;
|
|
391
|
+}
|
|
392
|
+
|
|
393
|
+.android #connectPageContainer {
|
|
394
|
+ max-width: none;
|
|
395
|
+ display: flex;
|
|
396
|
+ flex-direction: column;
|
|
397
|
+ flex: 1;
|
|
398
|
+}
|
|
399
|
+
|
|
400
|
+.android #breadcrumbs {
|
|
401
|
+ display: none;
|
|
402
|
+}
|
|
403
|
+
|
|
404
|
+.android #text-container {
|
|
405
|
+ display: flex;
|
|
406
|
+ flex-direction: column;
|
|
407
|
+ flex: 1;
|
|
408
|
+}
|
|
409
|
+
|
|
410
|
+.android .title {
|
|
411
|
+ background-position: left 0;
|
|
412
|
+ background-repeat: no-repeat;
|
|
413
|
+ background-size: 40px;
|
|
414
|
+ padding-top: 64px;
|
|
415
|
+ font-size: 22px;
|
|
416
|
+ line-height: 28px;
|
|
417
|
+}
|
|
418
|
+
|
|
419
|
+.android h1 {
|
|
420
|
+ font-weight: normal;
|
|
421
|
+ font-size: 100%;
|
|
422
|
+ margin: 0 0 16px 0;
|
|
423
|
+}
|
|
424
|
+
|
|
425
|
+.android p {
|
|
426
|
+ margin: 0;
|
|
427
|
+ padding-bottom: 8px;
|
|
428
|
+ line-height: 20px;
|
|
429
|
+}
|
|
430
|
+
|
|
431
|
+.android #quickstartContainer {
|
|
432
|
+ margin-top: 24px;
|
|
433
|
+}
|
|
434
|
+
|
|
435
|
+.android .button-container {
|
|
436
|
+ display: flex;
|
|
437
|
+ flex: 1;
|
|
438
|
+ flex-direction: column;
|
|
439
|
+}
|
|
440
|
+
|
|
441
|
+.android #locationDropdown {
|
|
442
|
+ width: 100%;
|
|
443
|
+ max-width: none;
|
|
444
|
+ margin: 0;
|
|
445
|
+}
|
|
446
|
+
|
|
447
|
+.android select {
|
|
448
|
+ background: transparent;
|
|
449
|
+ border: none;
|
|
450
|
+ border-bottom: 1px solid var(--android-dark-text-primary);
|
|
451
|
+ color: var(--android-dark-text-primary);
|
|
452
|
+ display: block;
|
|
453
|
+ width: 100%;
|
|
454
|
+ margin-top: 10px;
|
|
455
|
+ padding: 8px;
|
|
456
|
+}
|
|
457
|
+
|
|
458
|
+.android #buttonPadding {
|
|
459
|
+ flex: 1;
|
|
460
|
+}
|
|
461
|
+
|
|
462
|
+.android #connectButtonContainer {
|
|
463
|
+ width: 100%;
|
|
464
|
+ padding-bottom: 18px;
|
|
465
|
+ display: grid;
|
|
466
|
+}
|
|
467
|
+
|
|
468
|
+/* Be sure not to match the togglee */
|
|
469
|
+.android #connectButtonContainer button {
|
|
470
|
+ display: block;
|
|
471
|
+ width: 100%;
|
|
472
|
+ margin: 4px 0;
|
|
473
|
+ padding: 11px 30px;
|
|
474
|
+ font-size: 14px;
|
|
475
|
+ font-weight: 500;
|
|
476
|
+ border: none;
|
|
477
|
+ border-radius: 4px;
|
|
478
|
+}
|
|
479
|
+
|
|
480
|
+.android #connectButton, .android #tryBridgeButton, .android #configureButton.primary {
|
|
481
|
+ color: var(--android-dark-text-primary);
|
|
482
|
+ background-color: var(--android-dark-accents-buttons);
|
|
483
|
+}
|
|
484
|
+
|
|
485
|
+.android #configureButton {
|
|
486
|
+ order: 1;
|
|
487
|
+}
|
|
488
|
+
|
|
489
|
+.android #restartButton {
|
|
490
|
+ order: 2;
|
|
491
|
+}
|
|
492
|
+
|
|
493
|
+.android #restartButton, .android #cancelButton, .android #configureButton {
|
|
494
|
+ color: var(--android-light-text-primary);
|
|
495
|
+ background-color: var(--android-dark-background-secondary);
|
|
496
|
+}
|
|
497
|
+
|
|
498
|
+.android .onion-pattern-container {
|
|
499
|
+ display: none;
|
|
500
|
+} |
toolkit/components/torconnect/content/aboutTorConnect.xhtml
→
toolkit/components/torconnect/content/aboutTorConnect.html
1
|
1
|
<!-- Copyright (c) 2021, The Tor Project, Inc. -->
|
2
|
2
|
<!DOCTYPE html>
|
3
|
|
-<html xmlns="http://www.w3.org/1999/xhtml">
|
|
3
|
+<html>
|
4
|
4
|
<head>
|
5
|
5
|
<meta
|
6
|
6
|
http-equiv="Content-Security-Policy"
|
7
|
7
|
content="default-src chrome:; object-src 'none'"
|
8
|
8
|
/>
|
9
|
|
- <link
|
10
|
|
- rel="stylesheet"
|
11
|
|
- href="">"chrome://global/skin/onionPattern.css"
|
12
|
|
- type="text/css"
|
13
|
|
- media="all"
|
14
|
|
- />
|
|
9
|
+ <meta name="viewport" content="width=device-width">
|
15
|
10
|
<link
|
16
|
11
|
rel="stylesheet"
|
17
|
12
|
href="">"chrome://global/content/torconnect/aboutTorConnect.css"
|
... |
... |
@@ -21,64 +16,69 @@ |
21
|
16
|
</head>
|
22
|
17
|
<body>
|
23
|
18
|
<div id="progressBar">
|
24
|
|
- <div id="progressBackground" />
|
25
|
|
- <div id="progressSolid" />
|
|
19
|
+ <div id="progressBackground"></div>
|
|
20
|
+ <div id="progressSolid"></div>
|
26
|
21
|
</div>
|
27
|
22
|
<div id="connectPageContainer" class="container">
|
28
|
23
|
<div id="breadcrumbs" class="hidden">
|
29
|
24
|
<span id="connect-to-tor" class="breadcrumb-item">
|
30
|
|
- <span id="connect-to-tor-icon" class="breadcrumb-icon" />
|
31
|
|
- <span class="breadcrumb-label" />
|
|
25
|
+ <span id="connect-to-tor-icon" class="breadcrumb-icon"></span>
|
|
26
|
+ <span class="breadcrumb-label"></span>
|
32
|
27
|
</span>
|
33
|
28
|
<span
|
34
|
29
|
id="connection-assist-separator"
|
35
|
30
|
class="breadcrumb-separator breadcrumb-icon"
|
36
|
|
- />
|
|
31
|
+ ></span>
|
37
|
32
|
<span id="connection-assist" class="breadcrumb-item">
|
38
|
|
- <span id="connection-assist-icon" class="breadcrumb-icon" />
|
39
|
|
- <span class="breadcrumb-label" />
|
|
33
|
+ <span id="connection-assist-icon" class="breadcrumb-icon"></span>
|
|
34
|
+ <span class="breadcrumb-label"></span>
|
40
|
35
|
</span>
|
41
|
36
|
<span
|
42
|
37
|
id="try-bridge-separator"
|
43
|
38
|
class="breadcrumb-separator breadcrumb-icon"
|
44
|
|
- />
|
|
39
|
+ ></span>
|
45
|
40
|
<span id="try-bridge" class="breadcrumb-item">
|
46
|
|
- <span id="try-bridge-icon" class="breadcrumb-icon" />
|
47
|
|
- <span class="breadcrumb-label" />
|
|
41
|
+ <span id="try-bridge-icon" class="breadcrumb-icon"></span>
|
|
42
|
+ <span class="breadcrumb-label"></span>
|
48
|
43
|
</span>
|
49
|
44
|
</div>
|
50
|
45
|
<div id="text-container">
|
51
|
46
|
<div class="title">
|
52
|
|
- <h1 class="title-text" />
|
|
47
|
+ <h1 class="title-text"></h1>
|
53
|
48
|
</div>
|
54
|
49
|
<div id="connectLongContent">
|
55
|
|
- <p id="connectLongContentText" />
|
|
50
|
+ <p id="connectLongContentText"></p>
|
56
|
51
|
</div>
|
57
|
52
|
<div id="connectShortDesc">
|
58
|
|
- <p id="connectShortDescText" />
|
|
53
|
+ <p id="connectShortDescText"></p>
|
59
|
54
|
</div>
|
60
|
55
|
|
61
|
56
|
<button id="viewLogButton"></button>
|
62
|
57
|
|
63
|
58
|
<div id="quickstartContainer">
|
64
|
59
|
<input id="quickstartCheckbox" type="checkbox" />
|
65
|
|
- <label id="quickstartCheckboxLabel" for="">"quickstartCheckbox" />
|
|
60
|
+ <label id="quickstartCheckboxLabel" for="">"quickstartCheckbox"></label>
|
66
|
61
|
</div>
|
67
|
62
|
|
68
|
|
- <div id="connectButtonContainer" class="button-container">
|
69
|
|
- <button id="restartButton" hidden="true"></button>
|
70
|
|
- <button id="configureButton" hidden="true"></button>
|
71
|
|
- <button id="cancelButton" hidden="true"></button>
|
72
|
|
- <button id="connectButton" class="primary" hidden="true"></button>
|
73
|
|
- <label id="locationDropdownLabel" for="">"countries" />
|
|
63
|
+ <div class="button-container">
|
|
64
|
+ <label id="locationDropdownLabel" for="">"countries"></label>
|
74
|
65
|
<form id="locationDropdown" hidden="true">
|
75
|
66
|
<select id="countries"></select>
|
76
|
67
|
</form>
|
77
|
|
- <button id="tryBridgeButton" class="primary" hidden="true"></button>
|
|
68
|
+ <span id="buttonPadding"></span>
|
|
69
|
+ <span id="connectButtonContainer">
|
|
70
|
+ <button id="restartButton" hidden="true"></button>
|
|
71
|
+ <button id="configureButton" hidden="true"></button>
|
|
72
|
+ <button id="cancelButton" hidden="true"></button>
|
|
73
|
+ <button id="connectButton" class="primary" hidden="true"></button>
|
|
74
|
+ <button id="tryBridgeButton" class="primary" hidden="true"></button>
|
|
75
|
+ </span>
|
78
|
76
|
</div>
|
79
|
77
|
</div>
|
80
|
78
|
</div>
|
81
|
|
-#include ../../../themes/shared/onionPattern.inc.xhtml
|
|
79
|
+ <div class="onion-pattern-container">
|
|
80
|
+ <div class="onion-pattern-crop"></div>
|
|
81
|
+ </div>
|
|
82
|
+ <script src="">"chrome://global/content/torconnect/aboutTorConnect.js"></script>
|
82
|
83
|
</body>
|
83
|
|
- <script src="">"chrome://global/content/torconnect/aboutTorConnect.js" />
|
84
|
84
|
</html> |
toolkit/components/torconnect/content/aboutTorConnect.js
... |
... |
@@ -70,8 +70,8 @@ class AboutTorConnect { |
70
|
70
|
connect: "button#connectButton",
|
71
|
71
|
tryBridge: "button#tryBridgeButton",
|
72
|
72
|
locationDropdownLabel: "#locationDropdownLabel",
|
73
|
|
- locationDropdown: "form#locationDropdown",
|
74
|
|
- locationDropdownSelect: "form#locationDropdown select",
|
|
73
|
+ locationDropdown: "#locationDropdown",
|
|
74
|
+ locationDropdownSelect: "#locationDropdown select",
|
75
|
75
|
},
|
76
|
76
|
});
|
77
|
77
|
|
... |
... |
@@ -666,6 +666,9 @@ class AboutTorConnect { |
666
|
666
|
}
|
667
|
667
|
|
668
|
668
|
initElements(direction) {
|
|
669
|
+ const isAndroid = navigator.userAgent.indexOf("Android") !== -1;
|
|
670
|
+ document.body.classList.toggle("android", isAndroid);
|
|
671
|
+
|
669
|
672
|
document.documentElement.setAttribute("dir", direction);
|
670
|
673
|
|
671
|
674
|
this.elements.connectToTorLink.addEventListener("click", event => {
|
toolkit/themes/shared/onionPattern.svg
→
toolkit/components/torconnect/content/onion-pattern.svg
toolkit/components/torconnect/jar.mn
... |
... |
@@ -3,12 +3,13 @@ toolkit.jar: |
3
|
3
|
content/global/torconnect/torConnectTitlebarStatus.js (content/torConnectTitlebarStatus.js)
|
4
|
4
|
content/global/torconnect/torConnectTitlebarStatus.css (content/torConnectTitlebarStatus.css)
|
5
|
5
|
content/global/torconnect/aboutTorConnect.css (content/aboutTorConnect.css)
|
6
|
|
-* content/global/torconnect/aboutTorConnect.xhtml (content/aboutTorConnect.xhtml)
|
|
6
|
+ content/global/torconnect/aboutTorConnect.html (content/aboutTorConnect.html)
|
7
|
7
|
content/global/torconnect/aboutTorConnect.js (content/aboutTorConnect.js)
|
8
|
8
|
content/global/torconnect/arrow-right.svg (content/arrow-right.svg)
|
9
|
9
|
content/global/torconnect/bridge.svg (content/bridge.svg)
|
10
|
10
|
content/global/torconnect/connection-failure.svg (content/connection-failure.svg)
|
11
|
11
|
content/global/torconnect/connection-location.svg (content/connection-location.svg)
|
|
12
|
+ content/global/torconnect/onion-pattern.svg (content/onion-pattern.svg)
|
12
|
13
|
content/global/torconnect/tor-connect.svg (content/tor-connect.svg)
|
13
|
14
|
content/global/torconnect/tor-not-connected-to-connected-animated.svg (content/tor-not-connected-to-connected-animated.svg)
|
14
|
15
|
content/global/torconnect/tor-connect-broken.svg (content/tor-connect-broken.svg) |
toolkit/modules/Moat.sys.mjs
... |
... |
@@ -21,6 +21,56 @@ const TorLauncherPrefs = Object.freeze({ |
21
|
21
|
moat_service: "extensions.torlauncher.moat_service",
|
22
|
22
|
});
|
23
|
23
|
|
|
24
|
+function makeMeekCredentials(proxyType) {
|
|
25
|
+ // Construct the per-connection arguments.
|
|
26
|
+ let meekClientEscapedArgs = "";
|
|
27
|
+ const meekReflector = Services.prefs.getStringPref(
|
|
28
|
+ TorLauncherPrefs.bridgedb_reflector
|
|
29
|
+ );
|
|
30
|
+
|
|
31
|
+ // Escape aValue per section 3.5 of the PT specification:
|
|
32
|
+ // First the "<Key>=<Value>" formatted arguments MUST be escaped,
|
|
33
|
+ // such that all backslash, equal sign, and semicolon characters
|
|
34
|
+ // are escaped with a backslash.
|
|
35
|
+ const escapeArgValue = aValue =>
|
|
36
|
+ aValue
|
|
37
|
+ ? aValue
|
|
38
|
+ .replaceAll("\\", "\\\\")
|
|
39
|
+ .replaceAll("=", "\\=")
|
|
40
|
+ .replaceAll(";", "\\;")
|
|
41
|
+ : "";
|
|
42
|
+
|
|
43
|
+ if (meekReflector) {
|
|
44
|
+ meekClientEscapedArgs += "url="">";
|
|
45
|
+ meekClientEscapedArgs += escapeArgValue(meekReflector);
|
|
46
|
+ }
|
|
47
|
+ const meekFront = Services.prefs.getStringPref(
|
|
48
|
+ TorLauncherPrefs.bridgedb_front
|
|
49
|
+ );
|
|
50
|
+ if (meekFront) {
|
|
51
|
+ if (meekClientEscapedArgs.length) {
|
|
52
|
+ meekClientEscapedArgs += ";";
|
|
53
|
+ }
|
|
54
|
+ meekClientEscapedArgs += "front=";
|
|
55
|
+ meekClientEscapedArgs += escapeArgValue(meekFront);
|
|
56
|
+ }
|
|
57
|
+
|
|
58
|
+ // socks5
|
|
59
|
+ if (proxyType === "socks") {
|
|
60
|
+ if (meekClientEscapedArgs.length <= 255) {
|
|
61
|
+ return [meekClientEscapedArgs, "\x00"];
|
|
62
|
+ } else {
|
|
63
|
+ return [
|
|
64
|
+ meekClientEscapedArgs.substring(0, 255),
|
|
65
|
+ meekClientEscapedArgs.substring(255),
|
|
66
|
+ ];
|
|
67
|
+ }
|
|
68
|
+ // socks4
|
|
69
|
+ } else {
|
|
70
|
+ return [meekClientEscapedArgs, undefined];
|
|
71
|
+ }
|
|
72
|
+}
|
|
73
|
+
|
24
|
74
|
//
|
25
|
75
|
// Launches and controls the PT process lifetime
|
26
|
76
|
//
|
... |
... |
@@ -70,39 +120,6 @@ class MeekTransport { |
70
|
120
|
proxy.pathToBinary = meekPath.path;
|
71
|
121
|
}
|
72
|
122
|
|
73
|
|
- // Construct the per-connection arguments.
|
74
|
|
- let meekClientEscapedArgs = "";
|
75
|
|
- const meekReflector = Services.prefs.getStringPref(
|
76
|
|
- TorLauncherPrefs.bridgedb_reflector
|
77
|
|
- );
|
78
|
|
-
|
79
|
|
- // Escape aValue per section 3.5 of the PT specification:
|
80
|
|
- // First the "<Key>=<Value>" formatted arguments MUST be escaped,
|
81
|
|
- // such that all backslash, equal sign, and semicolon characters
|
82
|
|
- // are escaped with a backslash.
|
83
|
|
- const escapeArgValue = aValue =>
|
84
|
|
- aValue
|
85
|
|
- ? aValue
|
86
|
|
- .replaceAll("\\", "\\\\")
|
87
|
|
- .replaceAll("=", "\\=")
|
88
|
|
- .replaceAll(";", "\\;")
|
89
|
|
- : "";
|
90
|
|
-
|
91
|
|
- if (meekReflector) {
|
92
|
|
- meekClientEscapedArgs += "url="">";
|
93
|
|
- meekClientEscapedArgs += escapeArgValue(meekReflector);
|
94
|
|
- }
|
95
|
|
- const meekFront = Services.prefs.getStringPref(
|
96
|
|
- TorLauncherPrefs.bridgedb_front
|
97
|
|
- );
|
98
|
|
- if (meekFront) {
|
99
|
|
- if (meekClientEscapedArgs.length) {
|
100
|
|
- meekClientEscapedArgs += ";";
|
101
|
|
- }
|
102
|
|
- meekClientEscapedArgs += "front=";
|
103
|
|
- meekClientEscapedArgs += escapeArgValue(meekFront);
|
104
|
|
- }
|
105
|
|
-
|
106
|
123
|
// Setup env and start meek process
|
107
|
124
|
const ptStateDir = lazy.TorLauncherUtil.getTorFile("tordatadir", false);
|
108
|
125
|
ptStateDir.append("pt_state"); // Match what tor uses.
|
... |
... |
@@ -247,22 +264,9 @@ class MeekTransport { |
247
|
264
|
this.#meekClientProcess = null;
|
248
|
265
|
this.uninit();
|
249
|
266
|
});
|
250
|
|
-
|
251
|
|
- // socks5
|
252
|
|
- if (this.proxyType === "socks") {
|
253
|
|
- if (meekClientEscapedArgs.length <= 255) {
|
254
|
|
- this.proxyUsername = meekClientEscapedArgs;
|
255
|
|
- this.proxyPassword = "\x00";
|
256
|
|
- } else {
|
257
|
|
- this.proxyUsername = meekClientEscapedArgs.substring(0, 255);
|
258
|
|
- this.proxyPassword = meekClientEscapedArgs.substring(255);
|
259
|
|
- }
|
260
|
|
- // socks4
|
261
|
|
- } else {
|
262
|
|
- this.proxyUsername = meekClientEscapedArgs;
|
263
|
|
- this.proxyPassword = undefined;
|
264
|
|
- }
|
265
|
|
-
|
|
267
|
+ [this.proxyUsername, this.proxyPassword] = makeMeekCredentials(
|
|
268
|
+ this.proxyType
|
|
269
|
+ );
|
266
|
270
|
this.#inited = true;
|
267
|
271
|
} catch (ex) {
|
268
|
272
|
if (this.#meekClientProcess) {
|
... |
... |
@@ -403,7 +407,7 @@ export class MoatRPC { |
403
|
407
|
throw new Error("MoatRPC: Already initialized");
|
404
|
408
|
}
|
405
|
409
|
|
406
|
|
- let meekTransport = new MeekTransport();
|
|
410
|
+ const meekTransport = new MeekTransport();
|
407
|
411
|
await meekTransport.init();
|
408
|
412
|
this.#meekTransport = meekTransport;
|
409
|
413
|
this.#inited = true;
|
toolkit/themes/shared/minimal-toolkit.jar.inc.mn
... |
... |
@@ -47,7 +47,3 @@ toolkit.jar: |
47
|
47
|
skin/classic/global/media/textrecognition.css (../../shared/media/textrecognition.css)
|
48
|
48
|
|
49
|
49
|
skin/classic/global/browser-colors.css (../../shared/browser-colors.css) |
50
|
|
-
|
51
|
|
-# Tor customization
|
52
|
|
- skin/classic/global/onionPattern.css (../../shared/onionPattern.css)
|
53
|
|
- skin/classic/global/onionPattern.svg (../../shared/onionPattern.svg) |
toolkit/themes/shared/onionPattern.css
deleted
1
|
|
-/* Onion pattern */
|
2
|
|
-
|
3
|
|
-.onion-pattern-container {
|
4
|
|
-
|
5
|
|
- flex: auto; /* grow to consume remaining space on the page */
|
6
|
|
- display: flex;
|
7
|
|
- margin: 0 auto;
|
8
|
|
- width: 100%;
|
9
|
|
- /* two onions tall, 4x the radius */
|
10
|
|
- height: calc(4 * var(--onion-radius));
|
11
|
|
- max-height: calc(4 * var(--onion-radius));
|
12
|
|
- min-height: calc(4 * var(--onion-radius));
|
13
|
|
- direction: ltr;
|
14
|
|
-}
|
15
|
|
-
|
16
|
|
-.onion-pattern-crop {
|
17
|
|
- height: 100%;
|
18
|
|
- width: 100%;
|
19
|
|
-
|
20
|
|
- -moz-context-properties: fill;
|
21
|
|
- fill: var(--onion-color, currentColor);
|
22
|
|
- /* opacity of the entire div, not context-opacity */
|
23
|
|
- opacity: var(--onion-opacity, 1);
|
24
|
|
-
|
25
|
|
- background-image: url("chrome://global/skin/onionPattern.svg");
|
26
|
|
- background-repeat: repeat;
|
27
|
|
- background-attachment: local;
|
28
|
|
- background-position: center;
|
29
|
|
- /* svg source is 6 onions wide and 2 onions tall */
|
30
|
|
- background-size: calc(6 * 2 * var(--onion-radius)) calc(2 * 2 * var(--onion-radius));;
|
31
|
|
-} |
toolkit/themes/shared/onionPattern.inc.xhtml
deleted
1
|
|
-<!--
|
2
|
|
- Container div that holds onionPattern.svg
|
3
|
|
- It is expected the includer of this xhtml file also includes onionPattern.css
|
4
|
|
- and define the following vars:
|
5
|
|
- onion-radius : radius of an onion
|
6
|
|
- onion-color : the base color of the onion pattern
|
7
|
|
- onion-opacity : the opacity of the entire repeating pattern
|
8
|
|
--->
|
9
|
|
-
|
10
|
|
-<div class="onion-pattern-container">
|
11
|
|
- <div class="onion-pattern-crop"/>
|
12
|
|
-</div> |
|
|
\ No newline at end of file |
|