ruby-feroxbuster 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+ require 'feroxbuster/parsers/json'
3
+
4
+ describe Feroxbuster::Parsers::JSON do
5
+ describe ".parse" do
6
+ let(:line) { json }
7
+ let(:io) { StringIO.new(line + $/) }
8
+
9
+ let(:parsed_json) { JSON.parse(json) }
10
+
11
+ context "when the JSON \"type\" attribute is \"response\"" do
12
+ let(:json) do
13
+ "{\"type\":\"response\",\"url\":\"https://github.com/test\",\"original_url\":\"https://github.com\",\"path\":\"/test\",\"wildcard\":false,\"status\":200,\"method\":\"GET\",\"content_length\":0,\"line_count\":2010,\"word_count\":11253,\"headers\":{\"permissions-policy\":\"interest-cohort=()\",\"accept-ranges\":\"bytes\",\"referrer-policy\":\"origin-when-cross-origin, strict-origin-when-cross-origin\",\"x-content-type-options\":\"nosniff\",\"cache-control\":\"max-age=0, private, must-revalidate\",\"expect-ct\":\"max-age=2592000, report-uri=\\\"https://api.github.com/_private/browser/errors\\\"\",\"server\":\"GitHub.com\",\"x-github-request-id\":\"85A8:0E10:20B03E:27719A:6260B1D5\",\"transfer-encoding\":\"chunked\",\"date\":\"Thu, 21 Apr 2022 01:22:16 GMT\",\"strict-transport-security\":\"max-age=31536000; includeSubdomains; preload\",\"etag\":\"W/\\\"7c98cb0440eb94eddcfd360497fae419\\\"\",\"x-frame-options\":\"deny\",\"content-security-policy\":\"default-src 'none'; base-uri 'self'; block-all-mixed-content; child-src github.com/assets-cdn/worker/ gist.github.com/assets-cdn/worker/; connect-src 'self' uploads.github.com objects-origin.githubusercontent.com www.githubstatus.com collector.github.com raw.githubusercontent.com api.github.com github-cloud.s3.amazonaws.com github-production-repository-file-5c1aeb.s3.amazonaws.com github-production-upload-manifest-file-7fdce7.s3.amazonaws.com github-production-user-asset-6210df.s3.amazonaws.com cdn.optimizely.com logx.optimizely.com/v1/events translator.github.com *.actions.githubusercontent.com wss://*.actions.githubusercontent.com online.visualstudio.com/api/v1/locations github-production-repository-image-32fea6.s3.amazonaws.com github-production-release-asset-2e65be.s3.amazonaws.com insights.github.com wss://alive.github.com; font-src github.githubassets.com; form-action 'self' github.com gist.github.com objects-origin.githubusercontent.com; frame-ancestors 'none'; frame-src render.githubusercontent.com viewscreen.githubusercontent.com notebooks.githubusercontent.com; img-src 'self' data: github.githubassets.com identicons.github.com github-cloud.s3.amazonaws.com secured-user-images.githubusercontent.com/ *.githubusercontent.com; manifest-src 'self'; media-src github.com user-images.githubusercontent.com/; script-src github.githubassets.com; style-src 'unsafe-inline' github.githubassets.com; worker-src github.com/assets-cdn/worker/ gist.github.com/assets-cdn/worker/\",\"x-xss-protection\":\"0\",\"set-cookie\":\"logged_in=no; Path=/; Domain=github.com; Expires=Fri, 21 Apr 2023 01:22:29 GMT; HttpOnly; Secure; SameSite=Lax\",\"vary\":\"X-Requested-With, X-PJAX-Container, Accept-Encoding, Accept, X-Requested-With\",\"content-type\":\"text/html; charset=utf-8\"},\"extension\":\"\"}"
14
+ end
15
+
16
+ it "must parse each line and yield Feroxbuster::Response objects" do
17
+ yielded_objects = []
18
+
19
+ subject.parse(io) do |response|
20
+ yielded_objects << response
21
+ end
22
+
23
+ expect(yielded_objects.length).to eq(1)
24
+ expect(yielded_objects.first).to be_kind_of(Feroxbuster::Response)
25
+
26
+ yielded_response = yielded_objects.first
27
+ expect(yielded_response.url).to eq(parsed_json['url'])
28
+ expect(yielded_response.original_url).to eq(parsed_json['original_url'])
29
+ expect(yielded_response.path).to eq(parsed_json['path'])
30
+ expect(yielded_response.wildcard).to eq(parsed_json['wildcard'])
31
+ expect(yielded_response.status).to eq(parsed_json['status'])
32
+ expect(yielded_response.method).to eq(parsed_json['method'])
33
+ expect(yielded_response.content_length).to eq(parsed_json['content_length'])
34
+ expect(yielded_response.line_count).to eq(parsed_json['line_count'])
35
+ expect(yielded_response.word_count).to eq(parsed_json['word_count'])
36
+ expect(yielded_response.headers).to eq(parsed_json['headers'])
37
+ expect(yielded_response.extension).to eq(parsed_json['extension'])
38
+ end
39
+ end
40
+
41
+ context "when the JSON \"type\" attribute is \"statistics\"" do
42
+ let(:json) do
43
+ "{\"type\":\"statistics\",\"timeouts\":0,\"requests\":18,\"expected_per_scan\":6,\"total_expected\":12,\"errors\":0,\"successes\":12,\"redirects\":0,\"client_errors\":6,\"server_errors\":0,\"total_scans\":2,\"initial_targets\":0,\"links_extracted\":0,\"extensions_collected\":0,\"status_200s\":12,\"status_301s\":0,\"status_302s\":0,\"status_401s\":0,\"status_403s\":0,\"status_429s\":0,\"status_500s\":0,\"status_503s\":0,\"status_504s\":0,\"status_508s\":0,\"wildcards_filtered\":0,\"responses_filtered\":0,\"resources_discovered\":4,\"url_format_errors\":0,\"redirection_errors\":0,\"connection_errors\":0,\"request_errors\":0,\"directory_scan_times\":[0.434531853,0.434228035],\"total_runtime\":[1.6527268240000001]}"
44
+ end
45
+
46
+ it "must parse each line and yield Feroxbuster::Statistics objects" do
47
+ yielded_objects = []
48
+
49
+ subject.parse(io) do |statistics|
50
+ yielded_objects << statistics
51
+ end
52
+
53
+ expect(yielded_objects.length).to eq(1)
54
+ expect(yielded_objects.first).to be_kind_of(Feroxbuster::Statistics)
55
+
56
+ yielded_statistics = yielded_objects.first
57
+ expect(yielded_statistics.timeouts).to eq(parsed_json['timeouts'])
58
+ expect(yielded_statistics.requests).to eq(parsed_json['requests'])
59
+ expect(yielded_statistics.expected_per_scan).to eq(parsed_json['expected_per_scan'])
60
+ expect(yielded_statistics.total_expected).to eq(parsed_json['total_expected'])
61
+ expect(yielded_statistics.errors).to eq(parsed_json['errors'])
62
+ expect(yielded_statistics.successes).to eq(parsed_json['successes'])
63
+ expect(yielded_statistics.redirects).to eq(parsed_json['redirects'])
64
+ expect(yielded_statistics.client_errors).to eq(parsed_json['client_errors'])
65
+ expect(yielded_statistics.server_errors).to eq(parsed_json['server_errors'])
66
+ expect(yielded_statistics.total_scans).to eq(parsed_json['total_scans'])
67
+ expect(yielded_statistics.initial_targets).to eq(parsed_json['initial_targets'])
68
+ expect(yielded_statistics.links_extracted).to eq(parsed_json['links_extracted'])
69
+ expect(yielded_statistics.extensions_collected).to eq(parsed_json['extensions_collected'])
70
+ expect(yielded_statistics.status_200s).to eq(parsed_json['status_200s'])
71
+ expect(yielded_statistics.status_301s).to eq(parsed_json['status_301s'])
72
+ expect(yielded_statistics.status_302s).to eq(parsed_json['status_302s'])
73
+ expect(yielded_statistics.status_401s).to eq(parsed_json['status_401s'])
74
+ expect(yielded_statistics.status_403s).to eq(parsed_json['status_403s'])
75
+ expect(yielded_statistics.status_429s).to eq(parsed_json['status_429s'])
76
+ expect(yielded_statistics.status_500s).to eq(parsed_json['status_500s'])
77
+ expect(yielded_statistics.status_503s).to eq(parsed_json['status_503s'])
78
+ expect(yielded_statistics.status_504s).to eq(parsed_json['status_504s'])
79
+ expect(yielded_statistics.status_508s).to eq(parsed_json['status_508s'])
80
+ expect(yielded_statistics.wildcards_filtered).to eq(parsed_json['wildcards_filtered'])
81
+ expect(yielded_statistics.responses_filtered).to eq(parsed_json['responses_filtered'])
82
+ expect(yielded_statistics.resources_discovered).to eq(parsed_json['resources_discovered'])
83
+ expect(yielded_statistics.url_format_errors).to eq(parsed_json['url_format_errors'])
84
+ expect(yielded_statistics.redirection_errors).to eq(parsed_json['redirection_errors'])
85
+ expect(yielded_statistics.connection_errors).to eq(parsed_json['connection_errors'])
86
+ expect(yielded_statistics.request_errors).to eq(parsed_json['request_errors'])
87
+ expect(yielded_statistics.directory_scan_times).to eq(parsed_json['directory_scan_times'])
88
+ expect(yielded_statistics.total_runtime).to eq(parsed_json['total_runtime'])
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+ require 'feroxbuster/parsers/txt'
3
+
4
+ describe Feroxbuster::Parsers::TXT do
5
+ describe ".parse" do
6
+ let(:status) { 200 }
7
+ let(:method) { "GET" }
8
+ let(:url) { "https://github.com/test" }
9
+
10
+ let(:line_count) { 2010 }
11
+ let(:word_count) { 11253 }
12
+ let(:content_length) { 0 }
13
+
14
+ let(:line) do
15
+ "#{status} #{method} #{line_count}l #{word_count}w #{content_length}c #{url}"
16
+ end
17
+ let(:io) { StringIO.new(line + $/) }
18
+
19
+ it "must parse each line and yield Feroxbuster::Response objects" do
20
+ yielded_responses = []
21
+
22
+ subject.parse(io) do |response|
23
+ yielded_responses << response
24
+ end
25
+
26
+ expect(yielded_responses.length).to eq(1)
27
+ expect(yielded_responses.first).to be_kind_of(Feroxbuster::Response)
28
+
29
+ yielded_response = yielded_responses.first
30
+ expect(yielded_response.status).to eq(status)
31
+ expect(yielded_response.method).to eq(method)
32
+ expect(yielded_response.url).to eq(url)
33
+ expect(yielded_response.line_count).to eq(line_count)
34
+ expect(yielded_response.word_count).to eq(word_count)
35
+ expect(yielded_response.content_length).to eq(content_length)
36
+ end
37
+
38
+ context "when there is other output mixed in" do
39
+ let(:lines) do
40
+ [
41
+ "",
42
+ " ___ ___ __ __ __ __ __ ___",
43
+ "|__ |__ |__) |__) | / ` / \ \_/ | | \ |__",
44
+ "| |___ | \ | \ | \__, \__/ / \ | |__/ |___",
45
+ "by Ben \"epi\" Risher πŸ€“ ver: 2.7.0",
46
+ "───────────────────────────┬──────────────────────",
47
+ " 🎯 Target Url β”‚ https://github.com",
48
+ " πŸš€ Threads β”‚ 50",
49
+ " πŸ“– Wordlist β”‚ ./feroxbuster/wordlist.txt",
50
+ " πŸ‘Œ Status Codes β”‚ [200, 204, 301, 302, 307, 308, 401, 403, 405, 500]",
51
+ " πŸ’₯ Timeout (secs) β”‚ 7",
52
+ " 🦑 User-Agent β”‚ feroxbuster/2.7.0",
53
+ " πŸ’‰ Config File β”‚ /home/postmodern/.config/feroxbuster/ferox-config.toml",
54
+ " 🏁 HTTP methods β”‚ [GET]",
55
+ " πŸ”ƒ Recursion Depth β”‚ 4",
56
+ "───────────────────────────┴──────────────────────",
57
+ " 🏁 Press [ENTER] to use the Scan Management Menuβ„’",
58
+ "──────────────────────────────────────────────────",
59
+ line,
60
+ "[####################] - 1s 12/12 0s found:3 errors:0 ",
61
+ "[####################] - 0s 6/6 4/s https://github.com ",
62
+ "[####################] - 0s 6/6 9/s https://github.com/ ",
63
+ ''
64
+ ]
65
+ end
66
+ let(:io) { StringIO.new(lines.join($/)) }
67
+
68
+ it "must ignore the other output lines" do
69
+ yielded_responses = []
70
+
71
+ subject.parse(io) do |response|
72
+ yielded_responses << response
73
+ end
74
+
75
+ expect(yielded_responses.length).to eq(1)
76
+ expect(yielded_responses.first).to be_kind_of(Feroxbuster::Response)
77
+
78
+ yielded_response = yielded_responses.first
79
+ expect(yielded_response.status).to eq(status)
80
+ expect(yielded_response.method).to eq(method)
81
+ expect(yielded_response.url).to eq(url)
82
+ expect(yielded_response.line_count).to eq(line_count)
83
+ expect(yielded_response.word_count).to eq(word_count)
84
+ expect(yielded_response.content_length).to eq(content_length)
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,3 @@
1
+ require 'rspec'
2
+ require 'simplecov'
3
+ SimpleCov.start
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-feroxbuster
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Postmodern
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-04-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: command_mapper
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.2'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.2.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.2'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.2.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: bundler
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '2.0'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '2.0'
47
+ description: A Ruby interface to feroxbuster, a simple, fast, recursive content discovery
48
+ tool written in Rust.
49
+ email: postmodern.mod3@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files:
53
+ - ChangeLog.md
54
+ - LICENSE.txt
55
+ - README.md
56
+ files:
57
+ - ".document"
58
+ - ".github/workflows/ruby.yml"
59
+ - ".gitignore"
60
+ - ".rspec"
61
+ - ".yardopts"
62
+ - ChangeLog.md
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - gemspec.yml
68
+ - lib/feroxbuster/command.rb
69
+ - lib/feroxbuster/output_file.rb
70
+ - lib/feroxbuster/parsers/json.rb
71
+ - lib/feroxbuster/parsers/txt.rb
72
+ - lib/feroxbuster/response.rb
73
+ - lib/feroxbuster/statistics.rb
74
+ - lib/feroxbuster/version.rb
75
+ - ruby-feroxbuster.gemspec
76
+ - spec/command_spec.rb
77
+ - spec/fixtures/output.json
78
+ - spec/fixtures/output.txt
79
+ - spec/output_file_spec.rb
80
+ - spec/parsers/json_spec.rb
81
+ - spec/parsers/txt_spec.rb
82
+ - spec/spec_helper.rb
83
+ homepage: https://github.com/postmodern/ruby-feroxbuster#readme
84
+ licenses:
85
+ - MIT
86
+ metadata:
87
+ documentation_uri: https://rubydoc.info/gems/ruby-feroxbuster
88
+ source_code_uri: https://github.com/postmodern/ruby-feroxbuster
89
+ bug_tracker_uri: https://github.com/postmodern/ruby-feroxbuster/issues
90
+ changelog_uri: https://github.com/postmodern/ruby-feroxbuster/blob/master/ChangeLog.md
91
+ rubygems_mfa_required: 'true'
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: 2.0.0
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements:
107
+ - feroxbuster >= 2.7.0
108
+ rubygems_version: 3.2.22
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: A Ruby interface to feroxbuster.
112
+ test_files: []