Bug 40933: Move tor-launcher to tor-browser.git
Reviewer's guide for this MR
What does tor-launcher do?
- Do things at the Firefox start (launch
tor
/connect to a providedtor
instance) - Monitor the Tor status, to then provide information to the connection page (in particular, handle the events)
- Provide an interface to allow configuration from the preferences page
- Cleanup things when Firefox exits (+ as a bonus, clean the old meek profiles)
What was the previous architecture?
tor-launcher does that in three files: tl-protocol.js
, tl-process.js
, tl-util.jsm
, plus a shared logger that I replaced with the console.
tl-util.jsm
contains the TorLauncherUtil
module, the other two are components, which can be accessed through XPCOM wizardry (Cc["@torproject.org/whateveritis"]
).
tl-process
contains both the logic to start a tor
process, plus part of the logic to monitor it.
tl-protocol
contains the other part of monitoring, plus a part that checks how tor
should be reached (which address, or IPC path, etc etc), and should be used in general to send commands to Tor (even though the controller implementation is in torbutton).
In addition to that, there are localization files (moved with torbutton!95 (merged) and !369 (merged)) and the old connection wizard. The localization files should be moved to Fluent, and it's time to retire completely the old connection wizard (i.e., this MR doesn't contain it).
Many parts are implemented in torbutton, and in general, torbutton references tor-launcher. That's why I have also torbutton!96 (merged).
For tor-browser, we tried not to use them directly, but only through the XPCOM facilities (actually, we use XPCOM only to get a magic object, and then get the raw JS object with .wrappedJSObject
).
What is the new architecture?
I have tried to divide the files more, accordingly to my understanding of the functions of tor-launcher.
TorProtocolService.jsm
This was the most difficult file to deal with.
It had already some wrappers for tl-protocol.js
, so I've tried to move the actual implementation in these wrappers.
However, eventually I split the tl-protocol.js
in 2/3 parts:
- The interface to help with the configuration (it contained and still contains a map to prevent sending the same configuration to Tor twice)
- The event monitor: I moved it to its own file
- The part to query the address/path to use for SOCKS and for the control port: I've kept it here, because I think it partially overlaps with torbutton, so we should also move torbutton before moving this part.
TorProcess.jsm
Previously, we had TorProcessService.jsm
, which only exposed the status of the tor
process to TorConnect.jsm
(mainly to handle a case in which the process was started before the TorConnect
logic was initialized, not sure it was actually possible).
This only feature isn't part of the new TorProcess
, because I feel that we're not interested in knowing whether the process has been started, but to know whether we are monitoring any Tor process already.
So, I took the parts from tl-process.js
that actually dealt with starting a new process with the XPCOM facilities (in particular, nsIProcess).
Everything else from tl-process.js
was moved to the event monitor.
Also, we don't have a singleton anymore, but a normal class, which is instanced only when we need to start tor
(which is most of the cases, actually, but you know).
It reports events like Tor has exited, or Tor has been restarted through callbacks, instead of observers (these callbacks are implemented in the monitor, which actually notify observers again
Also, TorProcess
still contains the code to make the "Do you want to restart Tor?" prompt appear.
We might want to move it somewhere else, because it's a mix of frontend and backend
TorMonitorService.jsm
This is a new file.
I moved the event parsing here, and it is also responsible of telling whether the bootstrap has been completed, or what was last error, etc...
It starts the Tor process, if needed, and it's notified of its events.
tor
ownership
This is very important, so it deserves its own section.
We don't kill tor
, but we set it to self-kill when the "main" control port connection has been closed.
According to the comments I found, this has been done to prevent Firefox from ramping the CPU up because its connections are closed unexpectedly.
I thought that it made more sense to make the connection that this module keeps the one that makes tor
close.
This is different from the previous implementation, in which the connection that is used to send the configuration was also the owner of the daemon.
The rationale is that this might simplify the management of the connection on TorProtocolService
.
However, we might try to switch to a single connection to the control port, too, but will see in the next phase.
TorParsers.jsm
tl-protocol.js
contained some text-processing functions. I preferred moving them to their own file, to reuse them wherever needed.
IIRC, torbutton also has many additional parsers, that we should move here when the time comes.
Also, this was helpful to create TorMonitorService.jsm
.
TorLauncherUtil.jsm
This is the previous tl-util.jsm
, without the stuff we don't need anymore.
I have to rework a lot the getTorFile
functions... which I transformed from a single function to an entire class.
This could be further improved (e.g., don't use strings, but create an object to use as an enum, etc...).
But the truth is that I'd like to get rid of this file.
Many functions can be moved together with the part of TorProtocolService.jsm
that detects how Tor should be reached.
So, I kept it, but I think we should at least rename it after merging torbutton.
TorStartupService.jsm
We still needed a way to start/initialize things at the right moment.
So, instead of registering each module as a component, I have registered only this components, which calls the needed function on the other modules.
Phase 2/3 + Arti
This MR is phase 1, but I expect we'll have a phase 2 for tor-launcher. Or phase 2 is torbutton, and phase 3 is review of the whole.
My objective is to make TorProcotolService.jsm
a configuration utility, that will become a TorSettings
backend, rather than what it is now.
Anything else should be moved to another module.
I don't know how Arti works already, but my idea is that we'll have a check that tells that we're using Arti, and that we don't need to initialize the modules of this MR.
Also, I'd like to make TorService
more abstract and focused on the functionalities (e.g., tell its backends that the user wants to use bridges, not that Tor should be configured with an array of bridge strings, if it makes sense).
But again, I think that we should port torbutton to tor-browser, first.
Closes #40853 (closed), #40993.
Should be merged with torbutton!96 (merged).
Previous description
I'm trying to follow the strategy I described in #40933 (closed).
Setting as a draft because I'm still working on it, but I could use an early review.
TL;DR:
-
tl-process.js
➡ ️TorProcessService.jsm
(mostly done) -
tl-protocol.js
➡ ️TorProtocolService.jsm
(work in progress) -
tl-util.jsm
copy&paste&rework (not done yet) - l10n
➡ ️ torbutton, until we approve tor-browser-build!503 (merged)?
Component analysis (WIP)
tl-process.js
/TorProcessService
-
Public interface: - only the possibility to get the status of the tor process.
- I renamed the getter to
status
only, because I think that adding tor to every method/getter is redundant🙂 - This can be tested by querying the value in the browser console
- To make things more spicy, we can kill
tor
- I renamed the getter to
-
tl-process.js
had some public interfaces that were accessed throughTorProtocolService
, instead. So, I moved themtl-protocol.js
in thetor-launcher
branch-
isBootstrapDone
,clearBootstrapError
,torBootstrapErrorOccurred
,_torBootstrapDebugSetError
- I'm not sure on how to test them. The preference to debug
about:torconnect
could be handy.
-
- other "public" communication happens through observers (see later, but I have tried to keep all the topics in
TorProcessTopics
)
- only the possibility to get the status of the tor process.
-
Custom logger, instead of using the old logger - I think using a standard API is better than maintaining our log code
- It has its own nice label in the Firefox console
😄 - No way to customize the level, yet, but we can add a preference
- Way to test: open the console and see that we can still see logs (increase the
maxLogLevel
toall
, if needed)
-
Startup observer ( profile-after-change
)- This needs a component, so I have used a mix between the previous code, and the SecurityLevel code.
- This is the reason for which
TorProcessService
needs to be a class instanced by Firefox now, rather than a plain old object. - I think we could use a single startup/quit observer in a new module, in a new revision
- This is the reason for which
- Test: without this,
tor
won't be started.
- This needs a component, so I have used a mix between the previous code, and the SecurityLevel code.
-
Quit observer: kills the the process in a smart way (the code hasn't been touched, mostly) - Test way: I haven't thought to it, yet.
-
Process observer: it is notified if tor
exits- Way to test:
killall tor
and see Tor Browser reacting
- Way to test:
-
tor
starter- Tests:
- check on the system monitor that the
tor
process is started correctly, and with the expected arguments- arguments are also dumped to the console
- It includes
extensions.torlauncher.launch_delay
. We can add a very high value, and in any case check that the process is started as expected even when this preference is set - Start TBB when another
tor
/another TBB is already running to trigger a failure
- check on the system monitor that the
- Tests:
-
start a tor
controller: callsTorProtocolService.torStartEventMonitor()
,TorProtocolService.torRetrieveBootstrapStatus()
and notifies the observers that the process is ready (or if it timed out)- This was based on a
nsITimer
, and was handled in the observer, I switched to asetTimeout
- Tests:
- we should actually think on how to test the other methods
- add a custom observer, just to check that it is notified
- hijack
tor
to some sleep process, just to see that theProcessDidNotStart
observer is notified, instead - try with an already-running
tor
, and see that it works like the previous implementation (critical for Tails)
- This was based on a
-
fix torrc
: I have copied and pasted the old functions, but haven't analyzed them too much- It was the only method using
_valueIsUnixDomainSocket
and_valueContainsPort
, so I changed them to closures insidefixupTorrc
- Tests: analyze the code, reverse engineer what we expect it to do, modify the
torrc
and see that is gets fixed as we expect
- It was the only method using
-
remove Meek and Moat helper profiles - can we remove this, actually?
- If we can't, we need to test this on macOS: create some directories, and check that they're deleted
😈 ️
Removed code - messing with (default) bridges
- From what I could gather, this code isn't actually used
- helpers to open the old launcher/settings/locale picker
- The locale picker maybe could be still useful... But until then, let's keep it outta here!
- helper to remove the program
- I think it isn't used anymore
- filesystem helpers: use
IOUtils
instead- they are used to fix
torrc
, so we will testIOUtils
while testing it
- they are used to fix
- helper to get Firefox's PID: I yoloed and used
Services.appinfo.processID
only