ronin-web 1.0.1 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +3 -2
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +5 -0
  5. data/ChangeLog.md +46 -1
  6. data/Gemfile +25 -12
  7. data/README.md +486 -39
  8. data/Rakefile +9 -0
  9. data/data/completions/ronin-web +203 -0
  10. data/gemspec.yml +18 -5
  11. data/lib/ronin/web/cli/browser_options.rb +92 -0
  12. data/lib/ronin/web/cli/browser_shell.rb +448 -0
  13. data/lib/ronin/web/cli/command.rb +1 -1
  14. data/lib/ronin/web/cli/commands/browser.rb +373 -0
  15. data/lib/ronin/web/cli/commands/completion.rb +63 -0
  16. data/lib/ronin/web/cli/commands/diff.rb +60 -8
  17. data/lib/ronin/web/cli/commands/html.rb +21 -33
  18. data/lib/ronin/web/cli/commands/irb.rb +1 -1
  19. data/lib/ronin/web/cli/commands/new/{webapp.rb → app.rb} +8 -8
  20. data/lib/ronin/web/cli/commands/new/nokogiri.rb +4 -4
  21. data/lib/ronin/web/cli/commands/new/server.rb +1 -1
  22. data/lib/ronin/web/cli/commands/new/spider.rb +1 -1
  23. data/lib/ronin/web/cli/commands/new.rb +5 -3
  24. data/lib/ronin/web/cli/commands/reverse_proxy.rb +1 -1
  25. data/lib/ronin/web/cli/commands/screenshot.rb +186 -0
  26. data/lib/ronin/web/cli/commands/server.rb +3 -3
  27. data/lib/ronin/web/cli/commands/session_cookie.rb +265 -0
  28. data/lib/ronin/web/cli/commands/spider.rb +60 -466
  29. data/lib/ronin/web/cli/commands/user_agent.rb +177 -0
  30. data/lib/ronin/web/cli/commands/vulns.rb +463 -0
  31. data/lib/ronin/web/cli/commands/wordlist.rb +484 -0
  32. data/lib/ronin/web/cli/commands/xml.rb +149 -0
  33. data/lib/ronin/web/cli/js_shell.rb +69 -0
  34. data/lib/ronin/web/cli/ruby_shell.rb +1 -1
  35. data/lib/ronin/web/cli/spider_options.rb +919 -0
  36. data/lib/ronin/web/cli.rb +3 -1
  37. data/lib/ronin/web/html.rb +1 -1
  38. data/lib/ronin/web/root.rb +1 -1
  39. data/lib/ronin/web/version.rb +2 -2
  40. data/lib/ronin/web/xml.rb +1 -1
  41. data/lib/ronin/web.rb +4 -364
  42. data/man/ronin-web-browser.1 +92 -0
  43. data/man/ronin-web-browser.1.md +96 -0
  44. data/man/ronin-web-completion.1 +76 -0
  45. data/man/ronin-web-completion.1.md +78 -0
  46. data/man/ronin-web-diff.1 +14 -21
  47. data/man/ronin-web-diff.1.md +13 -6
  48. data/man/ronin-web-html.1 +30 -46
  49. data/man/ronin-web-html.1.md +27 -17
  50. data/man/ronin-web-irb.1 +9 -16
  51. data/man/ronin-web-irb.1.md +6 -2
  52. data/man/ronin-web-new-app.1.md +39 -0
  53. data/man/ronin-web-new-nokogiri.1 +9 -20
  54. data/man/ronin-web-new-nokogiri.1.md +5 -5
  55. data/man/ronin-web-new-server.1 +11 -23
  56. data/man/ronin-web-new-server.1.md +5 -5
  57. data/man/ronin-web-new-spider.1 +44 -88
  58. data/man/ronin-web-new-spider.1.md +37 -37
  59. data/man/ronin-web-new.1 +18 -30
  60. data/man/ronin-web-new.1.md +15 -11
  61. data/man/ronin-web-reverse-proxy.1 +33 -38
  62. data/man/ronin-web-reverse-proxy.1.md +20 -14
  63. data/man/ronin-web-screenshot.1 +56 -0
  64. data/man/ronin-web-screenshot.1.md +56 -0
  65. data/man/ronin-web-server.1 +15 -29
  66. data/man/ronin-web-server.1.md +13 -9
  67. data/man/ronin-web-session-cookie.1 +38 -0
  68. data/man/ronin-web-session-cookie.1.md +41 -0
  69. data/man/ronin-web-spider.1 +121 -130
  70. data/man/ronin-web-spider.1.md +115 -66
  71. data/man/ronin-web-user-agent.1 +44 -0
  72. data/man/ronin-web-user-agent.1.md +46 -0
  73. data/man/ronin-web-vulns.1 +175 -0
  74. data/man/ronin-web-vulns.1.md +177 -0
  75. data/man/ronin-web-wordlist.1 +258 -0
  76. data/man/ronin-web-wordlist.1.md +263 -0
  77. data/man/ronin-web-xml.1 +43 -0
  78. data/man/ronin-web-xml.1.md +46 -0
  79. data/man/ronin-web.1 +67 -18
  80. data/man/ronin-web.1.md +55 -4
  81. data/scripts/setup +58 -0
  82. metadata +122 -31
  83. data/lib/ronin/web/mechanize.rb +0 -82
  84. data/man/ronin-web-new-webapp.1.md +0 -39
  85. /data/data/new/{webapp → app}/.gitignore +0 -0
  86. /data/data/new/{webapp → app}/.ruby-version.erb +0 -0
  87. /data/data/new/{webapp → app}/Dockerfile.erb +0 -0
  88. /data/data/new/{webapp → app}/Gemfile +0 -0
  89. /data/data/new/{webapp → app}/app.rb.erb +0 -0
  90. /data/data/new/{webapp → app}/config.ru +0 -0
  91. /data/data/new/{webapp → app}/docker-compose.yml.erb +0 -0
@@ -0,0 +1,373 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-web - A collection of useful web helper methods and commands.
4
+ #
5
+ # Copyright (c) 2006-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-web is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-web is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with ronin-web. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ require 'ronin/web/cli/command'
22
+ require 'ronin/web/cli/browser_options'
23
+ require 'ronin/web/cli/browser_shell'
24
+ require 'ronin/web/cli/js_shell'
25
+
26
+ require 'command_kit/colors'
27
+
28
+ module Ronin
29
+ module Web
30
+ class CLI
31
+ module Commands
32
+ #
33
+ # Screenshots one or more URLs.
34
+ #
35
+ # ## Usage
36
+ #
37
+ # ronin-web browser [options] [URL]
38
+ #
39
+ # ## Options
40
+ #
41
+ # -B, --browser NAME|PATH The browser name or path to execute
42
+ # -W, --width WIDTH Sets the width of the browser viewport (Default: 1024)
43
+ # -H, --height HEIGHT Sets the height of the browser viewport (Default: 768)
44
+ # --headless Run the browser in headless mode
45
+ # --visible Open a visible browser
46
+ # -x, --x INT Sets the position of the browser X coordinate
47
+ # -y, --y INT Sets the position of the browser Y coordinate
48
+ # --inject-js JS Injects JavaScript into every page
49
+ # --inject-js-file FILE Injects a JavaScript file into every page
50
+ # --bypass-csp Enables bypassing CSP
51
+ # --print-urls Print all requested URLs
52
+ # --print-status Print the status of all requested URLs
53
+ # --print-requests Print all requests sent by the browser
54
+ # --print-responses Print responses to all requests
55
+ # --print-traffic Print requests and responses
56
+ # --print-headers Print headers of requests/responses
57
+ # --print-body Print request/response bodies
58
+ # --shell Starts an interactive shell
59
+ # --js-shell Starts an interactive JavaScript shell
60
+ # -h, --help Print help information
61
+ #
62
+ # ## Arguments
63
+ #
64
+ # [URL] The initial URL to visit
65
+ #
66
+ # @since 2.0.0
67
+ #
68
+ class Browser < Command
69
+
70
+ include BrowserOptions
71
+ include CommandKit::Colors
72
+
73
+ usage '[options] [URL]'
74
+
75
+ option :headless, desc: 'Run the browser in headless mode' do
76
+ @mode = :headless
77
+ end
78
+
79
+ option :visible, desc: 'Open a visible browser' do
80
+ @mode = :visible
81
+ end
82
+
83
+ option :x, short: '-x',
84
+ value: {
85
+ type: Integer
86
+ },
87
+ desc: "Sets the position of the browser X coordinate"
88
+
89
+ option :y, short: '-y',
90
+ value: {
91
+ type: Integer
92
+ },
93
+ desc: "Sets the position of the browser Y coordinate"
94
+
95
+ option :inject_js, value: {
96
+ type: String,
97
+ usage: 'JS'
98
+ },
99
+ desc: 'Injects JavaScript into every page'
100
+
101
+ option :inject_js_file, value: {
102
+ type: String,
103
+ usage: 'FILE'
104
+ },
105
+ desc: 'Injects a JavaScript file into every page'
106
+
107
+ option :bypass_csp, desc: 'Enables bypassing CSP'
108
+
109
+ option :print_urls, desc: 'Print all requested URLs'
110
+
111
+ option :print_status, desc: 'Print the status of all requested URLs'
112
+
113
+ option :print_requests, desc: 'Print all requests sent by the browser'
114
+
115
+ option :print_responses, desc: 'Print responses to all requests'
116
+
117
+ option :print_traffic, desc: 'Print requests and responses'
118
+
119
+ option :print_headers, desc: 'Print headers of requests/responses'
120
+
121
+ option :print_cookies, desc: 'Print Set-Cookie headers from all responses'
122
+
123
+ option :print_body, desc: 'Print request/response bodies'
124
+
125
+ option :shell, desc: 'Starts an interactive shell'
126
+
127
+ option :js_shell, desc: 'Starts an interactive JavaScript shell'
128
+
129
+ argument :url, required: false,
130
+ desc: 'The initial URL to visit'
131
+
132
+ description "Automates a web browser"
133
+
134
+ man_page 'ronin-web-browser.1'
135
+
136
+ #
137
+ # Initializes the `ronin-web browser` command.
138
+ #
139
+ # @param [Hash{Symbol => Object}] kwargs
140
+ # Additional keywords for the command.
141
+ #
142
+ def initialize(**kwargs)
143
+ super(**kwargs)
144
+
145
+ @mode = if stdout.tty? then :visible
146
+ else :headless
147
+ end
148
+ end
149
+
150
+ #
151
+ # Runs the `ronin-web browser` command.
152
+ #
153
+ # @param [String, nil] url
154
+ # The optional URL to visit.
155
+ #
156
+ def run(url=nil)
157
+ unless (url || options[:shell] || options[:js_shell])
158
+ print_error "must specify a URL or --shell / --js-shell"
159
+ exit(-1)
160
+ end
161
+
162
+ configure_browser
163
+ open_browser(url)
164
+
165
+ if options[:shell] || options[:js_shell]
166
+ start_shell
167
+ else
168
+ wait_until_closed
169
+ end
170
+
171
+ close_browser
172
+ end
173
+
174
+ #
175
+ # Configures the browser and registers callbacks.
176
+ #
177
+ def configure_browser
178
+ if options[:x] || options[:y]
179
+ browser.position = {
180
+ left: options.fetch(:x,0),
181
+ top: options.fetch(:y,0)
182
+ }
183
+ end
184
+
185
+ browser.bypass_csp = true if options[:bypass_csp]
186
+
187
+ if options[:inject_js_file]
188
+ browser.inject_js(File.read(options[:inject_js_file]))
189
+ elsif options[:inject_js]
190
+ browser.inject_js(options[:inject_js])
191
+ end
192
+
193
+ if options[:print_status]
194
+ browser.every_response(&method(:print_url_status))
195
+ elsif options[:print_cookies]
196
+ browser.every_response(&method(:print_cookies))
197
+ elsif options[:print_urls]
198
+ browser.every_url(&method(:puts))
199
+ elsif options[:print_traffic]
200
+ browser.every_request(&method(:print_request))
201
+ browser.every_response(&method(:print_response))
202
+ else
203
+ browser.every_request(&method(:print_request)) if options[:print_requests]
204
+ browser.every_response(&method(:print_response)) if options[:print_responses]
205
+ end
206
+ end
207
+
208
+ #
209
+ # Open the browser window.
210
+ #
211
+ # @param [String, nil] url
212
+ # The optional URL to visit.
213
+ #
214
+ def open_browser(url=nil)
215
+ browser.goto(url) if url
216
+ end
217
+
218
+ #
219
+ # Starts an interactive browser shell.
220
+ #
221
+ def start_shell
222
+ # start the shell then immediately quit the browser once exited
223
+ if options[:js_shell]
224
+ JSShell.start(browser)
225
+ elsif options[:shell]
226
+ BrowserShell.start(browser)
227
+ end
228
+ end
229
+
230
+ #
231
+ # Waits until the browser is done or if the user exits the command.
232
+ #
233
+ def wait_until_closed
234
+ if @mode == :visible
235
+ # wait for the browser window to be closed
236
+ browser.wait_until_closed
237
+ else
238
+ # wait until there's no network traffic
239
+ browser.network.wait_for_idle { browser.quit }
240
+ end
241
+ end
242
+
243
+ #
244
+ # Close the browser.
245
+ #
246
+ def close_browser
247
+ browser.quit
248
+ end
249
+
250
+ #
251
+ # Additional keyword arguments for `Ronin::Web::Browser.new`.
252
+ #
253
+ # @return [Hash{Symbol => Object}]
254
+ #
255
+ def browser_kwargs
256
+ kwargs = super()
257
+
258
+ case @mode
259
+ when :headless then kwargs[:headless] = true
260
+ when :visible then kwargs[:visible] = true
261
+ end
262
+
263
+ return kwargs
264
+ end
265
+
266
+ #
267
+ # Prints the status and URL of a response.
268
+ #
269
+ # @param [Ferrum::Network::Response] response
270
+ # The respones object.
271
+ #
272
+ def print_url_status(response)
273
+ if response.status < 300
274
+ puts "#{colors.bright_green(response.status)} #{colors.green(response.url)}"
275
+ elsif response.status < 400
276
+ puts "#{colors.bright_yellow(response.status)} #{colors.yellow(response.url)}"
277
+ elsif response.status < 500
278
+ puts "#{colors.bright_red(response.status)} #{colors.red(response.url)}"
279
+ else
280
+ puts "#{colors.bold(colors.bright_red(response.status))} #{colors.bold(colors.red(response.url))}"
281
+ end
282
+ end
283
+
284
+ #
285
+ # Prints a request from the browser.
286
+ #
287
+ # @param [Ferrum::Network::InterceptedRequest] request
288
+ #
289
+ def print_request(request)
290
+ sigil = colors.bold(colors.bright_white('>'))
291
+
292
+ puts "#{sigil} #{colors.bold(colors.bright_cyan(request.method))} #{colors.cyan(request.url)}"
293
+
294
+ if options[:print_headers]
295
+ print_headers(sigil,request.headers)
296
+ end
297
+
298
+ if options[:print_body] && (body = request.body)
299
+ print_body(sigil,body)
300
+ end
301
+ end
302
+
303
+ #
304
+ # Prints a response.
305
+ #
306
+ # @param [Ferrum::Network::Response] response
307
+ # The respones object.
308
+ #
309
+ def print_response(response)
310
+ sigil = colors.bold(colors.bright_white('<'))
311
+
312
+ print "#{sigil} "
313
+ print_url_status(response)
314
+
315
+ if options[:print_headers]
316
+ print_headers(sigil,response.headers)
317
+ end
318
+
319
+ if options[:print_body]
320
+ print_body(sigil,response.body)
321
+ end
322
+ end
323
+
324
+ #
325
+ # Prints headers.
326
+ #
327
+ # @param [String] sigil
328
+ # The "sigil" representing either a request (`>`) or
329
+ # a response (`<`).
330
+ #
331
+ # @param [Hash{String => String}] headers
332
+ # The header names and values.
333
+ #
334
+ def print_headers(sigil,headers)
335
+ headers.each do |name,value|
336
+ puts "#{sigil} #{colors.bright_white(name)}: #{value}"
337
+ end
338
+ end
339
+
340
+ #
341
+ # Prints the request or response body.
342
+ #
343
+ # @param [String] sigil
344
+ # The "sigil" representing either a request (`>`) or
345
+ # a response (`<`).
346
+ #
347
+ # @param [String] body
348
+ # the request or response body.
349
+ #
350
+ def print_body(sigil,body)
351
+ puts sigil
352
+ response.body.each_line do |line|
353
+ puts "#{sigil} #{line}"
354
+ end
355
+ end
356
+
357
+ #
358
+ # Prints the `Set-Cookie` header for each HTTP response.
359
+ #
360
+ # @param [Ferrum::Network::Response] response
361
+ # A response from the browser.
362
+ #
363
+ def print_cookies(response)
364
+ if (set_cookie = respones.headers['set-cookie'])
365
+ puts set_cookie
366
+ end
367
+ end
368
+
369
+ end
370
+ end
371
+ end
372
+ end
373
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-web - A collection of useful web helper methods and commands.
4
+ #
5
+ # Copyright (c) 2006-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-web is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-web is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with ronin-web. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ require 'ronin/web/root'
22
+ require 'ronin/core/cli/completion_command'
23
+
24
+ module Ronin
25
+ module Web
26
+ class CLI
27
+ module Commands
28
+ #
29
+ # Manages the shell completion rules for `ronin-web`.
30
+ #
31
+ # ## Usage
32
+ #
33
+ # ronin-web completion [options]
34
+ #
35
+ # ## Options
36
+ #
37
+ # --print Prints the shell completion file
38
+ # --install Installs the shell completion file
39
+ # --uninstall Uninstalls the shell completion file
40
+ # -h, --help Print help information
41
+ #
42
+ # ## Examples
43
+ #
44
+ # ronin-web completion --print
45
+ # ronin-web completion --install
46
+ # ronin-web completion --uninstall
47
+ #
48
+ # @since 2.0.0
49
+ #
50
+ class Completion < Core::CLI::CompletionCommand
51
+
52
+ completion_file File.join(ROOT,'data','completions','ronin-web')
53
+
54
+ man_dir File.join(ROOT,'man')
55
+ man_page 'ronin-web-completion.1'
56
+
57
+ description 'Manages the shell completion rules for ronin-web'
58
+
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # ronin-web - A collection of useful web helper methods and commands.
4
4
  #
5
- # Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
+ # Copyright (c) 2006-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
6
6
  #
7
7
  # ronin-web is free software: you can redistribute it and/or modify
8
8
  # it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@
21
21
  require 'ronin/web/cli/command'
22
22
  require 'ronin/support/network/http'
23
23
 
24
- require 'command_kit/terminal'
24
+ require 'command_kit/colors'
25
25
  require 'nokogiri/diff'
26
26
 
27
27
  module Ronin
@@ -43,10 +43,11 @@ module Ronin
43
43
  # ## Options
44
44
  #
45
45
  # -h, --help Print help information
46
+ # -f, --format Pass the format of the URL or files. Supported formats are html and xml. (Default: html)
46
47
  #
47
48
  class Diff < Command
48
49
 
49
- include CommandKit::Terminal
50
+ include CommandKit::Colors
50
51
 
51
52
  usage '[options] {URL | FILE} {URL | FILE}'
52
53
 
@@ -58,7 +59,14 @@ module Ronin
58
59
  usage: 'URL | FILE',
59
60
  desc: 'The modified URL or file'
60
61
 
61
- description 'Diffs two web pges'
62
+ option :format, short: '-f',
63
+ value: {
64
+ type: [:html, :xml],
65
+ default: :html
66
+ },
67
+ desc: 'The format of the web pages'
68
+
69
+ description 'Diffs two web pages'
62
70
 
63
71
  man_page 'ronin-web-diff.1'
64
72
 
@@ -72,16 +80,41 @@ module Ronin
72
80
  # The URL or file path of the modified page.
73
81
  #
74
82
  def run(page1,page2)
75
- doc1 = Nokogiri::HTML(read(page1))
76
- doc2 = Nokogiri::HTML(read(page2))
83
+ doc1 = parse_doc(page1)
84
+ doc2 = parse_doc(page2)
77
85
 
78
86
  doc1.diff(doc2) do |change,node|
79
- unless change == ' '
80
- puts "#{change} #{node}"
87
+ unless change == ' ' # ignroe unchanged nodes
88
+ print_change(change,node)
81
89
  end
82
90
  end
83
91
  end
84
92
 
93
+ #
94
+ # Prints a change to the document.
95
+ #
96
+ # @param ["+", "-"] change
97
+ # The type of change.
98
+ #
99
+ # * `+` - indicates an added node.
100
+ # * `-` - indicates a removed node.
101
+ #
102
+ # @param [Nokogiri::HTML::Node, Nokogiri::HTML::Node] node
103
+ # The node that was changed.
104
+ #
105
+ def print_change(change,node)
106
+ color = case change
107
+ when '+' then colors.method(:green)
108
+ when '-' then colors.method(:red)
109
+ end
110
+
111
+ content = node.to_s
112
+
113
+ content.each_line(chomp: true) do |line|
114
+ puts color.call("#{change} #{line}")
115
+ end
116
+ end
117
+
85
118
  #
86
119
  # Reads a web page.
87
120
  #
@@ -100,6 +133,25 @@ module Ronin
100
133
  end
101
134
  end
102
135
 
136
+ #
137
+ # Loads the given html or xml sources
138
+ #
139
+ # @param [String] page
140
+ # The URL or file path of the original page.
141
+ #
142
+ # @return [Nokogiri::HTML::Document, Nokogiri::XML::Document]
143
+ # html or xml document depends upon --format option
144
+ #
145
+ def parse_doc(page)
146
+ case options[:format]
147
+ when :html
148
+ Nokogiri::HTML(read(page))
149
+ when :xml
150
+ Nokogiri::XML(read(page))
151
+ else
152
+ raise(NotImplementedError,"unsupported format: #{options[:format].inspect}")
153
+ end
154
+ end
103
155
  end
104
156
  end
105
157
  end
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # ronin-web - A collection of useful web helper methods and commands.
4
4
  #
5
- # Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
+ # Copyright (c) 2006-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
6
6
  #
7
7
  # ronin-web is free software: you can redistribute it and/or modify
8
8
  # it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
18
18
  # along with ronin-web. If not, see <https://www.gnu.org/licenses/>.
19
19
  #
20
20
 
21
- require 'ronin/web/cli/command'
21
+ require 'ronin/web/cli/commands/xml'
22
22
  require 'ronin/support/network/http'
23
23
 
24
24
  require 'nokogiri'
@@ -38,6 +38,7 @@ module Ronin
38
38
  #
39
39
  # -X, --xpath XPATH XPath query
40
40
  # -C, --css-path CSSPath CSS-path query
41
+ # -t, --text Prints the inner-text
41
42
  # -M, --meta-tags Searches for all <meta ...> tags
42
43
  # -l, --links Searches for all <a href="..."> URLs
43
44
  # -S, --style Dumps all <style> tags
@@ -54,18 +55,15 @@ module Ronin
54
55
  # URL | FILE The URL or FILE to search
55
56
  # [XPATH | CSS-path] The XPath or CSS-path query
56
57
  #
57
- class Html < Command
58
+ class Html < Xml
58
59
 
59
60
  usage '[options] {URL | FILE} [XPATH | CSS-path]'
60
61
 
61
- option :xpath, short: '-X',
62
- value: {type: String, usage: 'XPATH'},
63
- desc: 'XPath query' do |xpath|
64
- @query = xpath
65
- end
66
-
67
62
  option :css_path, short: '-C',
68
- value: {type: String, usage: 'CSSPath'},
63
+ value: {
64
+ type: String,
65
+ usage: 'CSSPath'
66
+ },
69
67
  desc: 'CSS-path query' do |css_path|
70
68
  @query = css_path
71
69
  end
@@ -110,9 +108,6 @@ module Ronin
110
108
  @query = '//a/@href | //link/@href | //script/@src | //form/@action'
111
109
  end
112
110
 
113
- option :first, short: '-F',
114
- desc: 'Only print the first match'
115
-
116
111
  argument :source, required: true,
117
112
  usage: 'URL | FILE',
118
113
  desc: 'The URL or FILE to search'
@@ -125,6 +120,11 @@ module Ronin
125
120
 
126
121
  man_page 'ronin-web-html.1'
127
122
 
123
+ # The XPath or CSS-path query.
124
+ #
125
+ # @return [String, nil]
126
+ attr_reader :query
127
+
128
128
  #
129
129
  # Runs the `ronin-web xpath` command.
130
130
  #
@@ -140,32 +140,20 @@ module Ronin
140
140
  exit(-1)
141
141
  end
142
142
 
143
- doc = Nokogiri::HTML(read(source))
144
- nodes = if options[:first] then [doc.at(query)]
145
- else doc.search(query)
146
- end
147
-
148
- nodes.each do |node|
149
- puts node
150
- end
143
+ super(source,query)
151
144
  end
152
145
 
153
146
  #
154
- # Reads a URI or file.
147
+ # Parses the HTML source code.
155
148
  #
156
- # @param [String] source
157
- # The URI or file path.
149
+ # @param [String] html
150
+ # The raw unparsed HTML.
158
151
  #
159
- # @return [File, String]
160
- # The contents of the URI or file.
152
+ # @return [Nokogiri::HTML::Document]
153
+ # The parsed HTML document.
161
154
  #
162
- def read(source)
163
- if source.start_with?('https://') ||
164
- source.start_with?('http://')
165
- Support::Network::HTTP.get_body(source)
166
- else
167
- File.new(source)
168
- end
155
+ def parse(html)
156
+ Nokogiri::HTML(html)
169
157
  end
170
158
 
171
159
  end
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # ronin-web - A collection of useful web helper methods and commands.
4
4
  #
5
- # Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
+ # Copyright (c) 2006-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
6
6
  #
7
7
  # ronin-web is free software: you can redistribute it and/or modify
8
8
  # it under the terms of the GNU General Public License as published by