selenium_tor 1.0.0 → 1.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cd34aa798531de8ada12d53163c343733610aa6115141d58aeaa3b4875c40cd6
4
- data.tar.gz: f989c3ca02651ba825beefde17a4f2ac007ae25bb7c09e29ca080eee24cd3d03
3
+ metadata.gz: 6aeb8724ddcdf0d7260330ca616651d54b94ce33c6a635c71ef5c5f3577de220
4
+ data.tar.gz: 12b5d264f6a774dab990148feb15179d0b7873e42eb5b1c4bb99e8383f5e5577
5
5
  SHA512:
6
- metadata.gz: 1a71cffb60fc1e7f58d4a8cb4ffc9b0b42abfca1f5c541332b0febf50b78440fb5adfacb76f18e7289184bd7fb185582c4b338f6c2cde8177847b0db4e9a8ba7
7
- data.tar.gz: 3c9291018aede2ef805bf96110ff3742b4e2791634801be4ac607ad27e4d318ddafe931950946499a8547883c48ca750d6af9a409674b91e40cf9cce41e418b5
6
+ metadata.gz: deafbf4cbbc646e2fef5dc1800bc009edceb72906d65dc071942d0c742a49dd6aa17ac4fe2f88fc8d36f909445b31378996073f7d44b8cff473db2e9e3f5d403
7
+ data.tar.gz: 71c615ce16eb80f696aaa4dc26d73459df4ce8c4b7d994998580be1d93405baa5dc9ee94f321e7494f1567f3bed1f48481e53149829c2e1671268a6069d9d91f
data/.rubocop.yml CHANGED
@@ -10,8 +10,9 @@ AllCops:
10
10
  Style/HashSyntax:
11
11
  Enabled: false # yuk Ruby 3.1
12
12
 
13
- Layout/LineLength:
14
- Max: 120
13
+ Naming/MethodName:
14
+ Exclude:
15
+ - !ruby/regexp /test_.*\.rb$/ # for test_FOO constant tests
15
16
 
16
17
  Security/Eval:
17
18
  Exclude:
@@ -27,3 +28,10 @@ Style/RegexpLiteral:
27
28
 
28
29
  Minitest/TestMethodName:
29
30
  Enabled: true
31
+
32
+ Minitest/AssertTruthy:
33
+ Enabled: false
34
+
35
+ Minitest/TestFileName:
36
+ Exclude:
37
+ - test/features/fingerprinting/vglrun_test_fingerprintjs.rb
data/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  ## master (unreleased)
2
2
 
3
+ ## [1.2.0] - 2024-07-31
4
+
5
+ ### Bug fixes
6
+
7
+ * [#11](https://gitlab.com/matzfan/selenium-tor/-/issues/11)
8
+
9
+ ### New features
10
+
11
+ * add ability to change security level
12
+ * add ability to get new circuit for page ([#10](https://gitlab.com/matzfan/selenium-tor/-/issues/10))
13
+
14
+ ## [1.1.0] - 2024-07-28
15
+
16
+ ### Bug fixes
17
+
18
+ * [#9](https://gitlab.com/matzfan/selenium-tor/-/issues/9)
19
+
20
+ ### New features
21
+
22
+ * deprecate SystemTor options IFO tor_opts
23
+
3
24
  ## [1.0.0] - 2024-07-15
4
25
 
5
26
  ### New features
data/README.md CHANGED
@@ -17,6 +17,10 @@ The above approach will hide your IP, but there is a good chance your browser's
17
17
 
18
18
  ## Known issues
19
19
 
20
+ Known issues are recorded [here](https://gitlab.com/matzfan/selenium-tor/-/issues).
21
+
22
+ ### Fingerprinting
23
+
20
24
  The gem uses Xvfb to allow Tor Browser to be manipulated headlessly. Xvfb in turn uses `llvmpipe` software acceleration which may lead to issues with WebGL fingerprinting - see [issue #7](https://gitlab.com/matzfan/selenium-tor/-/issues/7). If this is a problem we recommend using [VirtualGL](https://www.virtualgl.org) to force Xvfb to use your hardware driver instead. This is done by prepending your executable code with the command `vglrun`. For an example see the section below on testing. VirtualGL can be installed from a [package repo](https://virtualgl.org/Downloads/YUM).
21
25
 
22
26
  ## Installation
@@ -44,39 +48,56 @@ options = Selenium::WebDriver::Tor::Options.new
44
48
  @driver.title # => Congratulations. This browser is configured to use Tor.
45
49
  @driver.quit
46
50
  ```
47
- By default Tor Broswer will use the bundled `tor` process, in which case the driver will not be instantiated until a connection to the Tor network is made. If the network is inaccessible for any reason a `TorNetworkError` will result.
48
-
49
- ### Multiple instances using the system tor
51
+ If the network is inaccessible for any reason a `TorNetworkError` will result.
50
52
 
51
- The following options require `tor` to be installed. Tor is available via various package managers e.g. `sudo apt install tor`.
53
+ ### Multiple driver instances
52
54
 
53
- If a `SystemTor` object is passed to options, the system `tor` will be used instead of the `tor` included in the Tor Browser Bundle (TBB).
54
- ```ruby
55
- system_tor = Selenium::WebDriver::Tor::SystemTor.new # writes a driver-specific torrc file
56
- options = Selenium::WebDriver::Tor::Options.new system_tor: system_tor
57
- @driver = Selenium::WebDriver.for :tor, options: options # new tor process started when :system_tor option passed to driver
58
- @driver.get 'https://example.com'
59
- @driver.quit # stops the new system tor process and deletes torrc file
60
- ```
61
- Multiple instances may be instantiated, in which case `SystemTor` options for :socks_port (default 9150) and :control_port (default 9151) must be set for each so they do not conflict. For example:
55
+ Running multiple `tor` processes requires that each uses different ports for SocksPort and ControlPort. These and other valid tor options can be passed using the `:tor_opts` key. Recognized options are snake_case equivalents of the camel case options reconized by tor. For a list see `man tor`. An example using the [Parallel gem](https://rubygems.org/gems/parallel):
62
56
  ```ruby
63
- def new_driver(socks_p, control_p)
64
- system_tor = Selenium::WebDriver::Tor::SystemTor.new(socks_port: socks_p, control_port: control_p)
65
- options = Selenium::WebDriver::Tor::Options.new system_tor: system_tor
66
- Selenium::WebDriver.for :tor, options: options
67
- end
57
+ require 'parallel'
68
58
 
69
59
  socks_port = 9150
70
60
  control_port = 9151
71
61
 
72
- driver1 = new_driver(socks_port, control_port)
73
- socks_port += 2
74
- control_port += 2
75
- driver2 = new_driver(socks_port, control_port)
62
+ def driver(socks_p, control_p)
63
+ options = Selenium::WebDriver::Tor::Options.new tor_opts: { socks_port: socks_p, control_port: control_p }
64
+ Selenium::WebDriver.for :tor, options: options # new tor process started with tor_opts
65
+ end
66
+
67
+ driver1 = driver(socks_port, control_port)
68
+ driver2 = driver(socks_port += 2, control_port += 2)
69
+
70
+ title = 'Congratulations. This browser is configured to use Tor.'
71
+
72
+ Parallel.all?([driver1, driver2], in_threads: 2) do |driver|
73
+ driver.get 'https://check.torproject.org'
74
+ driver.title == title
75
+ end
76
+ # => true
77
+
78
+ driver1&.quit
79
+ driver2&.quit
80
+ ```
81
+ ### Tor Browser specific functionality
76
82
 
77
- driver1.quit
78
- driver2.quit
83
+ You can get and set the secuirty level (shield icon in TB) as follows. 4 is 'Standard', 2 is 'Safer', 1 is 'Safest'.
84
+ ```ruby
85
+ @driver = Selenium::WebDriver.for :tor
86
+ @driver.security_level
87
+ # => 4 - the default value
88
+ @driver.security_level = 1
89
+ @driver.security_level
90
+ # => 1
91
+ @driver.quit
92
+ ```
93
+ You can get a new circuit for the current page ('New Tor circuit for this site' on TB's application menu):
94
+ ```ruby
95
+ @driver = Selenium::WebDriver.for :tor
96
+ @driver.get 'https://example.com'
97
+ @driver.new_circuit_for_page # new circuit for the current page only
98
+ @driver.quit
79
99
  ```
100
+ ### Miscellaneous
80
101
 
81
102
  The `Selenium::WebDriver::Tor` namespace is used for `Driver`, `Options`, `Profile` and all tor-specific classes. Otherwise Selenium's `Selenium::WebDriver::Firefox` namespace is used.
82
103
 
@@ -0,0 +1,7 @@
1
+ DO NOT MODIFY THE CONTENTS OF THIS DIRECTORY
2
+
3
+ Any adjustment to bundled fonts will result in an altered fingerprint. Font
4
+ fingerprinting is more than just detecting what fonts you have, it also includes
5
+ font fallbacks and characters (unicode code points) and any change in those can
6
+ be measured.
7
+
data/lib/tor/driver.rb CHANGED
@@ -1,58 +1,83 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'open-uri'
4
- require_relative 'driver_not_yet_connected_to_tor_network'
4
+ require_relative '../service'
5
+ require_relative '../options'
6
+ require_relative 'profile'
7
+ require_relative 'tor_process'
5
8
 
6
9
  module Selenium
7
10
  module WebDriver
8
11
  module Tor
12
+ # delegate class
13
+ class DriverDelegate < Firefox::Driver; end
14
+
9
15
  # tor driver
10
- class Driver < DelegateClass(DriverNotYetConnectedToTorNetwork)
16
+ class Driver < DelegateClass(DriverDelegate)
11
17
  class TorNetworkError < StandardError; end
12
18
 
13
- CONNECT_BUTTON_ID = 'network-status-tor-connect-button' # visible only until connected
14
- TOR_PREFS_CONNECTION_URL = 'about:preferences#connection'
15
-
16
- attr_reader :system_tor
19
+ TB_SECURITY_LEVELS = [4, 2, 1].freeze
17
20
 
18
21
  def initialize(options: nil, **)
19
- instantiate_driver_from_tbb_dir(options: options, **)
20
- setup_system_tor options.system_tor if options&.system_tor
22
+ @data_dir = Dir.mktmpdir
23
+ @options = options || Options.new # fix for issue #11, 'tis a puzzlement
24
+ add_torrc_path_to_options
25
+ @instance = DriverDelegate.new(options: @options, **)
26
+ install_extensions @instance
27
+ create_tor_process_and_start_tor @options.tor_opts
21
28
  super(@instance)
22
- install_extensions
23
- wait_for_tor_connection unless system_tor # no need if system tor used
29
+ end
30
+
31
+ def browser
32
+ :tor # overides :firefox
24
33
  end
25
34
 
26
35
  def quit
27
- system_tor&.stop_tor
36
+ @tor_process&.stop_tor
37
+ FileUtils.rm_rf @data_dir
28
38
  super
29
39
  end
30
40
 
31
- private
41
+ def security_level
42
+ old_context = context
43
+ self.context = 'chrome'
44
+ execute_script("return Services.prefs.getIntPref('browser.security_level.security_slider')")
45
+ ensure
46
+ self.context = old_context
47
+ end
32
48
 
33
- def instantiate_driver_from_tbb_dir(...)
34
- cwd = FileUtils.pwd
35
- FileUtils.cd TBB_BROWSER_DIR # crucial - fixes [#2](https://gitlab.com/matzfan/selenium-tor/-/issues/2)
36
- @instance = DriverNotYetConnectedToTorNetwork.new(...)
49
+ def security_level=(int)
50
+ old_context = context
51
+ self.context = 'chrome'
52
+ raise(ArgumentError, 'Security level can be set to 4, 2 or 1') unless TB_SECURITY_LEVELS.include?(int)
53
+
54
+ execute_script("return Services.prefs.setIntPref('browser.security_level.security_slider', #{int})")
55
+ ensure
56
+ self.context = old_context if old_context
57
+ end
58
+
59
+ def new_circuit_for_page
60
+ old_context = context
61
+ self.context = 'chrome'
62
+ execute_script "ChromeUtils.importESModule('resource://gre/modules/TorDomainIsolator.sys.mjs');
63
+ TorDomainIsolator.newCircuitForDomain('#{current_url}')"
37
64
  ensure
38
- FileUtils.cd cwd
65
+ self.context = old_context
39
66
  end
40
67
 
41
- def wait_for_tor_connection
42
- @instance.get TOR_PREFS_CONNECTION_URL
43
- Wait.new(timeout: 10).until { !@instance.find_element(:id, CONNECT_BUTTON_ID).displayed? }
44
- rescue Selenium::WebDriver::Error::TimeoutError => e
45
- @instance.quit # abort initialization
46
- raise TorNetworkError, "Cannot connect to Tor network: #{e.message}"
68
+ private
69
+
70
+ def add_torrc_path_to_options
71
+ @options.prefs['extensions.torlauncher.torrc_path'] = File.join(@data_dir, 'torrc')
47
72
  end
48
73
 
49
- def install_extensions
50
- Pathname.new(TBB_EXTENSIONS_DIR).children.each { |xpi_path| @instance.install_addon xpi_path }
74
+ def install_extensions(instance)
75
+ Pathname.new(TBB_EXTENSIONS_DIR).children.each { |xpi_path| instance.install_addon xpi_path }
51
76
  end
52
77
 
53
- def setup_system_tor(system_tor)
54
- @system_tor = system_tor
55
- system_tor.start_tor
78
+ def create_tor_process_and_start_tor(opts)
79
+ @tor_process = TorProcess.new(@data_dir, opts || {})
80
+ @tor_process.start_tor
56
81
  end
57
82
  end
58
83
  end
data/lib/tor/options.rb CHANGED
@@ -9,44 +9,47 @@ module Selenium
9
9
  module Tor
10
10
  # tor options
11
11
  class Options < Firefox::Options
12
- CAPABILITIES = CAPABILITIES.merge(system_tor: 'system_tor')
12
+ CAPABILITIES = CAPABILITIES.merge(tor_opts: 'tor_opts')
13
+ CAPABILITIES[:system_tor] = 'system_tor' # DEPRECATED 2.0
13
14
  DEFAULT_TBB_DIR = File.join Dir.home, 'tor-browser'
14
15
 
15
16
  Tor::TBB_DIR = ENV.fetch('TOR_BROWSER_ROOT_DIR', nil) || DEFAULT_TBB_DIR
16
17
  Tor::TBB_BROWSER_DIR = File.join Tor::TBB_DIR, 'Browser'
17
18
  Tor::TBB_BINARY_PATH = File.join Tor::TBB_BROWSER_DIR, 'firefox'
19
+ Tor::TBB_TOR_BINARY_PATH = File.join Tor::TBB_BROWSER_DIR, *%w[TorBrowser Tor tor]
18
20
  Tor::TBB_PROFILE_DIR = File.join Tor::TBB_BROWSER_DIR, *%w[TorBrowser Data Browser profile.default]
19
21
  Tor::TBB_EXTENSIONS_DIR = File.join Tor::TBB_PROFILE_DIR, 'extensions'
20
22
  Tor::TBB_VERSION = JSON.parse(File.read(File.join(Tor::TBB_BROWSER_DIR, 'tbb_version.json')))['version']
21
23
 
22
- attr_reader :system_tor # read by Driver
24
+ attr_reader :tor_opts
23
25
 
24
26
  def initialize(log_level: nil, **opts)
25
- @system_tor_prefs = {}
26
- system_tor_prefs(opts.delete(:system_tor)) if opts[:system_tor] # must be deleted before call to super
27
- super(log_level: log_level, **tor_options(opts.delete(:prefs)).merge(opts))
27
+ opts[:tor_opts] = opts.delete(:system_tor).opts if opts[:system_tor] # DEPRECATED 2.0
28
+ @tor_opts = opts[:tor_opts] ? opts.delete(:tor_opts) : {} # must be deleted before call to super
28
29
  do_start_tor_browser_script_stuff # stuff the start-tor-browser script in TBB does
30
+ copy_fonts # so we don't have to change dir before executing TB binary - issues #2 and #9
31
+ super(log_level: log_level, **tor_options(opts.delete(:prefs)).merge(opts))
29
32
  end
30
33
 
31
34
  private
32
35
 
33
- def system_tor_prefs(system_tor)
34
- @system_tor = system_tor
35
- @system_tor_prefs = system_tor.prefs
36
- end
37
-
38
36
  def tor_options(prefs)
39
- { binary: TBB_BINARY_PATH, prefs: (prefs || {}).merge(TOR_PREFS).merge(@system_tor_prefs) }
37
+ { binary: TBB_BINARY_PATH, prefs: (prefs || {}).merge(TOR_PREFS) }
40
38
  end
41
39
 
42
40
  def do_start_tor_browser_script_stuff
43
41
  ENV['SESSION_MANAGER'] = nil
44
42
  ENV['XAUTHORITY'] = File.join(Dir.home, '.Xauthority') unless ENV.fetch('XAUTHORITY', nil)
45
- ENV['FONTCONFIG_PATH'] = File.join Tor::TBB_BROWSER_DIR, 'fontconfig' # supposed to stop font leaks..
43
+ ENV['FONTCONFIG_PATH'] = File.join TBB_BROWSER_DIR, 'fontconfig'
46
44
  ENV['FONTCONFIG_FILE'] = 'fonts.conf'
47
45
  FileUtils.rm_rf File.join(Tor::TBB_BROWSER_DIR, *%w[TorBrowser Data fontconfig])
48
46
  ENV['GSETTINGS_BACKEND'] = 'memory'
49
- # cd to TBB_BROWSER_DIR now handled in Tor::Driver
47
+ end
48
+
49
+ def copy_fonts
50
+ return unless Dir[File.join('fonts', '*')].size == 1 # README checked into git
51
+
52
+ FileUtils.cp(Dir[File.join(Tor::TBB_BROWSER_DIR, 'fonts', '*')], File.expand_path('fonts'))
50
53
  end
51
54
  end
52
55
  end
@@ -1,82 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'timeout'
4
- require_relative 'torrc'
5
- require_relative '../string_extensions'
6
-
7
3
  module Selenium
8
4
  module WebDriver
9
5
  module Tor
10
- # Respresentation of a system tor process
6
+ # DEPRECATED
11
7
  class SystemTor
12
- include StringExtensions
13
-
14
- class SystemTorError < StandardError; end
15
-
16
- BOOTSTRAP_SUCCESS_REGEX = /Bootstrapped 100% \(done\): Done$/
17
- BOOTSTRAP_FAIL_REGEX = /^[A-Z][a-z]{2} \d{1,2} \d{2}:\d{2}:\d{2}\.\d{3} \[err\] .*/
18
- # BOOTSTRAP_TIMEOUT_REGEX = /^[A-Z][a-z]{2} \d{1,2} \d{2}:\d{2}:\d{2}\.\d{3} \[err\] .*/
19
-
20
- TORRC_PREFS = { 'extensions.torlauncher.start_tor' => false }.freeze
21
- TORRC_PATH_KEY = 'extensions.torlauncher.torrc_path'
22
-
23
- attr_reader :pid, :config
8
+ attr_reader :opts
24
9
 
25
10
  def initialize(opts = {})
26
- raise SystemTorError, 'tor executable not found in PATH' unless tor_executable?
27
- raise ArgumentError, 'SystemTor.new takes an options hash' unless opts.is_a? Hash
28
-
29
- @opts = map_opts_to_torrc_keys opts
30
- @data_dir = Dir.mktmpdir # each tor process needs a separate data directory
31
- @torrc = Torrc.new(@data_dir)
32
- @config ||= setup_config # Hash to store torrc config
33
- end
34
-
35
- def prefs
36
- TORRC_PREFS.merge({ TORRC_PATH_KEY => @torrc.path })
37
- end
38
-
39
- def start_tor
40
- r, io = IO.pipe
41
- pid = Process.spawn "tor -f #{@torrc.path}", out: io, err: :out
42
- io.close
43
- errors = parse_tor_bootstrap_errors r
44
- errors.empty? ? @pid = pid : raise(SystemTorError, "Tor failed to start with errors:\n\n#{errors}")
45
- ensure
46
- r.close
47
- end
48
-
49
- def stop_tor
50
- Process.kill 'KILL', pid if pid
51
- FileUtils.rm_rf @data_dir if @data_dir
52
- @pid = nil
53
- end
54
-
55
- private
56
-
57
- def map_opts_to_torrc_keys(opts)
58
- raise SystemTorError, 'Options hash keys must be snake case' unless opts.keys.map!(&:to_s).all?(&:snake_case?)
59
-
60
- opts.transform_keys { |k| k.to_s.split('_').map(&:capitalize).join }
61
- end
62
-
63
- def setup_config
64
- @torrc.write_to_config @opts
65
- @torrc.config
66
- end
67
-
68
- def tor_executable?
69
- `which tor`
70
- end
71
-
72
- def parse_tor_bootstrap_errors(io)
73
- lines = []
74
- io.each_line do |line|
75
- lines << line
76
- break lines if line.match BOOTSTRAP_FAIL_REGEX
77
- break [] if line.match BOOTSTRAP_SUCCESS_REGEX
78
- # break false if line.match BOOTSTRAP_TIMEOUT_REGEX
79
- end
11
+ warn '[DEPRECATION] `SystemTor` options are deprecated in `selenium_tor` 2.0. Use `tor_opts` instead.'
12
+ @opts = opts
80
13
  end
81
14
  end
82
15
  end
data/lib/tor/tor_prefs.rb CHANGED
@@ -17,7 +17,8 @@ module Selenium
17
17
 
18
18
  OTHER_PREFS = {
19
19
  'intl.language_notification.shown' => true, # affects font fingerprint (viewport size)
20
- 'remote.active-protocols' => 3 # CDP & BiDi future support
20
+ 'remote.active-protocols' => 3, # CDP & BiDi future support
21
+ 'extensions.torlauncher.start_tor' => false
21
22
  }.freeze
22
23
 
23
24
  TOR_PREFS = FIRST_CONNECTION_PREFS.merge OTHER_PREFS
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'timeout'
4
+ require_relative 'torrc'
5
+ require_relative '../string_extensions'
6
+
7
+ module Selenium
8
+ module WebDriver
9
+ module Tor
10
+ # Respresentation of a tor process
11
+ class TorProcess
12
+ include StringExtensions
13
+
14
+ class TorProcessError < StandardError; end
15
+
16
+ BOOTSTRAP_SUCCESS_REGEX = /Bootstrapped 100% \(done\): Done$/
17
+ BOOTSTRAP_FAIL_REGEX = /^[A-Z][a-z]{2} \d{1,2} \d{2}:\d{2}:\d{2}\.\d{3} \[err\] .*/
18
+ # BOOTSTRAP_TIMEOUT_REGEX = /^[A-Z][a-z]{2} \d{1,2} \d{2}:\d{2}:\d{2}\.\d{3} \[err\] .*/
19
+
20
+ attr_reader :pid, :config
21
+
22
+ def initialize(data_dir, opts = {})
23
+ valid_data_dir?(data_dir)
24
+ raise ArgumentError, 'TorProcess.new takes an options hash' unless opts.is_a? Hash
25
+
26
+ @data_dir = data_dir # each tor process needs a separate data directory
27
+ @opts = map_opts_to_torrc_keys opts
28
+ @torrc = Torrc.new(@data_dir)
29
+ @config ||= setup_config # Hash to store torrc config
30
+ end
31
+
32
+ def start_tor
33
+ r, io = IO.pipe
34
+ pid = Process.spawn "#{TBB_TOR_BINARY_PATH} -f #{@torrc.path}", out: io, err: :out
35
+ io.close
36
+ errors = parse_tor_bootstrap_errors r
37
+ errors.empty? ? @pid = pid : raise(TorProcessError, "Tor failed to start with errors:\n\n#{errors}")
38
+ ensure
39
+ r.close
40
+ end
41
+
42
+ def stop_tor
43
+ Process.kill 'KILL', pid if pid
44
+ FileUtils.rm_rf @data_dir if @data_dir
45
+ @pid = nil
46
+ end
47
+
48
+ # private
49
+
50
+ def valid_data_dir?(dir)
51
+ msg = 'data_dir must exist and be a dir'
52
+ raise ArgumentError, msg unless Pathname.new(dir.to_s).directory? && Pathname.new(dir.to_s).empty?
53
+ end
54
+
55
+ def map_opts_to_torrc_keys(opts)
56
+ raise TorProcessError, 'Options keys must be snake case' unless opts.keys.map!(&:to_s).all?(&:snake_case?)
57
+
58
+ opts.transform_keys { |k| k.to_s.split('_').map(&:capitalize).join }
59
+ end
60
+
61
+ def setup_config
62
+ @torrc.write_to_config @opts
63
+ @torrc.config
64
+ end
65
+
66
+ def parse_tor_bootstrap_errors(io)
67
+ lines = []
68
+ io.each_line do |line|
69
+ lines << line
70
+ break lines.join if line.match BOOTSTRAP_FAIL_REGEX
71
+ break '' if line.match BOOTSTRAP_SUCCESS_REGEX
72
+ # break false if line.match BOOTSTRAP_TIMEOUT_REGEX
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
data/lib/tor/torrc.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'options' # for Tor::TBB_TOR_BINARY_PATH
4
+
3
5
  module Selenium
4
6
  module WebDriver
5
7
  module Tor
@@ -41,7 +43,7 @@ module Selenium
41
43
  tmp = Tempfile.new
42
44
  tmp.write hash_to_config_string(hash)
43
45
  tmp.rewind
44
- invalid_opts = parse_invalid_opts `tor -f #{tmp.path} --verify-config`
46
+ invalid_opts = parse_invalid_opts `#{TBB_TOR_BINARY_PATH} -f #{tmp.path} --verify-config`
45
47
  raise TorrcError, "Invalid torrc opts: #{invalid_opts}" unless invalid_opts.empty?
46
48
  ensure
47
49
  tmp.unlink
data/lib/tor/version.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  module Selenium
4
4
  module WebDriver
5
5
  module Tor
6
- VERSION = '1.0.0'
6
+ VERSION = '1.2.0'
7
7
  end
8
8
  end
9
9
  end
data/selenium_tor.gemspec CHANGED
@@ -30,5 +30,5 @@ Gem::Specification.new do |spec|
30
30
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
31
  spec.require_paths = ['lib']
32
32
 
33
- spec.add_runtime_dependency 'selenium-webdriver', '~> 4.22'
33
+ spec.add_dependency 'selenium-webdriver', '>= 4.23'
34
34
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: selenium_tor
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.2.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-07-15 00:00:00.000000000 Z
11
+ date: 2024-07-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: selenium-webdriver
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '4.22'
19
+ version: '4.23'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '4.22'
26
+ version: '4.23'
27
27
  description: An extension for Selenium::WebDriver that automates Tor Browser
28
28
  email:
29
29
  executables: []
@@ -39,17 +39,18 @@ files:
39
39
  - LICENSE.txt
40
40
  - README.md
41
41
  - Rakefile
42
+ - fonts/000_README.txt
42
43
  - lib/driver.rb
43
44
  - lib/options.rb
44
45
  - lib/selenium_tor.rb
45
46
  - lib/service.rb
46
47
  - lib/string_extensions.rb
47
48
  - lib/tor/driver.rb
48
- - lib/tor/driver_not_yet_connected_to_tor_network.rb
49
49
  - lib/tor/options.rb
50
50
  - lib/tor/profile.rb
51
51
  - lib/tor/system_tor.rb
52
52
  - lib/tor/tor_prefs.rb
53
+ - lib/tor/tor_process.rb
53
54
  - lib/tor/torrc.rb
54
55
  - lib/tor/version.rb
55
56
  - selenium_tor.gemspec
@@ -77,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
77
78
  - !ruby/object:Gem::Version
78
79
  version: '0'
79
80
  requirements: []
80
- rubygems_version: 3.5.15
81
+ rubygems_version: 3.5.16
81
82
  signing_key:
82
83
  specification_version: 4
83
84
  summary: Selenium extension for Tor Browser
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../service'
4
- require_relative '../options'
5
- require_relative '../tor/profile'
6
-
7
- module Selenium
8
- module WebDriver
9
- module Tor
10
- # subclass - doesn't wait to be connected to tor network
11
- class DriverNotYetConnectedToTorNetwork < Firefox::Driver
12
- def browser
13
- :tor # overides :firefox
14
- end
15
- end
16
- end
17
- end
18
- end