selenium_tor 1.7.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +14 -0
- data/README.md +30 -35
- data/lib/selenium_tor.rb +5 -1
- data/lib/tor/driver.rb +26 -12
- data/lib/tor/error.rb +18 -0
- data/lib/tor/libxul_checksums.yml +4 -0
- data/lib/tor/libxul_patchable.rb +13 -13
- data/lib/tor/options.rb +13 -16
- data/lib/tor/tor_prefs.rb +1 -1
- data/lib/tor/tor_process.rb +6 -6
- data/lib/tor/torrc.rb +14 -9
- data/lib/tor/version.rb +1 -1
- metadata +2 -2
- data/lib/tor/system_tor.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d91caf67c6dbe8d0ee5a4e9e1fde84901ec736d0280dc5913b91e9d38e78bc55
|
4
|
+
data.tar.gz: e3e789ac86f09532c03472f52dd80c750695d71f1b7bd4b9b4521880d5f83751
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bc39fe85b2f2cceddc76d77c4e5cbbfcc35f658a0af9376affd99d397617523705e4b5a2cf11a74785ff7bfb41bf83cfbd15b87e5472649191b4d346b75f6b64
|
7
|
+
data.tar.gz: 2b0aa0060db12d4f6854b47b47979e9f50b7a013a8ad550a8fdb5268c1d9c8eda76df88090a81e620845cb1e114db6e8e1430cbdd983a0d0c5a0ef7f88758360
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
## master (unreleased)
|
2
2
|
|
3
|
+
## [2.0.0] - 2025-05-31
|
4
|
+
|
5
|
+
### New features
|
6
|
+
|
7
|
+
* SocksPort is now auto selected, 'SocksPort'/:socks_port keys are ignored in Tor::Options :tor_opts hash
|
8
|
+
* selenium-manager is disabled (avoids chance of FF being downloaded & used)
|
9
|
+
* errors in Tor namespace now subclass Selenium::WebDriver::Error::WebDriverError
|
10
|
+
* drop Xvfb/headless gem dependency
|
11
|
+
* drop deprecated :system_tor options
|
12
|
+
|
13
|
+
### Bug fixes
|
14
|
+
|
15
|
+
* ControlPort no longer set by default in torrc (security)
|
16
|
+
|
3
17
|
## [1.7.0] - 2025-05-21
|
4
18
|
|
5
19
|
### New features
|
data/README.md
CHANGED
@@ -8,7 +8,8 @@ A Selenium extension for Tor Browser.
|
|
8
8
|
# before_all
|
9
9
|
require 'selenium_tor'
|
10
10
|
|
11
|
-
options = Selenium::WebDriver::
|
11
|
+
options = Selenium::WebDriver::Options.tor
|
12
|
+
options.args << '-headless'
|
12
13
|
@driver = Selenium::WebDriver.for :tor, options: options
|
13
14
|
```
|
14
15
|
When you are done don't forget to quit the driver. Failure to do so may leave orphaned tor processes.
|
@@ -18,6 +19,9 @@ When you are done don't forget to quit the driver. Failure to do so may leave or
|
|
18
19
|
```
|
19
20
|
Once you have a driver instance:
|
20
21
|
```ruby
|
22
|
+
@driver
|
23
|
+
# => instance_of Selenium::WebDriver::Tor::Driver
|
24
|
+
|
21
25
|
@driver.get 'https://check.torproject.org'
|
22
26
|
@driver.title
|
23
27
|
# => "Congratulations. This browser is configured to use Tor."
|
@@ -43,11 +47,11 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
43
47
|
|
44
48
|
[Tor Browser](https://www.torproject.org/download). Tests are conducted with the latest stable ('release') and alpha versions of Tor Browser. Support for older versions is periodically dropped - see the CHANGELOG.
|
45
49
|
|
46
|
-
As with Firefox browser, `geckodriver` needs to be installed and in your PATH.
|
50
|
+
As with Firefox browser, `geckodriver` needs to be installed and in your PATH. [Selenium Manager](https://www.selenium.dev/documentation/selenium_manager) is disabled for security reasons, so you are responsible for ensuring the correct (latest) version of geckodriver is installed.
|
47
51
|
|
48
52
|
The gem needs to know the location of the Tor Browser Bundle (TBB). The Tor Browser download package archive must be extracted and the root TBB directory (named "tor-browser") placed somewhere on your system. By default it is assumed to be in the current user's HOME directory. An alternative location can be set via the env var `TOR_BROWSER_ROOT_DIR` - e.g. `export TOR_BROWSER_ROOT_DIR=/home/<user>/Downloads`. The Tor Browser binary location is *automatically set* by reference to this directory, so there is no need to do this:
|
49
53
|
```ruby
|
50
|
-
options = Selenium::WebDriver::
|
54
|
+
options = Selenium::WebDriver::Options.tor
|
51
55
|
options.binary = '/some/path/to/tor_firefox_binary' # UNNECESSARY
|
52
56
|
# => '/some/path/to/tor_firefox_binary'
|
53
57
|
```
|
@@ -56,21 +60,6 @@ The location of the TBB is not expected to change during code execution.
|
|
56
60
|
|
57
61
|
Tor Selenium is tested on **Linux only** right now.
|
58
62
|
|
59
|
-
### Patching libxul.so
|
60
|
-
|
61
|
-
A configuration option to patch the `libxul.so` packaged with Tor Browser is provided. This has the effect of preventing websites from fingerprinting Selenium-driven Tor Browser via a JS call to `navigator.webdriver`:
|
62
|
-
```ruby
|
63
|
-
@driver_class = Selenium::WebDriver::Tor::Driver
|
64
|
-
@driver_class.libxul_patched? # is Tor Browser's libxul.so patched?
|
65
|
-
# => false
|
66
|
-
@driver_class.patch_libxul # patch libxul.so
|
67
|
-
@driver_class.libxul_patched?
|
68
|
-
# => true
|
69
|
-
@driver_class.unpatch_libxul # revert the patch and restore the libxul.so packaged with Tor Browser
|
70
|
-
# => 0
|
71
|
-
```
|
72
|
-
The patcher uses the [Bsdiff](https://gitlab.com/matzfan/bsdiff) gem.
|
73
|
-
|
74
63
|
## Usage
|
75
64
|
```ruby
|
76
65
|
require 'selenium_tor'
|
@@ -84,21 +73,17 @@ A separate tor process is used for each driver. Failure to call `Driver#quit` af
|
|
84
73
|
|
85
74
|
### Tor options
|
86
75
|
|
87
|
-
In addition to the regular Firefox options, a
|
76
|
+
In addition to the regular Firefox options, a `:tor_opts` key may be passed to an instance of `Tor::Options` with a hash of tor options. All valid tor client options are recognized - see `man tor`. Snake case key symbols may be used if these can be coerced to valid camel case key strings - e.g. `:control_port` becomes 'ControlPort'. Additionally, a `:tor_opts` timeout value may be set with the `:timeout` key. This overrides the default time allowed for the tor process to bootstrap (10 seconds).
|
88
77
|
|
89
78
|
### Multiple driver instances
|
90
79
|
|
91
|
-
Running multiple tor processes requires that each uses different ports for SocksPort (and ControlPort, if used).
|
80
|
+
Running multiple tor processes requires that each uses different ports for SocksPort (and ControlPort, if used). From version 2.0 the SocksPort is auto selected, so no configuation is required. An example using the [Parallel gem](https://rubygems.org/gems/parallel):
|
92
81
|
```ruby
|
93
82
|
require 'parallel'
|
94
83
|
|
95
|
-
@socks_port = 9150
|
96
|
-
@control_port = 9151
|
97
|
-
|
98
84
|
def driver
|
99
|
-
|
100
|
-
|
101
|
-
options = Selenium::WebDriver::Tor::Options.new tor_opts: { socks_port: @socks_port, control_port: @control_port }
|
85
|
+
options = Selenium::WebDriver::Options.tor # no needs to pass SocksPort in :tor_opts from version 2.0
|
86
|
+
options.args << '-headless'
|
102
87
|
Selenium::WebDriver.for :tor, options: options
|
103
88
|
end
|
104
89
|
|
@@ -155,24 +140,34 @@ Tor::TBB_EXTENSIONS_DIR # path to the 'extensions' directory in the above
|
|
155
140
|
Tor::TBB_VERSION # the version installed, e.g. "13.0.1", note: driver.capabilities.browser_version returns the Firefox version Tor Browser is based on
|
156
141
|
# => instance_of String
|
157
142
|
```
|
143
|
+
### Patching libxul.so
|
158
144
|
|
159
|
-
|
145
|
+
A configuration option to patch the `libxul.so` packaged with Tor Browser is provided. This has the effect of preventing websites from fingerprinting Selenium-driven Tor Browser via a JS call to `navigator.webdriver`:
|
146
|
+
```ruby
|
147
|
+
@driver_class = Selenium::WebDriver::Tor::Driver
|
148
|
+
@driver_class.libxul_patched? # is Tor Browser's libxul.so patched?
|
149
|
+
# => false
|
150
|
+
@driver_class.patch_libxul # patch libxul.so
|
151
|
+
@driver_class.libxul_patched?
|
152
|
+
# => true
|
153
|
+
@driver_class.unpatch_libxul # revert the patch and restore the libxul.so packaged with Tor Browser
|
154
|
+
# => 0
|
155
|
+
```
|
156
|
+
The patcher uses the [Bsdiff](https://gitlab.com/matzfan/bsdiff) gem.
|
160
157
|
|
161
|
-
|
158
|
+
### Exceptions
|
162
159
|
|
163
|
-
|
160
|
+
Tor-specific webdriver funcionality raises `Tor::Error` or a subclass. `Tor::Error` itself subclasses `WebDriver::Error::WebDriverError`
|
164
161
|
|
165
|
-
|
162
|
+
## Known issues
|
163
|
+
|
164
|
+
Known issues are recorded [here](https://gitlab.com/matzfan/selenium-tor/-/issues).
|
166
165
|
|
167
166
|
## Testing
|
168
167
|
|
169
168
|
~~After checking out the repo, run `bin/setup` to install dependencies.~~
|
170
169
|
|
171
|
-
|
172
|
-
|
173
|
-
Tests are run in the display set by the `DISPLAY` env var, usually :0 by default. To run headless tests, set it to another value:
|
174
|
-
|
175
|
-
$ DISPLAY=:99 bundle exec rake
|
170
|
+
$ bundle exec rake
|
176
171
|
|
177
172
|
If you find driver instantiation failing with port bind failure error messages ( these include "Address already in use. Is Tor already running?") check you have no other tor processes running with conflicting ports. With timeout errors, you may also want to check the Tor network is actually up, it isn't always..
|
178
173
|
|
data/lib/selenium_tor.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
ENV['SE_OFFLINE'] = 'true' # we don't want selenium-manager getting & using firefox in error
|
4
|
+
ENV['SE_AVOID_STATS'] = 'true' # no telemetry thanks!
|
5
|
+
|
6
|
+
load 'selenium-webdriver.rb' # force load to ensure env vars are applied
|
7
|
+
|
4
8
|
require_relative 'driver'
|
data/lib/tor/driver.rb
CHANGED
@@ -18,12 +18,20 @@ module Selenium
|
|
18
18
|
class Driver < DelegateClass(DriverDelegate)
|
19
19
|
extend LibxulPatchable
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
21
|
+
TORRC = 'torrc'
|
22
|
+
|
23
|
+
PREF_BROWSER_SECURITY_LEVEL = 'browser.security_level.security_slider'
|
24
|
+
PREF_TORRC_PATH = 'extensions.torlauncher.torrc_path'
|
25
|
+
PREF_SOCKS_PORT = 'network.proxy.socks_port'
|
26
|
+
|
27
|
+
DOMAIN_ISOLATOR = 'TorDomainIsolator' # ES6 module
|
28
|
+
NEW_CIRCUIT = 'newCircuitForDomain' # js function
|
29
|
+
|
30
|
+
TB_SEC_LEVELS = { 'standard' => 4, 'safer' => 2, 'safest' => 1 }.freeze
|
31
|
+
|
32
|
+
LOCALHOST_PORT_REGEXP = /127\.0\.0\.1:(\d+)/
|
33
|
+
|
34
|
+
attr_reader :tor_process
|
27
35
|
|
28
36
|
def initialize(options: nil, **)
|
29
37
|
@data_dir = Dir.mktmpdir
|
@@ -31,7 +39,8 @@ module Selenium
|
|
31
39
|
add_torrc_path_to_options
|
32
40
|
@instance = DriverDelegate.new(options: @options, **)
|
33
41
|
install_extensions @instance
|
34
|
-
create_tor_process_and_start_tor
|
42
|
+
pid = create_tor_process_and_start_tor(@options.tor_opts)
|
43
|
+
@instance.pref[PREF_SOCKS_PORT] = socks_port(pid)
|
35
44
|
super(@instance)
|
36
45
|
end
|
37
46
|
|
@@ -46,13 +55,13 @@ module Selenium
|
|
46
55
|
end
|
47
56
|
|
48
57
|
def security_level
|
49
|
-
pref[
|
58
|
+
pref[PREF_BROWSER_SECURITY_LEVEL]
|
50
59
|
end
|
51
60
|
|
52
61
|
def security_level=(int)
|
53
62
|
raise(ArgumentError, "Valid security levels are: #{TB_SEC_LEVELS.values}") unless TB_SEC_LEVELS.value?(int)
|
54
63
|
|
55
|
-
pref[
|
64
|
+
pref[PREF_BROWSER_SECURITY_LEVEL] = int
|
56
65
|
end
|
57
66
|
|
58
67
|
def new_circuit_for_site
|
@@ -64,7 +73,7 @@ module Selenium
|
|
64
73
|
private
|
65
74
|
|
66
75
|
def add_torrc_path_to_options
|
67
|
-
@options.prefs[
|
76
|
+
@options.prefs[PREF_TORRC_PATH] = File.join(@data_dir, TORRC)
|
68
77
|
end
|
69
78
|
|
70
79
|
def install_extensions(instance)
|
@@ -73,20 +82,25 @@ module Selenium
|
|
73
82
|
|
74
83
|
def create_tor_process_and_start_tor(opts)
|
75
84
|
timeout = opts.delete :timeout
|
76
|
-
@tor_process =
|
85
|
+
@tor_process = create_tor_process(opts)
|
77
86
|
@tor_process.start_tor(timeout: timeout)
|
78
87
|
rescue Tor::TorProcess::TorProcessError => e
|
79
88
|
instance_variable_get(:@instance)&.quit # avoids hanging firefox.real process
|
80
89
|
raise Error::WebDriverError, e
|
81
90
|
end
|
82
91
|
|
83
|
-
def
|
92
|
+
def create_tor_process(opts)
|
84
93
|
TorProcess.new(@data_dir, opts || {})
|
85
94
|
end
|
86
95
|
|
87
96
|
def domain
|
88
97
|
URI(current_url).host&.match(/[^\.]+\.\w+$/)
|
89
98
|
end
|
99
|
+
|
100
|
+
def socks_port(pid)
|
101
|
+
str = `netstat -tnlp 2>/dev/null|grep #{pid}/tor` # net-tools dep
|
102
|
+
str.match(LOCALHOST_PORT_REGEXP)[1].to_i
|
103
|
+
end
|
90
104
|
end
|
91
105
|
end
|
92
106
|
end
|
data/lib/tor/error.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal:true
|
2
|
+
|
3
|
+
require 'selenium-webdriver'
|
4
|
+
|
5
|
+
# errors
|
6
|
+
module Selenium
|
7
|
+
module WebDriver
|
8
|
+
module Tor
|
9
|
+
class Error < WebDriver::Error::WebDriverError; end
|
10
|
+
|
11
|
+
class TorrcError < Error; end
|
12
|
+
|
13
|
+
class TorProcessError < Error; end
|
14
|
+
|
15
|
+
class LibxulPatchableError < Error; end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,4 +1,8 @@
|
|
1
1
|
---
|
2
|
+
14.5.3:
|
3
|
+
unpatched_libxul: 88c9aef61ca0df4c617a8c7c589194bd8ff31d1d7a6360512e1ab1cfc81390a8
|
4
|
+
patched_libxul: 18e6f350a2a8983395ffac984aac1a7a431d2acb0c97faa69d6f965199b67e2c
|
5
|
+
patch_checksum: b216ba4ad661e79e9cbf648837e1f18282490ee504f5970a2cb1ae7f847dd271
|
2
6
|
14.5.2:
|
3
7
|
unpatched_libxul: 0e4d960cb427df67a25ab50aa934272e7ac7ee3487c709e48d97e2611e2ae930
|
4
8
|
patched_libxul: 20579db140991d77db1a3ffa3e248752dd689bf4156056402cbe1fd6287430c1
|
data/lib/tor/libxul_patchable.rb
CHANGED
@@ -5,6 +5,8 @@ require 'digest'
|
|
5
5
|
require 'json'
|
6
6
|
require 'open-uri'
|
7
7
|
require 'yaml'
|
8
|
+
|
9
|
+
require_relative 'error'
|
8
10
|
require_relative 'options' # module needs access to consts therein defined
|
9
11
|
|
10
12
|
module Selenium
|
@@ -12,19 +14,17 @@ module Selenium
|
|
12
14
|
module Tor
|
13
15
|
# methods to patch/unpatch libxul.so
|
14
16
|
module LibxulPatchable
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
NO_PATCH_MSG = "No patch for #{Tor::TBB_VERSION}, please raise an issue at #{ISSUES_URL}".freeze
|
20
|
-
UNDEF_REGEXP = /undefined method (`|')\[\]' for nil/
|
17
|
+
PATCH_REPO_URL = 'https://gitlab.com/matzfan/keymaster/-/raw/master/patches/tor-browser'
|
18
|
+
ISSUES_URL = 'https://gitlab.com/matzfan/keymaster/-/issues'
|
19
|
+
NO_PATCH_MSG = "No patch for #{Tor::TBB_VERSION}, please raise an issue at #{ISSUES_URL}".freeze
|
20
|
+
UNDEF_REGEXP = /undefined method (`|')\[\]' for nil/
|
21
21
|
|
22
22
|
def libxul_patched?
|
23
23
|
libxul_checksum = checksum_for Tor::TBB_LIBXUL
|
24
24
|
return true if patched_libxul_checksum_for_version == libxul_checksum
|
25
25
|
return false if unpatched_libxul_checksum_for_version == libxul_checksum
|
26
26
|
|
27
|
-
raise LibxulPatchableError, 'Unrecognized libxul.so'
|
27
|
+
raise Tor::LibxulPatchableError, 'Unrecognized libxul.so'
|
28
28
|
end
|
29
29
|
|
30
30
|
def patch_libxul
|
@@ -36,7 +36,7 @@ module Selenium
|
|
36
36
|
execute_patch patchfile
|
37
37
|
FileUtils.cp libxul_patched, Tor::TBB_LIBXUL
|
38
38
|
rescue OpenURI::HTTPError
|
39
|
-
raise LibxulPatchableError, NO_PATCH_MSG
|
39
|
+
raise Tor::LibxulPatchableError, NO_PATCH_MSG
|
40
40
|
end
|
41
41
|
|
42
42
|
def unpatch_libxul
|
@@ -57,7 +57,7 @@ module Selenium
|
|
57
57
|
|
58
58
|
def valid?(patchfile)
|
59
59
|
msg = "Invalid patch for #{Tor::TBB_VERSION}, please raise an issue at #{ISSUES_URL}"
|
60
|
-
raise LibxulPatchableError, msg unless patch_checksum_for_version == checksum_for(patchfile)
|
60
|
+
raise Tor::LibxulPatchableError, msg unless patch_checksum_for_version == checksum_for(patchfile)
|
61
61
|
end
|
62
62
|
|
63
63
|
def execute_patch(patchfile)
|
@@ -71,7 +71,7 @@ module Selenium
|
|
71
71
|
def unpatched_libxul_checksum_for_version
|
72
72
|
libxul_checksums['unpatched_libxul']
|
73
73
|
rescue NoMethodError => e
|
74
|
-
raise LibxulPatchableError, NO_PATCH_MSG if e.message.match UNDEF_REGEXP
|
74
|
+
raise Tor::LibxulPatchableError, NO_PATCH_MSG if e.message.match UNDEF_REGEXP
|
75
75
|
|
76
76
|
raise e
|
77
77
|
end
|
@@ -79,7 +79,7 @@ module Selenium
|
|
79
79
|
def patched_libxul_checksum_for_version
|
80
80
|
libxul_checksums['patched_libxul']
|
81
81
|
rescue NoMethodError => e
|
82
|
-
raise LibxulPatchableError, NO_PATCH_MSG if e.message.match UNDEF_REGEXP
|
82
|
+
raise Tor::LibxulPatchableError, NO_PATCH_MSG if e.message.match UNDEF_REGEXP
|
83
83
|
|
84
84
|
raise e
|
85
85
|
end
|
@@ -87,7 +87,7 @@ module Selenium
|
|
87
87
|
def patch_checksum_for_version
|
88
88
|
libxul_checksums['patch_checksum']
|
89
89
|
rescue NoMethodError => e
|
90
|
-
raise LibxulPatchableError, NO_PATCH_MSG if e.message.match UNDEF_REGEXP
|
90
|
+
raise Tor::LibxulPatchableError, NO_PATCH_MSG if e.message.match UNDEF_REGEXP
|
91
91
|
|
92
92
|
raise e
|
93
93
|
end
|
@@ -106,7 +106,7 @@ module Selenium
|
|
106
106
|
end
|
107
107
|
|
108
108
|
def patch_url
|
109
|
-
File.join
|
109
|
+
File.join PATCH_REPO_URL, "#{Tor::TBB_VERSION}.patch"
|
110
110
|
end
|
111
111
|
end
|
112
112
|
end
|
data/lib/tor/options.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'tor_prefs'
|
4
|
-
require_relative 'system_tor'
|
5
4
|
require 'selenium-webdriver'
|
6
5
|
|
7
6
|
module Selenium
|
@@ -9,25 +8,23 @@ module Selenium
|
|
9
8
|
module Tor
|
10
9
|
# tor options
|
11
10
|
class Options < Firefox::Options
|
12
|
-
CAPABILITIES
|
13
|
-
CAPABILITIES[:system_tor] = 'system_tor' # DEPRECATED 2.0
|
11
|
+
CAPABILITIES = CAPABILITIES.merge(tor_opts: 'tor_opts')
|
14
12
|
DEFAULT_TBB_DIR = File.join Dir.home, 'tor-browser'
|
15
13
|
|
16
|
-
Tor::TBB_DIR
|
17
|
-
Tor::TBB_BROWSER_DIR
|
18
|
-
Tor::TBB_LIBXUL
|
19
|
-
Tor::TBB_BINARY_PATH
|
14
|
+
Tor::TBB_DIR = ENV.fetch('TOR_BROWSER_ROOT_DIR', nil) || DEFAULT_TBB_DIR
|
15
|
+
Tor::TBB_BROWSER_DIR = File.join Tor::TBB_DIR, 'Browser'
|
16
|
+
Tor::TBB_LIBXUL = File.join Tor::TBB_BROWSER_DIR, 'libxul.so'
|
17
|
+
Tor::TBB_BINARY_PATH = File.join Tor::TBB_BROWSER_DIR, 'firefox'
|
20
18
|
Tor::TBB_TOR_BINARY_PATH = File.join Tor::TBB_BROWSER_DIR, *%w[TorBrowser Tor tor]
|
21
|
-
Tor::TBB_TOR_DATA_DIR
|
22
|
-
Tor::TBB_PROFILE_DIR
|
23
|
-
Tor::TBB_EXTENSIONS_DIR
|
24
|
-
Tor::TBB_VERSION
|
19
|
+
Tor::TBB_TOR_DATA_DIR = File.join Tor::TBB_BROWSER_DIR, *%w[TorBrowser Data Tor]
|
20
|
+
Tor::TBB_PROFILE_DIR = File.join Tor::TBB_BROWSER_DIR, *%w[TorBrowser Data Browser profile.default]
|
21
|
+
Tor::TBB_EXTENSIONS_DIR = File.join Tor::TBB_PROFILE_DIR, 'extensions'
|
22
|
+
Tor::TBB_VERSION = JSON.parse(File.read(File.join(Tor::TBB_BROWSER_DIR, 'tbb_version.json')))['version']
|
25
23
|
|
26
24
|
attr_reader :tor_opts
|
27
25
|
|
28
26
|
def initialize(log_level: nil, **opts)
|
29
|
-
opts[:tor_opts]
|
30
|
-
@tor_opts = opts[:tor_opts] ? opts.delete(:tor_opts) : {} # must be deleted before call to super
|
27
|
+
@tor_opts = opts[:tor_opts] ? opts.delete(:tor_opts) : {}
|
31
28
|
do_start_tor_browser_script_stuff # stuff the start-tor-browser script in TBB does
|
32
29
|
super(log_level: log_level, **tor_options(opts.delete(:prefs)).merge(opts))
|
33
30
|
end
|
@@ -39,10 +36,10 @@ module Selenium
|
|
39
36
|
end
|
40
37
|
|
41
38
|
def do_start_tor_browser_script_stuff
|
42
|
-
ENV['SESSION_MANAGER']
|
43
|
-
ENV['XAUTHORITY'] = File.join(Dir.home, '.Xauthority') unless ENV.fetch('XAUTHORITY', nil)
|
44
|
-
FileUtils.rm_rf File.join(Tor::TBB_BROWSER_DIR, *%w[TorBrowser Data fontconfig])
|
39
|
+
ENV['SESSION_MANAGER'] = nil
|
45
40
|
ENV['GSETTINGS_BACKEND'] = 'memory'
|
41
|
+
ENV['XAUTHORITY'] = File.join(Dir.home, '.Xauthority') unless ENV.fetch('XAUTHORITY', nil)
|
42
|
+
FileUtils.rm_rf File.join(Tor::TBB_BROWSER_DIR, *%w[TorBrowser Data fontconfig])
|
46
43
|
end
|
47
44
|
end
|
48
45
|
end
|
data/lib/tor/tor_prefs.rb
CHANGED
@@ -18,7 +18,7 @@ module Selenium
|
|
18
18
|
OTHER_PREFS = {
|
19
19
|
'intl.language_notification.shown' => true, # affects font fingerprint (viewport size)
|
20
20
|
'remote.active-protocols' => 1, # BiDi only >= 4.32 https://github.com/SeleniumHQ/selenium/pull/15224/files
|
21
|
-
'extensions.torlauncher.start_tor' => false
|
21
|
+
'extensions.torlauncher.start_tor' => false # no settings Connection pane
|
22
22
|
}.freeze
|
23
23
|
|
24
24
|
TOR_PREFS = FIRST_CONNECTION_PREFS.merge OTHER_PREFS
|
data/lib/tor/tor_process.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'timeout'
|
4
|
+
require_relative 'error'
|
4
5
|
require_relative 'torrc'
|
5
6
|
|
6
7
|
module Selenium
|
@@ -8,12 +9,10 @@ module Selenium
|
|
8
9
|
module Tor
|
9
10
|
# Respresentation of a tor process
|
10
11
|
class TorProcess
|
11
|
-
class TorProcessError < StandardError; end
|
12
|
-
|
13
12
|
BOOTSTRAP_SUCCESS_REGEX = /Bootstrapped 100% \(done\): Done$/
|
14
|
-
BOOTSTRAP_FAIL_REGEX
|
13
|
+
BOOTSTRAP_FAIL_REGEX = /^[A-Z][a-z]{2} \d{2} \d{2}:\d{2}:\d{2}\.\d{3} \[err\] .*/
|
15
14
|
|
16
|
-
DIR_MSG
|
15
|
+
DIR_MSG = 'data_dir must exist and be a dir'
|
17
16
|
DATA_FILES = %w[cached-certs cached-microdesc-consensus cached-microdescs.new].freeze
|
18
17
|
|
19
18
|
class << self
|
@@ -36,6 +35,7 @@ module Selenium
|
|
36
35
|
pid = Process.spawn tor_command, out: io, err: :out
|
37
36
|
io.close
|
38
37
|
parse_tor_bootstrap_errors_with_timeout(r, timeout: timeout)
|
38
|
+
# tor process now bootstrapped
|
39
39
|
read_from_data_files
|
40
40
|
@pid = pid
|
41
41
|
rescue Timeout::Error
|
@@ -88,7 +88,7 @@ module Selenium
|
|
88
88
|
break '' if line.match BOOTSTRAP_SUCCESS_REGEX
|
89
89
|
end
|
90
90
|
end
|
91
|
-
raise(TorProcessError, "Tor failed to start with errors:\n\n#{errors}") unless errors.empty?
|
91
|
+
raise(Tor::TorProcessError, "Tor failed to start with errors:\n\n#{errors}") unless errors.empty?
|
92
92
|
end
|
93
93
|
|
94
94
|
def read_from_data_files
|
@@ -101,7 +101,7 @@ module Selenium
|
|
101
101
|
|
102
102
|
def timeout_with(pid, timeout)
|
103
103
|
Process.kill 'KILL', pid if pid
|
104
|
-
raise Error::TimeoutError, "Tor not bootstrapped after #{timeout} seconds"
|
104
|
+
raise WebDriver::Error::TimeoutError, "Tor not bootstrapped after #{timeout} seconds" # regular s-w error
|
105
105
|
end
|
106
106
|
end
|
107
107
|
end
|
data/lib/tor/torrc.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'error'
|
3
4
|
require_relative 'options'
|
4
5
|
|
5
6
|
module Selenium
|
@@ -7,9 +8,7 @@ module Selenium
|
|
7
8
|
module Tor
|
8
9
|
# Respresentation of a torrc file
|
9
10
|
class Torrc
|
10
|
-
|
11
|
-
|
12
|
-
DEFAULT_PORTS = { 'SocksPort' => 9150, 'ControlPort' => 9151 }.freeze
|
11
|
+
FIXED_CONFIG_KEYS = %w[DataDirectory GeoIPFile GeoIPv6File SocksPort].freeze
|
13
12
|
INVALID_OPTION_REGEX = %r{\[warn\] Failed to parse/validate config: (.*).$}
|
14
13
|
|
15
14
|
attr_reader :path
|
@@ -29,20 +28,26 @@ module Selenium
|
|
29
28
|
raise ArgumentError, 'Torrc#write_to_config takes a hash as argument' unless hash.is_a? Hash
|
30
29
|
|
31
30
|
validate_torrc_options hash
|
32
|
-
@torrc_file.write hash_to_config_string(config.merge(hash))
|
31
|
+
@torrc_file.write hash_to_config_string(config.merge(hash).merge(fixed_config))
|
33
32
|
@torrc_file.rewind
|
34
33
|
end
|
35
34
|
|
36
35
|
private
|
37
36
|
|
38
37
|
def write_default_config
|
39
|
-
write_to_config
|
38
|
+
write_to_config fixed_config
|
39
|
+
end
|
40
|
+
|
41
|
+
def fixed_config
|
42
|
+
@fixed_config ||= FIXED_CONFIG_KEYS.zip([@data_dir, geoip_file, geoip6_file, 'auto']).to_h
|
43
|
+
end
|
44
|
+
|
45
|
+
def geoip_file
|
46
|
+
File.join(TBB_TOR_DATA_DIR, 'geoip')
|
40
47
|
end
|
41
48
|
|
42
|
-
def
|
43
|
-
|
44
|
-
'GeoIPFile' => File.join(TBB_TOR_DATA_DIR, 'geoip'),
|
45
|
-
'GeoIPv6File' => File.join(TBB_TOR_DATA_DIR, 'geoip6') }
|
49
|
+
def geoip6_file
|
50
|
+
File.join(TBB_TOR_DATA_DIR, 'geoip6')
|
46
51
|
end
|
47
52
|
|
48
53
|
def validate_torrc_options(hash)
|
data/lib/tor/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: selenium_tor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- MatzFan
|
@@ -202,11 +202,11 @@ files:
|
|
202
202
|
- lib/selenium_tor.rb
|
203
203
|
- lib/service.rb
|
204
204
|
- lib/tor/driver.rb
|
205
|
+
- lib/tor/error.rb
|
205
206
|
- lib/tor/libxul_checksums.yml
|
206
207
|
- lib/tor/libxul_patchable.rb
|
207
208
|
- lib/tor/options.rb
|
208
209
|
- lib/tor/profile.rb
|
209
|
-
- lib/tor/system_tor.rb
|
210
210
|
- lib/tor/tor_prefs.rb
|
211
211
|
- lib/tor/tor_process.rb
|
212
212
|
- lib/tor/torrc.rb
|
data/lib/tor/system_tor.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Selenium
|
4
|
-
module WebDriver
|
5
|
-
module Tor
|
6
|
-
# DEPRECATED
|
7
|
-
class SystemTor
|
8
|
-
attr_reader :opts
|
9
|
-
|
10
|
-
def initialize(opts = {})
|
11
|
-
warn '[DEPRECATION] `SystemTor` options are deprecated in `selenium_tor` 2.0. Use `tor_opts` instead.'
|
12
|
-
@opts = opts
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|