ruby-gobuster 0.1.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.
@@ -0,0 +1,68 @@
1
+ module Gobuster
2
+ #
3
+ # Represents a HTTP resposne found by `gobuster dir` or `gobuster fuzz`.
4
+ #
5
+ class Response
6
+
7
+ # The path of the response.
8
+ #
9
+ # @return [String, nil]
10
+ attr_reader :path
11
+
12
+ # The URL of the response.
13
+ #
14
+ # @return [String, nil]
15
+ attr_reader :url
16
+
17
+ # The HTTP status code.
18
+ #
19
+ # @return [Integer]
20
+ attr_reader :status
21
+
22
+ # The size of the response.
23
+ #
24
+ # @return [Integer]
25
+ attr_reader :size
26
+
27
+ #
28
+ # Initializes the HTTP response.
29
+ #
30
+ # @param [String, nil] path
31
+ #
32
+ # @param [String, nil] url
33
+ #
34
+ # @param [Integer] status
35
+ #
36
+ # @param [Integer] size
37
+ #
38
+ # @raise [ArgumentError]
39
+ # The `path:` or `url:` keyword argument is required.
40
+ #
41
+ def initialize(path: nil, url: nil, status: , size: )
42
+ if url
43
+ @url = url
44
+ @path = nil
45
+ elsif path
46
+ @url = nil
47
+ @path = path
48
+ else
49
+ raise(ArgumentError,"path: or url: keyword argument must be given")
50
+ end
51
+
52
+ @status = status
53
+ @size = size
54
+ end
55
+
56
+ #
57
+ # Converts the response to a String.
58
+ #
59
+ # @return [String]
60
+ #
61
+ def to_s
62
+ @path || @url
63
+ end
64
+
65
+ alias to_str to_s
66
+
67
+ end
68
+ end
@@ -0,0 +1,33 @@
1
+ module Gobuster
2
+ #
3
+ # Represents an S3 bucket found by `gobuster s3`.
4
+ #
5
+ class S3Bucket
6
+
7
+ # The URL to the S3 bucket.
8
+ #
9
+ # @return [String]
10
+ attr_reader :url
11
+
12
+ #
13
+ # Initializes the S3 bucket.
14
+ #
15
+ # @param [String] url
16
+ #
17
+ def initialize(url)
18
+ @url = url
19
+ end
20
+
21
+ #
22
+ # Converts the S3 bucket to a String.
23
+ #
24
+ # @return [String]
25
+ #
26
+ def to_s
27
+ @url
28
+ end
29
+
30
+ alias to_str to_s
31
+
32
+ end
33
+ end
@@ -0,0 +1,4 @@
1
+ module Gobuster
2
+ # ruby-gobuster version
3
+ VERSION = '0.1.0'
4
+ end
@@ -0,0 +1,61 @@
1
+ # encoding: utf-8
2
+
3
+ require 'yaml'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gemspec = YAML.load_file('gemspec.yml')
7
+
8
+ gem.name = gemspec.fetch('name')
9
+ gem.version = gemspec.fetch('version') do
10
+ lib_dir = File.join(File.dirname(__FILE__),'lib')
11
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
12
+
13
+ require 'gobuster/version'
14
+ Gobuster::VERSION
15
+ end
16
+
17
+ gem.summary = gemspec['summary']
18
+ gem.description = gemspec['description']
19
+ gem.licenses = Array(gemspec['license'])
20
+ gem.authors = Array(gemspec['authors'])
21
+ gem.email = gemspec['email']
22
+ gem.homepage = gemspec['homepage']
23
+ gem.metadata = gemspec['metadata'] if gemspec['metadata']
24
+
25
+ glob = lambda { |patterns| gem.files & Dir[*patterns] }
26
+
27
+ gem.files = `git ls-files`.split($/)
28
+ gem.files = glob[gemspec['files']] if gemspec['files']
29
+
30
+ gem.executables = gemspec.fetch('executables') do
31
+ glob['bin/*'].map { |path| File.basename(path) }
32
+ end
33
+ gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
34
+
35
+ gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
36
+ gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
37
+ gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
38
+
39
+ gem.require_paths = Array(gemspec.fetch('require_paths') {
40
+ %w[ext lib].select { |dir| File.directory?(dir) }
41
+ })
42
+
43
+ gem.requirements = Array(gemspec['requirements'])
44
+ gem.required_ruby_version = gemspec['required_ruby_version']
45
+ gem.required_rubygems_version = gemspec['required_rubygems_version']
46
+ gem.post_install_message = gemspec['post_install_message']
47
+
48
+ split = lambda { |string| string.split(/,\s*/) }
49
+
50
+ if gemspec['dependencies']
51
+ gemspec['dependencies'].each do |name,versions|
52
+ gem.add_dependency(name,split[versions])
53
+ end
54
+ end
55
+
56
+ if gemspec['development_dependencies']
57
+ gemspec['development_dependencies'].each do |name,versions|
58
+ gem.add_development_dependency(name,split[versions])
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+ require 'gobuster/command'
3
+
4
+ describe Gobuster::Command do
5
+ describe described_class::Duration do
6
+ describe "#validate" do
7
+ context "when given nil" do
8
+ let(:value) { nil }
9
+
10
+ it "must return [false, \"cannot be nil\"]" do
11
+ expect(subject.validate(value)).to eq(
12
+ [false, "cannot be nil"]
13
+ )
14
+ end
15
+ end
16
+
17
+ context "when given a String" do
18
+ context "when given an empty String" do
19
+ let(:value) { "" }
20
+
21
+ it "must return [false, \"does not allow an empty value\"]" do
22
+ expect(subject.validate(value)).to eq(
23
+ [false, "does not allow an empty value"]
24
+ )
25
+ end
26
+ end
27
+
28
+ context "when given a number" do
29
+ let(:value) { "10" }
30
+
31
+ it "must return [false, \"must be a number and end with 'm', 's', 'ms', or 'ns'\"]" do
32
+ expect(subject.validate(value)).to eq(
33
+ [false, "must be a number and end with 'm', 's', 'ms', or 'ns'"]
34
+ )
35
+ end
36
+ end
37
+
38
+ context "when given a number that ends with a unit" do
39
+ let(:value) { "10s" }
40
+
41
+ it "must return true" do
42
+ expect(subject.validate(value)).to be(true)
43
+ end
44
+
45
+ context "but the unit isn't recognized" do
46
+ let(:value) { "10x" }
47
+
48
+ it "must return [false, \"must be a number and end with 'm', 's', 'ms', or 'ns'\"]" do
49
+ expect(subject.validate(value)).to eq(
50
+ [false, "must be a number and end with 'm', 's', 'ms', or 'ns'"]
51
+ )
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ /dev (Status: 200) [Size: 175527]
2
+ /test (Status: 200) [Size: 176368]
3
+ /www (Status: 200) [Size: 166374]
@@ -0,0 +1,2 @@
1
+ Found: www.twitter.com
2
+ Found: dev.twitter.com
@@ -0,0 +1,5 @@
1
+ Found: [Status=200] [Length=1256] http://example.com
2
+ Found: [Status=200] [Length=1256] http://example.com
3
+ Found: [Status=200] [Length=1256] http://example.com
4
+ Found: [Status=200] [Length=1256] http://example.com
5
+ Found: [Status=200] [Length=1256] http://example.com
@@ -0,0 +1,5 @@
1
+ http://www.s3.amazonaws.com/
2
+ http://admin.s3.amazonaws.com/
3
+ http://test.s3.amazonaws.com/
4
+ http://downloads.s3.amazonaws.com/
5
+ http://dev.s3.amazonaws.com/
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+ require 'gobuster/hostname'
3
+
4
+ describe Gobuster::Hostname do
5
+ let(:name) { 'www.example.com' }
6
+
7
+ subject { described_class.new(name) }
8
+
9
+ describe "#initialize" do
10
+ it "must set #name" do
11
+ expect(subject.name).to eq(name)
12
+ end
13
+ end
14
+
15
+ describe "#to_s" do
16
+ it "must return #name" do
17
+ expect(subject.to_s).to eq(name)
18
+ end
19
+ end
20
+
21
+ describe "#to_str" do
22
+ it "must return #name" do
23
+ expect(subject.to_str).to eq(name)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,174 @@
1
+ require 'spec_helper'
2
+ require 'gobuster/output_file'
3
+
4
+ describe Gobuster::OutputFile do
5
+ let(:fixtures_dir) { File.expand_path(File.join(__dir__,'fixtures')) }
6
+
7
+ describe "PARSERS" do
8
+ subject { described_class::PARSERS }
9
+
10
+ describe ":dir" do
11
+ it { expect(subject[:dir]).to eq(Gobuster::Parsers::Dir) }
12
+ end
13
+
14
+ describe ":dns" do
15
+ it { expect(subject[:dns]).to eq(Gobuster::Parsers::DNS) }
16
+ end
17
+
18
+ describe ":fuzz" do
19
+ it { expect(subject[:fuzz]).to eq(Gobuster::Parsers::Fuzz) }
20
+ end
21
+
22
+ describe ":s3" do
23
+ it { expect(subject[:s3]).to eq(Gobuster::Parsers::S3) }
24
+ end
25
+ end
26
+
27
+ describe "#initialize" do
28
+ let(:path) { "/path/to/file.txt" }
29
+ let(:format) { :dir }
30
+
31
+ subject { described_class.new(path, format: format) }
32
+
33
+ it "must set #path" do
34
+ expect(subject.path).to eq(path)
35
+ end
36
+
37
+ it "must set #format" do
38
+ expect(subject.format).to be(format)
39
+ end
40
+
41
+ it "must set #parser based on #format" do
42
+ expect(subject.parser).to eq(described_class::PARSERS[subject.format])
43
+ end
44
+ end
45
+
46
+ let(:path) { File.join(fixtures_dir,'dir_output.txt') }
47
+
48
+ subject { described_class.new(path) }
49
+
50
+ describe "#each" do
51
+ context "when initialized with `gobuster dir` output file" do
52
+ let(:path) { File.join(fixtures_dir,'dir_output.txt') }
53
+
54
+ subject { described_class.new(path, format: :dir) }
55
+
56
+ context "and when a block is given" do
57
+ it "must yield each parsed Response object" do
58
+ yielded_responses = []
59
+
60
+ subject.each do |response|
61
+ yielded_responses << response
62
+ end
63
+
64
+ expect(yielded_responses).to_not be_empty
65
+ expect(yielded_responses).to all(be_kind_of(Gobuster::Response))
66
+ end
67
+ end
68
+
69
+ context "and when no block is given" do
70
+ it "must return an Enumerator of the parsed Response objects" do
71
+ responses = subject.each.to_a
72
+
73
+ expect(responses).to_not be_empty
74
+ expect(responses).to all(be_kind_of(Gobuster::Response))
75
+ end
76
+ end
77
+ end
78
+
79
+ context "when initialized with `gobuster dns` output file" do
80
+ let(:path) { File.join(fixtures_dir,'dns_output.txt') }
81
+
82
+ subject { described_class.new(path, format: :dns) }
83
+
84
+ context "and when a block is given" do
85
+ it "must yield each parsed Hostname object" do
86
+ yielded_hostnames = []
87
+
88
+ subject.each do |hostname|
89
+ yielded_hostnames << hostname
90
+ end
91
+
92
+ expect(yielded_hostnames).to_not be_empty
93
+ expect(yielded_hostnames).to all(be_kind_of(Gobuster::Hostname))
94
+ end
95
+ end
96
+
97
+ context "and when no block is given" do
98
+ it "must return an Enumerator of the parsed Hostname objects" do
99
+ hostnames = subject.each.to_a
100
+
101
+ expect(hostnames).to_not be_empty
102
+ expect(hostnames).to all(be_kind_of(Gobuster::Hostname))
103
+ end
104
+ end
105
+ end
106
+
107
+ context "when initialized with `gobuster fuzz` output file" do
108
+ let(:path) { File.join(fixtures_dir,'fuzz_output.txt') }
109
+
110
+ subject { described_class.new(path, format: :fuzz) }
111
+
112
+ context "and when a block is given" do
113
+ it "must yield each parsed Response object" do
114
+ yielded_responses = []
115
+
116
+ subject.each do |response|
117
+ yielded_responses << response
118
+ end
119
+
120
+ expect(yielded_responses).to_not be_empty
121
+ expect(yielded_responses).to all(be_kind_of(Gobuster::Response))
122
+ end
123
+ end
124
+
125
+ context "and when no block is given" do
126
+ it "must return an Enumerator of the parsed Response objects" do
127
+ responses = subject.each.to_a
128
+
129
+ expect(responses).to_not be_empty
130
+ expect(responses).to all(be_kind_of(Gobuster::Response))
131
+ end
132
+ end
133
+ end
134
+
135
+ context "when initialized with `gobuster s3` output file" do
136
+ let(:path) { File.join(fixtures_dir,'s3_output.txt') }
137
+
138
+ subject { described_class.new(path, format: :s3) }
139
+
140
+ context "and when a block is given" do
141
+ it "must yield each parsed S3Bucket object" do
142
+ yielded_s3_buckets = []
143
+
144
+ subject.each do |s3_bucket|
145
+ yielded_s3_buckets << s3_bucket
146
+ end
147
+
148
+ expect(yielded_s3_buckets).to_not be_empty
149
+ expect(yielded_s3_buckets).to all(be_kind_of(Gobuster::S3Bucket))
150
+ end
151
+ end
152
+
153
+ context "and when no block is given" do
154
+ it "must return an Enumerator of the parsed S3Bucket objects" do
155
+ s3_buckets = subject.each.to_a
156
+
157
+ expect(s3_buckets).to_not be_empty
158
+ expect(s3_buckets).to all(be_kind_of(Gobuster::S3Bucket))
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+ describe "#to_s" do
165
+ let(:path) { "/path/to/file.txt" }
166
+ let(:format) { :dir }
167
+
168
+ subject { described_class.new(path, format: format) }
169
+
170
+ it "must return #path" do
171
+ expect(subject.to_s).to eq(path)
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+ require 'gobuster/parsers/dir'
3
+
4
+ describe Gobuster::Parsers::Dir do
5
+ describe ".parse" do
6
+ let(:path) { '/test' }
7
+ let(:status) { 200 }
8
+ let(:size) { 176368 }
9
+
10
+ let(:line) { "#{path} (Status: #{status}) [Size: #{size}]" }
11
+ let(:io) { StringIO.new(line + $/) }
12
+
13
+ it "must parse each line and yield Gobuster::Response objects" do
14
+ yielded_responses = []
15
+
16
+ subject.parse(io) do |response|
17
+ yielded_responses << response
18
+ end
19
+
20
+ expect(yielded_responses.length).to eq(1)
21
+ expect(yielded_responses.first).to be_kind_of(Gobuster::Response)
22
+
23
+ yielded_response = yielded_responses.first
24
+
25
+ expect(yielded_response.path).to eq(path)
26
+ expect(yielded_response.status).to eq(status)
27
+ expect(yielded_response.size).to eq(size)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+ require 'gobuster/parsers/dns'
3
+
4
+ describe Gobuster::Parsers::DNS do
5
+ describe ".parse" do
6
+ let(:name) { "www.twitter.com" }
7
+ let(:line) { "Found: #{name}" }
8
+ let(:io) { StringIO.new(line + $/) }
9
+
10
+ it "must parse each line and yield Gobuster::Hostname objects" do
11
+ yielded_hostnames = []
12
+
13
+ subject.parse(io) do |hostname|
14
+ yielded_hostnames << hostname
15
+ end
16
+
17
+ expect(yielded_hostnames.length).to eq(1)
18
+ expect(yielded_hostnames.first).to be_kind_of(Gobuster::Hostname)
19
+
20
+ yielded_hostname = yielded_hostnames.first
21
+
22
+ expect(yielded_hostname.name).to eq(name)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+ require 'gobuster/parsers/fuzz'
3
+
4
+ describe Gobuster::Parsers::Fuzz do
5
+ describe ".parse" do
6
+ let(:url) { '/test' }
7
+ let(:status) { 200 }
8
+ let(:size) { 176368 }
9
+
10
+ let(:line) { "Found: [Status=#{status}] [Length=#{size}] #{url}" }
11
+ let(:io) { StringIO.new(line + $/) }
12
+
13
+ it "must parse each line and yield Gobuster::Response objects" do
14
+ yielded_responses = []
15
+
16
+ subject.parse(io) do |response|
17
+ yielded_responses << response
18
+ end
19
+
20
+ expect(yielded_responses.length).to eq(1)
21
+ expect(yielded_responses.first).to be_kind_of(Gobuster::Response)
22
+
23
+ yielded_response = yielded_responses.first
24
+
25
+ expect(yielded_response.url).to eq(url)
26
+ expect(yielded_response.path).to be(nil)
27
+ expect(yielded_response.status).to eq(status)
28
+ expect(yielded_response.size).to eq(size)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+ require 'gobuster/parsers/s3'
3
+
4
+ describe Gobuster::Parsers::S3 do
5
+ describe ".parse" do
6
+ let(:url) { "http://test.s3.amazonaws.com/" }
7
+ let(:line) { url }
8
+ let(:io) { StringIO.new(line + $/) }
9
+
10
+ it "must parse each line and yield Gobuster::S3Bucket objects" do
11
+ yielded_s3_buckets = []
12
+
13
+ subject.parse(io) do |s3_bucket|
14
+ yielded_s3_buckets << s3_bucket
15
+ end
16
+
17
+ expect(yielded_s3_buckets.length).to eq(1)
18
+ expect(yielded_s3_buckets.first).to be_kind_of(Gobuster::S3Bucket)
19
+
20
+ yielded_s3_bucket = yielded_s3_buckets.first
21
+
22
+ expect(yielded_s3_bucket.url).to eq(url)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+ require 'gobuster/response'
3
+
4
+ describe Gobuster::Response do
5
+ let(:path) { '/test' }
6
+ let(:url) { "https://example.com#{path}" }
7
+ let(:status) { 200 }
8
+ let(:size) { 176368 }
9
+
10
+ describe "#initialize" do
11
+ context "when initialized with the path: keyword argument" do
12
+ subject { described_class.new(path: path, status: status, size: size) }
13
+
14
+ it "must set #path" do
15
+ expect(subject.path).to eq(path)
16
+ end
17
+
18
+ it "must set #url to nil" do
19
+ expect(subject.url).to be(nil)
20
+ end
21
+
22
+ it "must set #status" do
23
+ expect(subject.status).to eq(status)
24
+ end
25
+
26
+ it "must set #size" do
27
+ expect(subject.size).to eq(size)
28
+ end
29
+ end
30
+
31
+ context "when initialized with the url: keyword argument" do
32
+ subject { described_class.new(url: url, status: status, size: size) }
33
+
34
+ it "must set #url" do
35
+ expect(subject.url).to eq(url)
36
+ end
37
+
38
+ it "must set #path to nil" do
39
+ expect(subject.path).to be(nil)
40
+ end
41
+
42
+ it "must set #status" do
43
+ expect(subject.status).to eq(status)
44
+ end
45
+
46
+ it "must set #size" do
47
+ expect(subject.size).to eq(size)
48
+ end
49
+ end
50
+ end
51
+
52
+ describe "#to_s" do
53
+ context "when initialized with the path: keyword argument" do
54
+ subject { described_class.new(path: path, status: status, size: size) }
55
+
56
+ it "must return #path" do
57
+ expect(subject.to_s).to eq(path)
58
+ end
59
+ end
60
+
61
+ context "when initialized with the url: keyword argument" do
62
+ subject { described_class.new(url: url, status: status, size: size) }
63
+
64
+ it "must return #url" do
65
+ expect(subject.to_s).to eq(url)
66
+ end
67
+ end
68
+ end
69
+
70
+ describe "#to_str" do
71
+ context "when initialized with the path: keyword argument" do
72
+ subject { described_class.new(path: path, status: status, size: size) }
73
+
74
+ it "must return #path" do
75
+ expect(subject.to_s).to eq(path)
76
+ end
77
+ end
78
+
79
+ context "when initialized with the url: keyword argument" do
80
+ subject { described_class.new(url: url, status: status, size: size) }
81
+
82
+ it "must return #url" do
83
+ expect(subject.to_s).to eq(url)
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+ require 'gobuster/s3_bucket'
3
+
4
+ describe Gobuster::S3Bucket do
5
+ let(:url) { 'http://test.s3.amazonaws.com/' }
6
+
7
+ subject { described_class.new(url) }
8
+
9
+ describe "#initialize" do
10
+ it "must set #url" do
11
+ expect(subject.url).to eq(url)
12
+ end
13
+ end
14
+
15
+ describe "#to_s" do
16
+ it "must return #url" do
17
+ expect(subject.to_s).to eq(url)
18
+ end
19
+ end
20
+
21
+ describe "#to_str" do
22
+ it "must return #url" do
23
+ expect(subject.to_str).to eq(url)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ require 'rspec'
2
+ require 'simplecov'
3
+ SimpleCov.start