selenium_tor 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +15 -1
- data/lib/tor/driver.rb +4 -0
- data/lib/tor/libxul_patchable.rb +97 -0
- data/lib/tor/options.rb +2 -0
- data/lib/tor/torrc.rb +8 -2
- data/lib/tor/version.rb +1 -1
- data/libxul_checksums.yml +13 -0
- 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: defca2c98d6db63f24a6b4dda2a2ade30ce248af24fe670e4237cd3feda2d2eb
|
4
|
+
data.tar.gz: a976b592807e153f0aaabff92a02e22f55bf900ea35b7435ba66f305990e8b6b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76f9832dc38aac26dce3591d0c624f9f57dab9aca02ef732dcf6beb13ffbc3c0ab090964ee12cacc2b8bef7b16981f8ba1febfe5733eb3125c8e7899cf99d95a
|
7
|
+
data.tar.gz: 9bb0c63ff4cfeaf847d8a3adaaac562ef9c74783c4629976de3d54b9014d2316b28828276e1862e8e0be19c6d0625c897c04cee3dc17dcf5d72ede23223461b9
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
## master (unreleased)
|
2
2
|
|
3
|
+
## [1.5.0] - 2024-08-31
|
4
|
+
|
5
|
+
### Bug fixes
|
6
|
+
|
7
|
+
* [#15](https://gitlab.com/matzfan/selenium-tor/-/issues/15)
|
8
|
+
* [#16](https://gitlab.com/matzfan/selenium-tor/-/issues/16)
|
9
|
+
* [#17](https://gitlab.com/matzfan/selenium-tor/-/issues/17)
|
10
|
+
|
11
|
+
### New features
|
12
|
+
|
13
|
+
* add ability to patch libxul.so to avoid webdriver fingerprint detection
|
14
|
+
|
3
15
|
## [1.4.0] - 2024-08-07
|
4
16
|
|
5
17
|
### 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,97 @@
|
|
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
|
+
PATCH_REPO = 'https://gitlab.com/matzfan/keymaster/-/raw/main/patches/tor-browser'
|
17
|
+
ISSUES_URL = 'https://gitlab.com/matzfan/keymaster/-/issues'
|
18
|
+
|
19
|
+
def libxul_patched?
|
20
|
+
libxul_checksum = checksum_for Tor::TBB_LIBXUL
|
21
|
+
return true if patched_libxul_checksum_for_version == libxul_checksum
|
22
|
+
return false if unpatched_libxul_checksum_for_version == libxul_checksum
|
23
|
+
|
24
|
+
raise LibxulPatchableError, 'Unrecognized libxul.so'
|
25
|
+
end
|
26
|
+
|
27
|
+
def patch_libxul
|
28
|
+
return if libxul_patched?
|
29
|
+
|
30
|
+
patchfile = fetch_patchfile
|
31
|
+
valid? patchfile
|
32
|
+
FileUtils.mv Tor::TBB_LIBXUL, libxul_original # rename libxul.so
|
33
|
+
execute_patch patchfile
|
34
|
+
FileUtils.cp libxul_patched, Tor::TBB_LIBXUL
|
35
|
+
rescue OpenURI::HTTPError
|
36
|
+
raise LibxulPatchableError, "No patch for #{Tor::TBB_VERSION}, please raise an issue at #{ISSUES_URL}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def unpatch_libxul
|
40
|
+
return unless libxul_patched?
|
41
|
+
|
42
|
+
FileUtils.mv libxul_original, Tor::TBB_LIBXUL
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def libxul_original
|
48
|
+
"#{Tor::TBB_LIBXUL}.ORIGINAL"
|
49
|
+
end
|
50
|
+
|
51
|
+
def libxul_patched
|
52
|
+
"#{Tor::TBB_LIBXUL}.PATCHED"
|
53
|
+
end
|
54
|
+
|
55
|
+
def valid?(patchfile)
|
56
|
+
msg = "Invalid patch for #{Tor::TBB_VERSION}, please raise an issue at #{ISSUES_URL}"
|
57
|
+
raise LibxulPatchableError, msg unless patch_checksum_for_version == checksum_for(patchfile)
|
58
|
+
end
|
59
|
+
|
60
|
+
def execute_patch(patchfile)
|
61
|
+
raise LibxulPatchableError, 'bspatch not found, please install bsdiff' if `which bspatch`.empty?
|
62
|
+
|
63
|
+
`bspatch #{libxul_original} #{libxul_patched} #{patchfile}`
|
64
|
+
end
|
65
|
+
|
66
|
+
def unpatched_libxul_checksum_for_version
|
67
|
+
YAML.load_file('libxul_checksums.yml')[Tor::TBB_VERSION]['unpatched_libxul']
|
68
|
+
end
|
69
|
+
|
70
|
+
def patched_libxul_checksum_for_version
|
71
|
+
YAML.load_file('libxul_checksums.yml')[Tor::TBB_VERSION]['patched_libxul']
|
72
|
+
end
|
73
|
+
|
74
|
+
def patch_checksum_for_version
|
75
|
+
YAML.load_file('libxul_checksums.yml')[Tor::TBB_VERSION]['patch_checksum']
|
76
|
+
end
|
77
|
+
|
78
|
+
def checksum_for(file)
|
79
|
+
Digest::SHA256.file(file).hexdigest
|
80
|
+
end
|
81
|
+
|
82
|
+
def fetch_patchfile
|
83
|
+
tmp = Tempfile.new.tap(&:binmode)
|
84
|
+
URI.parse(patch_url).open('rb') do |f|
|
85
|
+
tmp.write(f.read)
|
86
|
+
tmp.tap(&:flush)
|
87
|
+
end
|
88
|
+
tmp.path
|
89
|
+
end
|
90
|
+
|
91
|
+
def patch_url
|
92
|
+
File.join PATCH_REPO, "#{Tor::TBB_VERSION}.patch"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
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
@@ -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
|
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.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- MatzFan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-08-
|
11
|
+
date: 2024-08-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: selenium-webdriver
|
@@ -47,6 +47,7 @@ files:
|
|
47
47
|
- lib/selenium_tor.rb
|
48
48
|
- lib/service.rb
|
49
49
|
- lib/tor/driver.rb
|
50
|
+
- lib/tor/libxul_patchable.rb
|
50
51
|
- lib/tor/options.rb
|
51
52
|
- lib/tor/profile.rb
|
52
53
|
- lib/tor/system_tor.rb
|
@@ -54,8 +55,10 @@ files:
|
|
54
55
|
- lib/tor/tor_process.rb
|
55
56
|
- lib/tor/torrc.rb
|
56
57
|
- lib/tor/version.rb
|
58
|
+
- libxul_checksums.yml
|
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
|