selenium_tor 1.4.0 → 1.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +15 -1
- data/lib/tor/driver.rb +4 -0
- data/lib/tor/libxul_checksums.yml +13 -0
- data/lib/tor/libxul_patchable.rb +98 -0
- data/lib/tor/options.rb +2 -0
- data/lib/tor/torrc.rb +8 -2
- data/lib/tor/version.rb +1 -1
- data/tmp/.placeholder +0 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c45649309a0d50821238c2dc502b8e1d5e9f2137a24229cd09c4493aa45ea7d
|
4
|
+
data.tar.gz: 56177ff95c346118c5497bc0cfa44a1de83d3705be663596d7aefe8ab475e72e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d8ed9f5b35b852ea189f755d33af91676cbfb3b5750506b9955653220ec5bda98303dfe89dbf2ff850bdbc538d37d26169e5a5b74ff3f10cb3bfeff04b511e9
|
7
|
+
data.tar.gz: 4628ebe827ab1ef4004c7c5c09d1126a2aecb5ce53f52c652221ec76da36890f5ab9bb8df46b44da331a00d6a8a5eb8b94750ef8bdf84df6849d31cc1782f56f
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
## master (unreleased)
|
2
2
|
|
3
|
+
## [1.5.1] - 2024-09-02
|
4
|
+
|
5
|
+
Fix load path error in LibxulPatchable module
|
6
|
+
|
7
|
+
## [1.5.0] - 2024-08-31
|
8
|
+
|
9
|
+
### Bug fixes
|
10
|
+
|
11
|
+
* [#15](https://gitlab.com/matzfan/selenium-tor/-/issues/15)
|
12
|
+
* [#16](https://gitlab.com/matzfan/selenium-tor/-/issues/16)
|
13
|
+
* [#17](https://gitlab.com/matzfan/selenium-tor/-/issues/17)
|
14
|
+
|
15
|
+
### New features
|
16
|
+
|
17
|
+
* add ability to patch libxul.so to avoid webdriver fingerprint detection
|
18
|
+
|
3
19
|
## [1.4.0] - 2024-08-07
|
4
20
|
|
5
21
|
### Breaking changes
|
data/README.md
CHANGED
@@ -49,6 +49,19 @@ The location of the TBB is not expected to change during code execution.
|
|
49
49
|
|
50
50
|
Tor Selenium is tested on **Linux only** right now.
|
51
51
|
|
52
|
+
### Patching libxul.so
|
53
|
+
|
54
|
+
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`:
|
55
|
+
```ruby
|
56
|
+
Tor::Driver.libxul_patched? # is Tor Browser's libxul.so patched?
|
57
|
+
# => false
|
58
|
+
Tor::Driver.patch_libxul # patch libxul.so
|
59
|
+
Tor::Driver.libxul_patched?
|
60
|
+
# => true
|
61
|
+
Tor::Driver.unpatch_libxul # revert the patch and restore the libxul.so packaged with Tor Browser
|
62
|
+
```
|
63
|
+
The patcher uses the `[bsdiff](https://www.daemonology.net/bsdiff)` package, which must be installed on your system.
|
64
|
+
|
52
65
|
## Usage
|
53
66
|
```ruby
|
54
67
|
require 'selenium_tor'
|
@@ -63,7 +76,7 @@ A separate tor process is used for each driver. Failure to call `Driver#quit` af
|
|
63
76
|
|
64
77
|
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 options are recognized - see `man tor`. For convenience, "SocksPort" and "ControlPort" options may be set using snake_case symbols - i.e. :socks_port and :control_port. 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).
|
65
78
|
|
66
|
-
### Multiple driver instances
|
79
|
+
### Multiple driver instances
|
67
80
|
|
68
81
|
Running multiple tor processes requires that each uses different ports for SocksPort (and ControlPort, if used). These must be passed using the `:tor_opts` key. An example using the [Parallel gem](https://rubygems.org/gems/parallel):
|
69
82
|
```ruby
|
@@ -121,6 +134,7 @@ A number of constants are set during driver initialization based upon values fou
|
|
121
134
|
Tor::TBB_DIR # path to the TBB root directory
|
122
135
|
Tor::TBB_BROWSER_DIR # path to the 'Browser' directory in the above
|
123
136
|
Tor::TBB_BINARY_PATH # path to the firefox binary
|
137
|
+
Tor::TBB_TOR_BINARY_PATH # path to the bundled tor binary
|
124
138
|
Tor::TBB_PROFILE_DIR # path to the default profile directory
|
125
139
|
Tor::TBB_EXTENSIONS_DIR # path to the 'extensions' directory in the above
|
126
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
|
data/lib/tor/driver.rb
CHANGED
@@ -4,6 +4,7 @@ require 'open-uri'
|
|
4
4
|
require_relative '../service'
|
5
5
|
require_relative '../options'
|
6
6
|
require_relative '../firefox_prefs'
|
7
|
+
require_relative 'libxul_patchable'
|
7
8
|
require_relative 'profile'
|
8
9
|
require_relative 'tor_process'
|
9
10
|
|
@@ -15,6 +16,8 @@ module Selenium
|
|
15
16
|
|
16
17
|
# tor driver
|
17
18
|
class Driver < DelegateClass(DriverDelegate)
|
19
|
+
extend LibxulPatchable
|
20
|
+
|
18
21
|
TORRC_PATH_PREF = 'extensions.torlauncher.torrc_path'
|
19
22
|
TORRC = 'torrc'
|
20
23
|
BROWSER_SECURITY_LEVEL_PREF = 'browser.security_level.security_slider'
|
@@ -73,6 +76,7 @@ module Selenium
|
|
73
76
|
@tor_process = tor_process(opts)
|
74
77
|
@tor_process.start_tor(timeout: timeout)
|
75
78
|
rescue Tor::TorProcess::TorProcessError => e
|
79
|
+
instance_variable_get(:@instance)&.quit # avoids hanging firefox.real process
|
76
80
|
raise Error::WebDriverError, e
|
77
81
|
end
|
78
82
|
|
@@ -0,0 +1,13 @@
|
|
1
|
+
---
|
2
|
+
13.5.2:
|
3
|
+
unpatched_libxul: b2f8b3fd25466bd3ffa12fb34b422767b28e09577d5714d6d0c97f695dac15dc
|
4
|
+
patched_libxul: 7f761479c2d0307b97023455cfd7811b5749690302f54508b247720105dd0a3b
|
5
|
+
patch_checksum: 695f7534586c757781bd33a6dbc627cfe62d010edce20e5754fa5efff7aa80d0
|
6
|
+
14.0a2:
|
7
|
+
unpatched_libxul: e0eda8db975fe315e9be32b3bf95ee62767c60ee34deac97a7163f8ab0480dc9
|
8
|
+
patched_libxul: ed05f9c383f4ecbce69d978aefc0625c44874193707ebe11166e714b3e2b4f64
|
9
|
+
patch_checksum: 0cf817f97bdbe51fba5ad61d566934c9ebdda8fce5540bc803aeca23e0ac3e8b
|
10
|
+
14.0a3:
|
11
|
+
unpatched_libxul: f448fc180b547d622b969fe170028408f75493cf95be5e4c1180594daec2226b
|
12
|
+
patched_libxul: 337a4ef0e723069695294b37a4843126529c44e2bc4f90b1533b547100355db3
|
13
|
+
patch_checksum: 08dd8cab30c4416adf7ab6411e1346dce4a8b6f42e4c410adcd5bc63a71506e5
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'digest'
|
4
|
+
require 'json'
|
5
|
+
require 'open-uri'
|
6
|
+
require_relative 'options' # module needs access to consts therein defined
|
7
|
+
|
8
|
+
module Selenium
|
9
|
+
module WebDriver
|
10
|
+
module Tor
|
11
|
+
# methods to patch/unpatch libxul.so
|
12
|
+
module LibxulPatchable
|
13
|
+
class LibxulPatchableError < StandardError; end
|
14
|
+
|
15
|
+
# PATCH_REPO = 'https://gitlab.com/matzfan/keymaster/-/releases' # TODO
|
16
|
+
LIBXUL_CHECKSUMS = YAML.load_file(File.join(__dir__, 'libxul_checksums.yml'))[Tor::TBB_VERSION]
|
17
|
+
PATCH_REPO = 'https://gitlab.com/matzfan/keymaster/-/raw/main/patches/tor-browser'
|
18
|
+
ISSUES_URL = 'https://gitlab.com/matzfan/keymaster/-/issues'
|
19
|
+
|
20
|
+
def libxul_patched?
|
21
|
+
libxul_checksum = checksum_for Tor::TBB_LIBXUL
|
22
|
+
return true if patched_libxul_checksum_for_version == libxul_checksum
|
23
|
+
return false if unpatched_libxul_checksum_for_version == libxul_checksum
|
24
|
+
|
25
|
+
raise LibxulPatchableError, 'Unrecognized libxul.so'
|
26
|
+
end
|
27
|
+
|
28
|
+
def patch_libxul
|
29
|
+
return if libxul_patched?
|
30
|
+
|
31
|
+
patchfile = fetch_patchfile
|
32
|
+
valid? patchfile
|
33
|
+
FileUtils.mv Tor::TBB_LIBXUL, libxul_original # rename libxul.so
|
34
|
+
execute_patch patchfile
|
35
|
+
FileUtils.cp libxul_patched, Tor::TBB_LIBXUL
|
36
|
+
rescue OpenURI::HTTPError
|
37
|
+
raise LibxulPatchableError, "No patch for #{Tor::TBB_VERSION}, please raise an issue at #{ISSUES_URL}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def unpatch_libxul
|
41
|
+
return unless libxul_patched?
|
42
|
+
|
43
|
+
FileUtils.mv libxul_original, Tor::TBB_LIBXUL
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def libxul_original
|
49
|
+
"#{Tor::TBB_LIBXUL}.ORIGINAL"
|
50
|
+
end
|
51
|
+
|
52
|
+
def libxul_patched
|
53
|
+
"#{Tor::TBB_LIBXUL}.PATCHED"
|
54
|
+
end
|
55
|
+
|
56
|
+
def valid?(patchfile)
|
57
|
+
msg = "Invalid patch for #{Tor::TBB_VERSION}, please raise an issue at #{ISSUES_URL}"
|
58
|
+
raise LibxulPatchableError, msg unless patch_checksum_for_version == checksum_for(patchfile)
|
59
|
+
end
|
60
|
+
|
61
|
+
def execute_patch(patchfile)
|
62
|
+
raise LibxulPatchableError, 'bspatch not found, please install bsdiff' if `which bspatch`.empty?
|
63
|
+
|
64
|
+
`bspatch #{libxul_original} #{libxul_patched} #{patchfile}`
|
65
|
+
end
|
66
|
+
|
67
|
+
def unpatched_libxul_checksum_for_version
|
68
|
+
LIBXUL_CHECKSUMS['unpatched_libxul']
|
69
|
+
end
|
70
|
+
|
71
|
+
def patched_libxul_checksum_for_version
|
72
|
+
LIBXUL_CHECKSUMS['patched_libxul']
|
73
|
+
end
|
74
|
+
|
75
|
+
def patch_checksum_for_version
|
76
|
+
LIBXUL_CHECKSUMS['patch_checksum']
|
77
|
+
end
|
78
|
+
|
79
|
+
def checksum_for(file)
|
80
|
+
Digest::SHA256.file(file).hexdigest
|
81
|
+
end
|
82
|
+
|
83
|
+
def fetch_patchfile
|
84
|
+
tmp = Tempfile.new.tap(&:binmode)
|
85
|
+
URI.parse(patch_url).open('rb') do |f|
|
86
|
+
tmp.write(f.read)
|
87
|
+
tmp.tap(&:flush)
|
88
|
+
end
|
89
|
+
tmp.path
|
90
|
+
end
|
91
|
+
|
92
|
+
def patch_url
|
93
|
+
File.join PATCH_REPO, "#{Tor::TBB_VERSION}.patch"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/tor/options.rb
CHANGED
@@ -15,8 +15,10 @@ module Selenium
|
|
15
15
|
|
16
16
|
Tor::TBB_DIR = ENV.fetch('TOR_BROWSER_ROOT_DIR', nil) || DEFAULT_TBB_DIR
|
17
17
|
Tor::TBB_BROWSER_DIR = File.join Tor::TBB_DIR, 'Browser'
|
18
|
+
Tor::TBB_LIBXUL = File.join Tor::TBB_BROWSER_DIR, 'libxul.so'
|
18
19
|
Tor::TBB_BINARY_PATH = File.join Tor::TBB_BROWSER_DIR, 'firefox'
|
19
20
|
Tor::TBB_TOR_BINARY_PATH = File.join Tor::TBB_BROWSER_DIR, *%w[TorBrowser Tor tor]
|
21
|
+
Tor::TBB_TOR_DATA_DIR = File.join Tor::TBB_BROWSER_DIR, *%w[TorBrowser Data Tor]
|
20
22
|
Tor::TBB_PROFILE_DIR = File.join Tor::TBB_BROWSER_DIR, *%w[TorBrowser Data Browser profile.default]
|
21
23
|
Tor::TBB_EXTENSIONS_DIR = File.join Tor::TBB_PROFILE_DIR, 'extensions'
|
22
24
|
Tor::TBB_VERSION = JSON.parse(File.read(File.join(Tor::TBB_BROWSER_DIR, 'tbb_version.json')))['version']
|
data/lib/tor/torrc.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'options'
|
3
|
+
require_relative 'options'
|
4
4
|
|
5
5
|
module Selenium
|
6
6
|
module WebDriver
|
@@ -36,7 +36,13 @@ module Selenium
|
|
36
36
|
private
|
37
37
|
|
38
38
|
def write_default_config
|
39
|
-
write_to_config DEFAULT_PORTS.merge(
|
39
|
+
write_to_config DEFAULT_PORTS.merge(default_config)
|
40
|
+
end
|
41
|
+
|
42
|
+
def default_config
|
43
|
+
{ 'DataDirectory' => @data_dir,
|
44
|
+
'GeoIPFile' => File.join(TBB_TOR_DATA_DIR, 'geoip'),
|
45
|
+
'GeoIPv6File' => File.join(TBB_TOR_DATA_DIR, 'geoip6') }
|
40
46
|
end
|
41
47
|
|
42
48
|
def validate_torrc_options(hash)
|
data/lib/tor/version.rb
CHANGED
data/tmp/.placeholder
ADDED
File without changes
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: selenium_tor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- MatzFan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-09-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: selenium-webdriver
|
@@ -47,6 +47,8 @@ files:
|
|
47
47
|
- lib/selenium_tor.rb
|
48
48
|
- lib/service.rb
|
49
49
|
- lib/tor/driver.rb
|
50
|
+
- lib/tor/libxul_checksums.yml
|
51
|
+
- lib/tor/libxul_patchable.rb
|
50
52
|
- lib/tor/options.rb
|
51
53
|
- lib/tor/profile.rb
|
52
54
|
- lib/tor/system_tor.rb
|
@@ -56,6 +58,7 @@ files:
|
|
56
58
|
- lib/tor/version.rb
|
57
59
|
- selenium_tor.gemspec
|
58
60
|
- sig/tor.rbs
|
61
|
+
- tmp/.placeholder
|
59
62
|
homepage: https://gitlab.com/matzfan/selenium-tor
|
60
63
|
licenses:
|
61
64
|
- MIT
|