moby.rb 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 59fc23e9713b37a55d2e866bc1109b525dd188f04136092b05ae0b8f2a860d10
4
- data.tar.gz: 6945ecfdea1a8f3437bae309c1d9b0e20dbe31d3a28006699e145e9dd57abec9
3
+ metadata.gz: 6f4bd8e1d75dd3b141595bf678fb267890c5554a26999b147485bda0eaac40f7
4
+ data.tar.gz: c49e5c7240d47a06656b91c1108dacdd1016248d86d1b5eb4843beecb092fa33
5
5
  SHA512:
6
- metadata.gz: f909d78a0a23c40143f3ed9d876a80b5fdd1f963670cbaea39d5f5ad42224ee0458adf1a095c9734c65e95e122b6ba9b69ea65fe95e860edf03c12442c2eab65
7
- data.tar.gz: 1eb639787025eccdcc74517655651eef1e0ef2d142015abaad3523eab31dcc298f33e1a5bf7afb66735b281856261a49f03f499792eca4f7ad8c93c6f89036e1
6
+ metadata.gz: '029f6229354cdc1746db60befce2a266092c647dbd861c72871ad04b0abda2f46aa7568465a21b5c75543442456d03fd9979cce96a433fbc2a6ffe3898444fe7'
7
+ data.tar.gz: 8329d384ab5ff2ce15563cd07ddcda4ddecc97458558ecac9a3199607cb7dfdc240e56646cbaf479ee6bba9dda049da15abf0fbb24bd0adb7088da33fc8425a9
data/CHANGELOG ADDED
@@ -0,0 +1,120 @@
1
+ # CHANGELOG
2
+
3
+ ## 20260811
4
+
5
+ 2.0.0: Move the Mechanize engine into a pluggable backend and add a Selenium backend alongside it.
6
+
7
+ 1. ~ lib/Moby.rb: the monolithic Moby was the whole Mechanize engine; it becomes a thin facade that builds a Configuration, a RandomInputGenerator and the chosen backend, and delegates #counter_phish to it. The submission loop, the page, form and field finding, and the random credential generation all move out into the classes below.
8
+ 2. + lib/Moby/Backends/MechanizeBackend.rb: the Mechanize functionality, moved out of Moby and behind a backend interface, driven by Configuration and RandomInputGenerator.
9
+ 3. + lib/Moby/Backends/SeleniumBackend.rb: a second backend driving a real headless browser (Chrome or Firefox), for forms that filter non-browser clients so the Mechanize submissions never land.
10
+ 4. + lib/Moby/Backends.rb: Moby::Backends.for, which chooses the backend from the configuration: :mechanize (the default) or :selenium.
11
+ 5. + lib/Moby/Configuration.rb: Moby::Configuration, a settings object for a run (url, backend, browser, form and field identification, username generation, iterations, delay, word list).
12
+ 6. + lib/Moby/RandomInputGenerator.rb: Moby::RandomInputGenerator, the fake-credential generation (random username and password, optionally email-shaped), moved out of Moby.
13
+ 7. + lib/Selenium/ and lib/Thoran/Selenium/: Selenium::WebDriver::Driver#attempt (retry a block) and #element_present?, used by the Selenium backend.
14
+ 8. ~ bin/moby: builds a Configuration and runs the selected backend through the facade; + --backend, + --browser, + --iterations (moby runs until interrupted when it is omitted), + --delay; and the previously inert --username-prefilled is wired through, so only the password is submitted when the username is already on the form.
15
+ 9. - lib/File/self.collect.rb, - lib/Thoran/File/SelfCollect/self.collect.rb: File.collect was used only by the old Moby; RandomInputGenerator reads the word list with File.readlines.
16
+ 10. ~ test/moby_test.rb: it exercised the removed Moby monolith; rewritten to test the Moby facade (backend selection). + test/Moby/Configuration_test.rb, RandomInputGenerator_test.rb, Backends_test.rb, Backends/MechanizeBackend_test.rb and Backends/SeleniumBackend_test.rb.
17
+ 11. ~ moby.rb.gemspec: + selenium-webdriver (~> 4).
18
+ 12. ~ moby.rb.gemspec: required_ruby_version: /2.5.0/3.3.0/, which selenium-webdriver 4 requires.
19
+ 13. ~ Gemfile: + ostruct, which switches.rb requires and which is no longer a default gem as of Ruby 4.0.
20
+ 14. ~ lib/Moby/VERSION.rb: VERSION: /1.0.1/2.0.0/
21
+ 15. ~ test/Moby/VERSION_test.rb: /1.0.1/2.0.0/
22
+
23
+
24
+ ## 20260807
25
+
26
+ 1.0.1: Add a CHANGELOG in the form changelogger writes, and retire CHANGES.txt.
27
+
28
+ 1. + CHANGELOG, in the form changelogger writes: a dated heading per version, the version and its summary on the first line of the body, then the numbered items, newest first — the form the other repositories already use. Versions 0.8.0 to 1.0.0 are carried across from CHANGES.txt; 0.7.0 to 0.7.4 are recovered from the git-importall revisions, each of which carries a version and a date of its own. Nothing before 0.7.0 is recorded: the 2006 series stamps every version with the one creation date, and the revisions between it and 0.7.0 carry a date but no version, so neither a reliable date nor a reliable version can be had for them.
29
+ 2. - CHANGES.txt. The CHANGELOG holds that record now, and keeping both invites them to disagree. Its changelog_uri and file list in moby.rb.gemspec are pointed at CHANGELOG in its place.
30
+ 3. ~ lib/Moby/VERSION.rb: VERSION: /1.0.0/1.0.1/
31
+ 4. ~ test/Moby/VERSION_test.rb: /1.0.0/1.0.1/
32
+
33
+
34
+ ## 20260108
35
+
36
+ 1.0.0: Ensure that tests are in place and that version handling is working properly.
37
+
38
+ 1. + tests
39
+ 2. + moby.rb.gemspec
40
+ 3. ~ lib/moby.rb: - Moby::VERSION_STRING
41
+ 4. ~ lib/moby.rb: Fix finding username and password fields by name. It was returning the name of the field and not the field object.
42
+ 5. + lib/Moby/VERSION.rb
43
+ 6. ~ bin/moby: + --version flag
44
+ 7. ~ README.md: Updated installation and usage.
45
+ 8. ~ CHANGES.txt: Reorganised in descending order and added dates.
46
+ 9. ~ LICENSE.txt: Updated the years to include the year this was started: /2026/2006-2026/
47
+
48
+
49
+ ## 20260105
50
+
51
+ 0.9.1: Fix syntax errors in README.md.
52
+
53
+ 1. ~ README.md: Fix syntax errors.
54
+ 2. ~ lib/Moby.rb: VERSION_STRING: /0.9.0/0.9.1/
55
+
56
+
57
+ ## 20240605
58
+
59
+ 0.9.0: Merge of 2019's 0.8.0 and 2023's 0.8.1.
60
+
61
+
62
+ ## 20231206
63
+
64
+ 0.8.1: Fix when username or password field number is specified or nothing is specified.
65
+
66
+ 1. ~ lib/Whale: ~ set_username_field(): Fix when username field number is specified or nothing is specified.
67
+ 2. ~ lib/Whale: ~ set_password_field(): Fix when password field number is specified or nothing is specified.
68
+
69
+
70
+ ## 20231119
71
+
72
+ 0.8.0: An accidental fork of 0.7.0 in 2023.
73
+
74
+ 1. + README.md
75
+ 2. + CHANGES.txt
76
+ 3. + Gemfile
77
+ 4. ~ bin/whale: ~ main(): - args (unnecessary)
78
+ 5. ~ bin/whale VERSION_STRING --> lib/Whale::VERSION_STRING
79
+ 6. ~ bin/whale: ~ switches(): use Whale::VERSION_STRING
80
+ 7. ~ lib/Whale.rb: general tidying
81
+ 8. + lib/File/self.collect.rb
82
+
83
+
84
+ ## 20190820
85
+
86
+ 0.7.4: Rescue Net::OpenTimeout in the submission loop.
87
+
88
+ 1. ~ counter_phish(): + rescue Net::OpenTimeout.
89
+
90
+
91
+ ## 20190819
92
+
93
+ 0.7.3: Rescue Net::HTTP::Persistent::Error in place of EOFError.
94
+
95
+ 1. ~ counter_phish(): rescue Net::HTTP::Persistent::Error in place of EOFError.
96
+
97
+
98
+ ## 20190819
99
+
100
+ 0.7.2: Set field values on the field objects rather than through the setter methods.
101
+
102
+ 1. ~ counter_phish(): set the user agent and field values inline — mechanize.user_agent_alias, username_field.value, password_field.value — in place of set_user_agent()/set_username_field()/set_password_field().
103
+ 2. ~ username(): use the username_is_email_address? predicate, its default nil in place of false.
104
+ 3. ~ user_agent: attr_writer in place of attr_accessor.
105
+ 4. ~ counter_phish(): verbose reports username_field.value:password_field.value.
106
+
107
+
108
+ ## 20190819
109
+
110
+ 0.7.1: Assign to the field's value rather than replacing the field object.
111
+
112
+ 1. ~ set_username_field()/set_password_field(): set the field's value in place of replacing the field object at form.fields[n].
113
+ 2. ~ counter_phish(): + rescue EOFError; + pp page in debug.
114
+
115
+
116
+ ## 20190815
117
+
118
+ 0.7.0: The earliest recoverable version.
119
+
120
+ 1. whale floods a phishing form with fake credentials: counter_phish() loads the page, then loops submitting a generated username and password, each built from random dictionary words and TLDs. Recorded as an inventory of the first cleanly-versioned revision; the revision before it carries no version and a different structure, and is not reconstructed here.
data/Gemfile CHANGED
@@ -1,3 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
+
5
+ # switches.rb (the CLI option parser) requires ostruct, which is no longer a
6
+ # default gem as of Ruby 4.0, so it must be provided explicitly under bundler.
7
+ gem 'ostruct'
data/bin/moby CHANGED
@@ -11,12 +11,16 @@ require 'switches.rb'
11
11
 
12
12
  def switches
13
13
  Switches.new do |s|
14
- s.banner = 'Usage: whale <url> and any of the following options...'
14
+ s.banner = 'Usage: moby <url> and any of the following options...'
15
15
  s.set(:a, :user_agent){'What webclient I should pretend to be.'}
16
+ s.set(:b, :backend){'Which backend to use: mechanize (default) or selenium.'}
17
+ s.set(:browser){'Which browser the selenium backend should drive: chrome (default) or firefox.'}
16
18
  s.set(:debug?){'Show debugging information.'}
19
+ s.set(:delay){'Seconds to wait between submissions.'}
17
20
  s.set(:e?, :username_is_email_address?){'Automatically generate a username which is in the form of an email address.'}
18
21
  s.set(:f, :form, :form_name){'If left empty, the first form on the page will be used.'}
19
- s.set(:help){'Usage: whale <url> and any of the following options...'}
22
+ s.set(:help){'Usage: moby <url> and any of the following options...'}
23
+ s.set(:iterations){'How many submissions to make. If left empty, moby runs until interrupted.'}
20
24
  s.set(:n, :form_number){'This will set the number of the form in order of appearance on the page. Use zero-based indexing.'}
21
25
  s.set(:pass_field, :password_field, :pass_field_name, :password_field_name){'The name of the password field.'}
22
26
  s.set(:pass_field_number, :password_field_number){'The position of the password field in relation to the form it is attached to. Use zero-based indexing.'}
@@ -24,7 +28,7 @@ def switches
24
28
  s.set(:user_field, :username_field, :user_field_name, :username_field_name){'The name of the username field.'}
25
29
  s.set(:user_field_number, :username_field_number){'The position of the username field in relation to the form it is attached to. Use zero-based indexing.'}
26
30
  s.set(:username_hostname){'The hostname to be used when the username is an email address.'}
27
- s.set(:username_prefilled){'No need to supply an email address in the form.'}
31
+ s.set(:username_prefilled?){'The username is already filled in on the form, so only submit the password.'}
28
32
  s.set(:v?, :verbose?){'Outputs each submission as it goes.'}
29
33
  s.perform(:version) do
30
34
  puts "moby #{Moby::VERSION}"
@@ -35,31 +39,24 @@ end
35
39
 
36
40
  def main
37
41
  args = switches.to_h
38
- debug = args[:debug?]
39
- form_name = args[:form_name]
40
- form_number = args[:form_number]
41
- password_field_name = args[:password_field_name]
42
- password_field_number = args[:password_field_number]
43
- url = args[:url]
44
- user_agent = args[:user_agent]
45
- username_field_name = args[:username_field_name]
46
- username_field_number = args[:username_field_number]
47
- username_hostname = args[:username_hostname]
48
- username_is_email_address = args[:username_is_email_address?]
49
- verbose = args[:verbose?]
50
42
  moby = Moby.new(
51
- debug: debug,
52
- form_name: form_name,
53
- form_number: form_number,
54
- password_field_name: password_field_name,
55
- password_field_number: password_field_number,
56
- url: url,
57
- user_agent: user_agent,
58
- username_field_name: username_field_name,
59
- username_field_number: username_field_number,
60
- username_hostname: username_hostname,
61
- username_is_email_address: username_is_email_address,
62
- verbose: verbose
43
+ backend: args[:backend],
44
+ browser: args[:browser],
45
+ debug: args[:debug?],
46
+ delay: args[:delay],
47
+ form_name: args[:form_name],
48
+ form_number: args[:form_number],
49
+ iterations: args[:iterations],
50
+ password_field_name: args[:password_field_name],
51
+ password_field_number: args[:password_field_number],
52
+ url: args[:url],
53
+ user_agent: args[:user_agent],
54
+ username_field_name: args[:username_field_name],
55
+ username_field_number: args[:username_field_number],
56
+ username_hostname: args[:username_hostname],
57
+ username_is_email_address: args[:username_is_email_address?],
58
+ username_prefilled: args[:username_prefilled?],
59
+ verbose: args[:verbose?]
63
60
  )
64
61
  moby.counter_phish
65
62
  end
@@ -80,7 +80,7 @@ class Moby
80
80
  def fill_and_submit_login_form
81
81
  puts "Filling with: #{username}:#{password}" if @config.verbose?
82
82
  agent.user_agent_alias = @config.user_agent
83
- username_field.value = username
83
+ username_field.value = username unless @config.username_prefilled?
84
84
  password_field.value = password
85
85
  pp page if @config.debug?
86
86
  result = agent.submit(form)
@@ -3,8 +3,8 @@
3
3
 
4
4
  require 'selenium-webdriver'
5
5
 
6
- require_relative '../Selenium/WebDriver/Driver/Attempt/attempt'
7
- require_relative '../Selenium/WebDriver/SearchContext/ElementPresentQ/element_presentQ'
6
+ require_relative '../../Selenium/WebDriver/Driver/Attempt/attempt'
7
+ require_relative '../../Selenium/WebDriver/SearchContext/ElementPresentQ/element_presentQ'
8
8
 
9
9
  class Moby
10
10
  module Backends
@@ -26,24 +26,28 @@ class Moby
26
26
  end
27
27
 
28
28
  def driver
29
- puts "Setting up #{@config.browser} driver..." if @config.verbose
30
- case @config.browser.to_sym
31
- when :chrome
32
- options = Selenium::WebDriver::Chrome::Options.new
33
- options.add_argument('--headless') unless @config.debug
34
- options.add_argument('--disable-gpu')
35
- options.add_argument('--no-sandbox')
36
- options.add_argument("user-agent=#{@config.user_agent}") if @config.user_agent
37
- @driver = Selenium::WebDriver.for(:chrome, options: options)
38
- when :firefox
39
- options = Selenium::WebDriver::Firefox::Options.new
40
- options.add_argument('--headless') unless @config.debug
41
- options.add_preference('general.useragent.override', @config.user_agent) if @config.user_agent
42
- @driver = Selenium::WebDriver.for(:firefox, options: options)
43
- else
44
- @driver = Selenium::WebDriver.for(@config.browser)
45
- end
46
- puts "Driver setup complete." if @config.verbose?
29
+ @driver ||= (
30
+ puts "Setting up #{@config.browser} driver..." if @config.verbose
31
+ driver =
32
+ case @config.browser.to_sym
33
+ when :chrome
34
+ options = Selenium::WebDriver::Chrome::Options.new
35
+ options.add_argument('--headless') unless @config.debug
36
+ options.add_argument('--disable-gpu')
37
+ options.add_argument('--no-sandbox')
38
+ options.add_argument("user-agent=#{@config.user_agent}") if @config.user_agent
39
+ Selenium::WebDriver.for(:chrome, options: options)
40
+ when :firefox
41
+ options = Selenium::WebDriver::Firefox::Options.new
42
+ options.add_argument('--headless') unless @config.debug
43
+ options.add_preference('general.useragent.override', @config.user_agent) if @config.user_agent
44
+ Selenium::WebDriver.for(:firefox, options: options)
45
+ else
46
+ Selenium::WebDriver.for(@config.browser)
47
+ end
48
+ puts "Driver setup complete." if @config.verbose?
49
+ driver
50
+ )
47
51
  end
48
52
  alias_method :set_up_driver, :driver
49
53
 
@@ -105,8 +109,10 @@ class Moby
105
109
  driver.navigate.to(@config.url)
106
110
  wait_for_page_load
107
111
  driver.attempt do
108
- username_field.clear
109
- username_field.send_keys(username)
112
+ unless @config.username_prefilled?
113
+ username_field.clear
114
+ username_field.send_keys(username)
115
+ end
110
116
  password_field.clear
111
117
  password_field.send_keys(password)
112
118
  submit_form(form)
@@ -0,0 +1,20 @@
1
+ # lib/Moby/Backends.rb
2
+ # Moby::Backends
3
+
4
+ require_relative './Backends/MechanizeBackend'
5
+ require_relative './Backends/SeleniumBackend'
6
+
7
+ class Moby
8
+ module Backends
9
+ def self.for(config:, random_input_generator:)
10
+ case config.backend
11
+ when :mechanize
12
+ MechanizeBackend.new(config: config, random_input_generator: random_input_generator)
13
+ when :selenium
14
+ SeleniumBackend.new(config: config, random_input_generator: random_input_generator)
15
+ else
16
+ raise "Unknown backend: #{config.backend.inspect}."
17
+ end
18
+ end
19
+ end
20
+ end
@@ -21,6 +21,7 @@ class Moby
21
21
  :password_field_number,
22
22
  :username_hostname,
23
23
  :username_is_email_address,
24
+ :username_prefilled,
24
25
  :iterations,
25
26
  :delay,
26
27
  :word_list_path
@@ -58,6 +59,10 @@ class Moby
58
59
  @username_is_email_address || @username_hostname || @username_field_name == 'email'
59
60
  end
60
61
 
62
+ def username_prefilled?
63
+ @username_prefilled
64
+ end
65
+
61
66
  def debug?
62
67
  @debug
63
68
  end
@@ -73,36 +78,37 @@ class Moby
73
78
  private
74
79
 
75
80
  # @param url [String] The target URL
76
- # @param backend [Symbol] :mechanize or :selenium (default: :selenium)
81
+ # @param backend [Symbol] :mechanize or :selenium (default: :mechanize)
77
82
  # @param browser [Symbol] :chrome or :firefox (default: :chrome)
78
83
 
79
- def initialize(url:, backend: :selenium, browser: :chrome, **args)
84
+ def initialize(url:, backend: :mechanize, browser: :chrome, **args)
80
85
  @url = url
81
- @backend = backend.to_sym
86
+ @backend = (backend || :mechanize).to_sym
82
87
 
83
88
  # Browser configuration (for Selenium)
84
- @browser = browser.to_sym
89
+ @browser = (browser || :chrome).to_sym
85
90
  @user_agent = args[:user_agent]
86
91
 
87
92
  # Form identification
88
93
  @form_name = args[:form_name]
89
- @form_number = args[:form_number] || 0
94
+ @form_number = (args[:form_number] || 0).to_i
90
95
 
91
96
  # Field identification
92
- @username_field_name = args[:username_field_name]
93
- @username_field_number = args[:username_field_number] || 0
94
- @password_field_name = args[:password_field_name]
95
- @password_field_number = args[:password_field_number] || 1
97
+ @username_field_name = args[:username_field_name] || 'username'
98
+ @username_field_number = (args[:username_field_number] || 0).to_i
99
+ @password_field_name = args[:password_field_name] || 'password'
100
+ @password_field_number = (args[:password_field_number] || 1).to_i
96
101
 
97
102
  # Username configuration
98
103
  @username_hostname = args[:username_hostname]
99
104
  @username_is_email_address = args[:username_is_email_address] || false
105
+ @username_prefilled = args[:username_prefilled] || false
100
106
 
101
107
  # Runtime configuration
102
108
  @debug = args[:debug] || false
103
109
  @verbose = args[:verbose] || false
104
- @iterations = args[:iterations] || 100
105
- @delay = args[:delay] || 0
110
+ @iterations = args[:iterations] && args[:iterations].to_i
111
+ @delay = (args[:delay] || 0).to_i
106
112
  @word_list_path = args[:word_list_path] || '/usr/share/dict/words'
107
113
  end
108
114
 
data/lib/Moby/VERSION.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # Moby::VERSION
3
3
 
4
4
  class Moby
5
- VERSION = '1.0.0'
5
+ VERSION = '2.0.0'
6
6
  end
data/lib/Moby.rb CHANGED
@@ -1,179 +1,34 @@
1
1
  # Moby.rb
2
2
  # Moby
3
3
 
4
- require 'mechanize'
5
- require 'pp'
6
-
7
- require_relative './File/self.collect'
8
4
  require_relative './Moby/VERSION'
5
+ require_relative './Moby/Configuration'
6
+ require_relative './Moby/RandomInputGenerator'
7
+ require_relative './Moby/Backends'
9
8
 
10
9
  class Moby
11
- TLD = %w{com net org edu int mil gov arpa biz aero name coop info pro museum}
12
-
13
- attr_accessor\
14
- :debug,
15
- :form_name,
16
- :form_number,
17
- :password_field_name,
18
- :password_field_number,
19
- :url,
20
- :username_field_name,
21
- :username_field_number,
22
- :username_hostname,
23
- :username_is_email_address,
24
- :verbose
25
-
26
- attr_writer\
27
- :user_agent
28
-
29
- def initialize(
30
- debug: false,
31
- form_name: nil,
32
- form_number: 0,
33
- password_field_name: 'password',
34
- password_field_number: 1,
35
- url: nil,
36
- user_agent: nil,
37
- username_field_name: 'username',
38
- username_field_number: 0,
39
- username_hostname: nil,
40
- username_is_email_address: false,
41
- verbose: false
42
- )
43
- @debug = debug
44
- @form_name = form_name
45
- @form_number = form_number.to_i
46
- @password_field_name = password_field_name
47
- @password_field_number = password_field_number.to_i
48
- @url = url
49
- @user_agent = user_agent
50
- @username_field_name = username_field_name
51
- @username_field_number = username_field_number.to_i
52
- @username_hostname = username_hostname
53
- @username_is_email_address = username_is_email_address
54
- @verbose = verbose
55
- end
56
-
57
10
  def counter_phish
58
- start_time = Time.now
59
- puts "Moby session begun #{start_time}."
60
- submission_count = 0
61
- begin
62
- loop do
63
- mechanize.user_agent_alias = user_agent
64
- username_field.value = username
65
- password_field.value = password
66
- pp page if @debug
67
- result = mechanize.submit(form)
68
- pp result if @debug
69
- submission_count += 1
70
- puts "#{submission_count} #{username}:#{password}" if @verbose
71
- rescue Net::HTTP::Persistent::Error
72
- puts "\n\nNet::HTTP::Persistent::Error rescued.\n\n" if @verbose
73
- rescue Net::OpenTimeout
74
- puts "\n\nNet::OpenTimeout rescued.\n\n" if @verbose
75
- end
76
- ensure
77
- finish_time = Time.now
78
- time_delta_in_minutes = (finish_time - start_time) / 60
79
- submissions_per_minute = submission_count / time_delta_in_minutes
80
- puts "Moby session terminated #{finish_time} with #{submission_count} counter-phishes served in #{time_delta_in_minutes} minutes for an average of #{submissions_per_minute} submissions per minute."
81
- end
11
+ backend.counter_phish
82
12
  end
83
13
 
84
14
  private
85
15
 
86
- def mechanize
87
- @mechanize ||= Mechanize.new
88
- end
89
-
90
- def words(filename = '/usr/share/dict/words')
91
- @words ||= File.collect(filename){|line| line.chomp}
92
- end
93
-
94
- def random_word
95
- words[rand(words.size)]
96
- end
97
-
98
- def random_TLD
99
- TLD[rand(TLD.size)]
100
- end
101
-
102
- def random_user_agent
103
- agent_aliases = Mechanize::AGENT_ALIASES
104
- agent_aliases.delete('Mechanize')
105
- agent_aliases_keys = agent_aliases.keys
106
- agent_aliases_keys[rand(agent_aliases.size)]
16
+ def initialize(**args)
17
+ @configuration = Configuration.new(**args)
107
18
  end
108
19
 
109
- def page
110
- @page ||= (
111
- page = mechanize.get(@url)
112
- md = page.body.match(/meta.*?Refresh.*?url=(.*?)"/i)
113
- if md
114
- puts 'meta_refresh_url found' if @debug
115
- page = mechanize.get(md[1])
116
- end
117
- pp page if @debug
118
- page
20
+ def backend
21
+ @backend ||= Backends.for(
22
+ config: @configuration,
23
+ random_input_generator: random_input_generator
119
24
  )
120
25
  end
121
26
 
122
- def form
123
- @form ||= (
124
- if @form_name
125
- page.form(@form_name)
126
- elsif @form_number
127
- page.forms[@form_number]
128
- else
129
- page.forms[0]
130
- end
27
+ def random_input_generator
28
+ @random_input_generator ||= RandomInputGenerator.new(
29
+ word_list_path: @configuration.word_list_path,
30
+ username_hostname: @configuration.username_hostname,
31
+ username_is_email_address: @configuration.username_is_email_address?
131
32
  )
132
33
  end
133
-
134
- def username
135
- if username_is_email_address?
136
- if username_hostname
137
- "#{random_word}@#{@username_hostname}"
138
- else
139
- "#{random_word}@#{random_word}.#{random_TLD}"
140
- end
141
- else
142
- random_word
143
- end
144
- end
145
-
146
- def password
147
- random_word
148
- end
149
-
150
- def user_agent
151
- @user_agent || random_user_agent
152
- end
153
-
154
- def username_field
155
- if @username_field_name
156
- form.field(@username_field_name)
157
- elsif @username_field_number
158
- form.fields[@username_field_number]
159
- else
160
- form.fields[0]
161
- end
162
- end
163
-
164
- def password_field
165
- if @password_field_name
166
- form.field(@password_field_name)
167
- elsif @password_field_number
168
- form.fields[@password_field_number]
169
- else
170
- form.fields[1]
171
- end
172
- end
173
-
174
- # predicate methods
175
-
176
- def username_is_email_address?
177
- @username_is_email_address || @username_hostname || username_field.name == 'email'
178
- end
179
34
  end
@@ -1,4 +1,4 @@
1
- # moby.gemspec
1
+ # moby.rb.gemspec
2
2
 
3
3
  require_relative './lib/Moby/VERSION'
4
4
 
@@ -16,9 +16,10 @@ Gem::Specification.new do |spec|
16
16
  spec.homepage = 'https://github.com/thoran/moby'
17
17
  spec.license = 'MIT'
18
18
 
19
- spec.required_ruby_version = ">= 2.5.0"
19
+ spec.required_ruby_version = ">= 3.3.0"
20
20
 
21
21
  spec.add_dependency('mechanize', '~> 2')
22
+ spec.add_dependency('selenium-webdriver', '~> 4')
22
23
  spec.add_dependency('switches.rb', '~> 0')
23
24
 
24
25
  spec.add_development_dependency('minitest')
@@ -30,10 +31,10 @@ Gem::Specification.new do |spec|
30
31
  'bin/*',
31
32
  'lib/**/*.rb',
32
33
  'test/**/*.rb',
33
- 'CHANGES.txt',
34
+ 'CHANGELOG',
34
35
  'Gemfile',
35
36
  'LICENSE.txt',
36
- 'moby.gemspec',
37
+ 'moby.rb.gemspec',
37
38
  'Rakefile',
38
39
  'README.md',
39
40
  ]
@@ -44,7 +45,7 @@ Gem::Specification.new do |spec|
44
45
 
45
46
  spec.metadata = {
46
47
  "bug_tracker_uri" => "https://github.com/thoran/moby/issues",
47
- "changelog_uri" => "https://github.com/thoran/moby/blob/main/CHANGES.txt",
48
+ "changelog_uri" => "https://github.com/thoran/moby/blob/main/CHANGELOG",
48
49
  "source_code_uri" => "https://github.com/thoran/moby",
49
50
  "documentation_uri" => "https://github.com/thoran/moby/blob/main/README.md"
50
51
  }