ruby-nikto 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.
- checksums.yaml +7 -0
- data/.editorconfig +11 -0
- data/.github/workflows/ruby.yml +31 -0
- data/.gitignore +9 -0
- data/.rspec +1 -0
- data/.specopts +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +9 -0
- data/Gemfile +16 -0
- data/LICENSE.txt +22 -0
- data/README.md +80 -0
- data/Rakefile +10 -0
- data/gemspec.yml +24 -0
- data/lib/nikto/command.rb +188 -0
- data/lib/nikto/version.rb +4 -0
- data/lib/nikto/xml/item.rb +55 -0
- data/lib/nikto/xml/scan_details.rb +175 -0
- data/lib/nikto/xml/statistics.rb +64 -0
- data/lib/nikto/xml.rb +230 -0
- data/lib/nikto.rb +2 -0
- data/ruby-nikto.gemspec +58 -0
- data/spec/command_spec.rb +97 -0
- data/spec/fixtures/nikto.xml +47 -0
- data/spec/nikto_spec.rb +8 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/xml/item_spec.rb +61 -0
- data/spec/xml/scan_details_spec.rb +181 -0
- data/spec/xml/statistics_spec.rb +57 -0
- data/spec/xml_spec.rb +190 -0
- metadata +121 -0
@@ -0,0 +1,181 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'nikto/xml/scan_details'
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
describe Nikto::XML::ScanDetails do
|
6
|
+
let(:fixtures_dir) { File.expand_path(File.join(__dir__,'..','fixtures')) }
|
7
|
+
let(:path) { File.join(fixtures_dir,'nikto.xml') }
|
8
|
+
let(:xml) { File.read(path) }
|
9
|
+
let(:doc) { Nokogiri::XML(File.open(path)) }
|
10
|
+
let(:node) { doc.at_xpath('/niktoscan/scandetails') }
|
11
|
+
|
12
|
+
subject { described_class.new(node) }
|
13
|
+
|
14
|
+
describe "#target_ip" do
|
15
|
+
subject { super().target_ip }
|
16
|
+
|
17
|
+
it "must return a String" do
|
18
|
+
expect(subject).to be_kind_of(String)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "must return the 'targetip' attribute" do
|
22
|
+
expect(subject).to eq(node['targetip'])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#target_hostname" do
|
27
|
+
subject { super().target_hostname }
|
28
|
+
|
29
|
+
it "must return a String" do
|
30
|
+
expect(subject).to be_kind_of(String)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "must return the 'targethostname' attribute" do
|
34
|
+
expect(subject).to eq(node['targethostname'])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#target_port" do
|
39
|
+
subject { super().target_port }
|
40
|
+
|
41
|
+
it "must return the 'targetport' attribute as an Integer" do
|
42
|
+
expect(subject).to eq(node['targetport'].to_i)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "must be > 0" do
|
46
|
+
expect(subject).to be > 0
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#target_banner" do
|
51
|
+
subject { super().target_banner }
|
52
|
+
|
53
|
+
it "must return a String" do
|
54
|
+
expect(subject).to be_kind_of(String)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "must return the 'targetbanner' attribute" do
|
58
|
+
expect(subject).to eq(node['targetbanner'])
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#start_time" do
|
63
|
+
subject { super().start_time }
|
64
|
+
|
65
|
+
it "must return the 'starttime' attribute as a Time object" do
|
66
|
+
expect(subject).to eq(Time.parse(node['starttime']))
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#site_name" do
|
71
|
+
subject { super().site_name }
|
72
|
+
|
73
|
+
it "must return a String" do
|
74
|
+
expect(subject).to be_kind_of(String)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "must return the 'sitename' attribute" do
|
78
|
+
expect(subject).to eq(node['sitename'])
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "#site_ip" do
|
83
|
+
subject { super().site_ip }
|
84
|
+
|
85
|
+
it "must return a String" do
|
86
|
+
expect(subject).to be_kind_of(String)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "must return the 'siteip' attribute" do
|
90
|
+
expect(subject).to eq(node['siteip'])
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "#host_header" do
|
95
|
+
subject { super().host_header }
|
96
|
+
|
97
|
+
it "must return a String" do
|
98
|
+
expect(subject).to be_kind_of(String)
|
99
|
+
end
|
100
|
+
|
101
|
+
it "must return the 'hostheader' attribute" do
|
102
|
+
expect(subject).to eq(node['hostheader'])
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "#errors" do
|
107
|
+
subject { super().errors }
|
108
|
+
|
109
|
+
it "must return the 'errors' attribute as an Integer" do
|
110
|
+
expect(subject).to eq(node['errors'].to_i)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "#errors?" do
|
115
|
+
context "when #errors is 0" do
|
116
|
+
before { allow(subject).to receive(:errors).and_return(0) }
|
117
|
+
|
118
|
+
it "must return false" do
|
119
|
+
expect(subject.errors?).to be(false)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context "when #errors is greater than 0" do
|
124
|
+
before { allow(subject).to receive(:errors).and_return(1) }
|
125
|
+
|
126
|
+
it "must return true" do
|
127
|
+
expect(subject.errors?).to be(true)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe "#checks" do
|
133
|
+
subject { super().checks }
|
134
|
+
|
135
|
+
it "must return the 'checks' attribute as an Integer" do
|
136
|
+
expect(subject).to eq(node['checks'].to_i)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "must be > 0" do
|
140
|
+
expect(subject).to be > 0
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
let(:item_count) { node.xpath('item').count }
|
145
|
+
|
146
|
+
describe "#each_item" do
|
147
|
+
context "when given a block" do
|
148
|
+
it "must yield each Item object" do
|
149
|
+
expect { |b|
|
150
|
+
subject.each_item(&b)
|
151
|
+
}.to yield_successive_args(*Array.new(item_count,Nikto::XML::Item))
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context "when no block is given" do
|
156
|
+
subject { super().each_item.to_a }
|
157
|
+
|
158
|
+
it "must return an Enumerator of Nikto::XML::Item objects" do
|
159
|
+
expect(subject.length).to be(item_count)
|
160
|
+
expect(subject).to all(be_kind_of(Nikto::XML::Item))
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe "#items" do
|
166
|
+
subject { super().items}
|
167
|
+
|
168
|
+
it "must return an Array of Nikto::XML::ScanDetails" do
|
169
|
+
expect(subject.length).to be(item_count)
|
170
|
+
expect(subject).to all(be_kind_of(Nikto::XML::Item))
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "#statistics" do
|
175
|
+
subject { super().statistics }
|
176
|
+
|
177
|
+
it "must return a Statistics object" do
|
178
|
+
expect(subject).to be_kind_of(Nikto::XML::Statistics)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'nikto/xml/statistics'
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
describe Nikto::XML::Statistics do
|
6
|
+
let(:fixtures_dir) { File.expand_path(File.join(__dir__,'..','fixtures')) }
|
7
|
+
let(:path) { File.join(fixtures_dir,'nikto.xml') }
|
8
|
+
let(:xml) { File.read(path) }
|
9
|
+
let(:doc) { Nokogiri::XML(File.open(path)) }
|
10
|
+
let(:node) { doc.at_xpath('/niktoscan/scandetails/statistics') }
|
11
|
+
|
12
|
+
subject { described_class.new(node) }
|
13
|
+
|
14
|
+
describe "#elapsed" do
|
15
|
+
subject { super().elapsed }
|
16
|
+
|
17
|
+
it "must return the 'elapsed' attribute as an Integer" do
|
18
|
+
expect(subject).to eq(node['elapsed'].to_i)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "must be greater than 0" do
|
22
|
+
expect(subject).to be > 0
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#items_found" do
|
27
|
+
subject { super().items_found }
|
28
|
+
|
29
|
+
it "must return the 'itemsfound' attribute as an Integer" do
|
30
|
+
expect(subject).to eq(node['itemsfound'].to_i)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "must be greater than 0" do
|
34
|
+
expect(subject).to be > 0
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#items_tested" do
|
39
|
+
subject { super().items_tested }
|
40
|
+
|
41
|
+
it "must return the 'itemstested' attribute as an Integer" do
|
42
|
+
expect(subject).to eq(node['itemstested'].to_i)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "must be greater than 0" do
|
46
|
+
expect(subject).to be > 0
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#end_time" do
|
51
|
+
subject { super().end_time }
|
52
|
+
|
53
|
+
it "must return the 'endtime' attribute as a Time object" do
|
54
|
+
expect(subject).to eq(Time.parse(node['endtime']))
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/spec/xml_spec.rb
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'nikto/xml'
|
3
|
+
|
4
|
+
describe Nikto::XML do
|
5
|
+
let(:fixtures_dir) { File.expand_path(File.join(__dir__,'fixtures')) }
|
6
|
+
let(:path) { File.join(fixtures_dir,'nikto.xml') }
|
7
|
+
let(:xml) { File.read(path) }
|
8
|
+
let(:doc) { Nokogiri::XML(File.open(path)) }
|
9
|
+
|
10
|
+
subject { described_class.new(doc, path: path) }
|
11
|
+
|
12
|
+
describe "#initialize" do
|
13
|
+
it "must set #doc" do
|
14
|
+
expect(subject.doc).to eq(doc)
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when given a block" do
|
18
|
+
it "must yield the new XML object" do
|
19
|
+
expect { |b|
|
20
|
+
described_class.new(xml,&b)
|
21
|
+
}.to yield_with_args(described_class)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "when the path: keyword argument is not given" do
|
26
|
+
subject { described_class.new(xml) }
|
27
|
+
|
28
|
+
it "must set #path to nil" do
|
29
|
+
expect(subject.path).to be(nil)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "when the path: keyword argument is given" do
|
34
|
+
subject { described_class.new(xml, path: path) }
|
35
|
+
|
36
|
+
it "must set #path" do
|
37
|
+
expect(subject.path).to eq(path)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe ".parse" do
|
43
|
+
subject { described_class.parse(xml) }
|
44
|
+
|
45
|
+
it "must parse the XML data" do
|
46
|
+
expect(subject.doc).to be_kind_of(Nokogiri::XML::Document)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "must set #path to nil" do
|
50
|
+
expect(subject.path).to be(nil)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe ".open" do
|
55
|
+
subject { described_class.open(path) }
|
56
|
+
|
57
|
+
it "must open the file and parse the XML" do
|
58
|
+
expect(subject.doc).to be_kind_of(Nokogiri::XML::Document)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "must set #path" do
|
62
|
+
expect(subject.path).to eq(path)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#hosts_test" do
|
67
|
+
subject { super().hosts_test }
|
68
|
+
|
69
|
+
it "must return the 'hoststest' attribute as an Integer" do
|
70
|
+
expect(subject).to eq(doc.root['hoststest'].to_i)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "#options" do
|
75
|
+
subject { super().options }
|
76
|
+
|
77
|
+
it "must return a String" do
|
78
|
+
expect(subject).to be_kind_of(String)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "must return the 'options' attribute" do
|
82
|
+
expect(subject).to eq(doc.root['options'])
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#scan_start" do
|
87
|
+
subject { super().scan_start }
|
88
|
+
|
89
|
+
it "must return the 'scanstart' attribute as a Time object" do
|
90
|
+
expect(subject).to eq(Time.parse(doc.root['scanstart']))
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "#scan_end" do
|
95
|
+
subject { super().scan_end }
|
96
|
+
|
97
|
+
it "must return the 'scanend' attribute as a Time object" do
|
98
|
+
expect(subject).to eq(Time.parse(doc.root['scanend']))
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "#scan_elapsed" do
|
103
|
+
subject { super().scan_elapsed }
|
104
|
+
|
105
|
+
it "must return a String" do
|
106
|
+
expect(subject).to be_kind_of(String)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "must return the 'scanelapsed' attribute" do
|
110
|
+
expect(subject).to eq(doc.root['scanelapsed'])
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "#nikto_xml_version" do
|
115
|
+
subject { super().nikto_xml_version }
|
116
|
+
|
117
|
+
it "must return a String" do
|
118
|
+
expect(subject).to be_kind_of(String)
|
119
|
+
end
|
120
|
+
|
121
|
+
it "must return the 'nxmlversion' attribute" do
|
122
|
+
expect(subject).to eq(doc.root['nxmlversion'])
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "#each_scan_details" do
|
127
|
+
context "when given a block" do
|
128
|
+
it "must yield each ScanDetails object" do
|
129
|
+
expect { |b|
|
130
|
+
subject.each_scan_details(&b)
|
131
|
+
}.to yield_successive_args(described_class::ScanDetails)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context "when no block is given" do
|
136
|
+
subject { super().each_scan_details.to_a }
|
137
|
+
|
138
|
+
it "must return an Enumerator of #{described_class}::ScanDetails objects" do
|
139
|
+
expect(subject.length).to be(1)
|
140
|
+
expect(subject[0]).to be_kind_of(described_class::ScanDetails)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "#scan_details" do
|
146
|
+
subject { super().scan_details }
|
147
|
+
|
148
|
+
it "must return an Array of #{described_class}::ScanDetails" do
|
149
|
+
expect(subject).to be_kind_of(Array)
|
150
|
+
expect(subject.length).to be(1)
|
151
|
+
expect(subject[0]).to be_kind_of(described_class::ScanDetails)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe "#target" do
|
156
|
+
let(:first_scan_details) { subject.scan_details.first }
|
157
|
+
let(:target) { subject.target }
|
158
|
+
|
159
|
+
it "must return the first #scan_details" do
|
160
|
+
expect(target.target_ip).to eq(first_scan_details.target_ip)
|
161
|
+
expect(target.target_hostname).to eq(first_scan_details.target_hostname)
|
162
|
+
expect(target.target_port).to eq(first_scan_details.target_port)
|
163
|
+
expect(target.target_banner).to eq(first_scan_details.target_banner)
|
164
|
+
expect(target.start_time).to eq(first_scan_details.start_time)
|
165
|
+
expect(target.site_name).to eq(first_scan_details.site_name)
|
166
|
+
expect(target.site_ip).to eq(first_scan_details.site_ip)
|
167
|
+
expect(target.host_header).to eq(first_scan_details.host_header)
|
168
|
+
expect(target.errors).to eq(first_scan_details.errors)
|
169
|
+
expect(target.checks).to eq(first_scan_details.checks)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "#to_s" do
|
174
|
+
context "when #path is set" do
|
175
|
+
subject { described_class.open(path) }
|
176
|
+
|
177
|
+
it "must return the #path" do
|
178
|
+
expect(subject.to_s).to eq(path)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
context "when #path is nil" do
|
183
|
+
subject { described_class.parse(xml) }
|
184
|
+
|
185
|
+
it "must return the XML" do
|
186
|
+
expect(subject.to_s).to eq(doc.to_s)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby-nikto
|
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: 2021-11-30 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.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: nokogiri
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.0'
|
55
|
+
description: A Ruby interface to Nikto, the Web Server scanner.
|
56
|
+
email: postmodern.mod3@gmail.com
|
57
|
+
executables: []
|
58
|
+
extensions: []
|
59
|
+
extra_rdoc_files:
|
60
|
+
- ChangeLog.md
|
61
|
+
- LICENSE.txt
|
62
|
+
- README.md
|
63
|
+
files:
|
64
|
+
- ".editorconfig"
|
65
|
+
- ".github/workflows/ruby.yml"
|
66
|
+
- ".gitignore"
|
67
|
+
- ".rspec"
|
68
|
+
- ".specopts"
|
69
|
+
- ".yardopts"
|
70
|
+
- ChangeLog.md
|
71
|
+
- Gemfile
|
72
|
+
- LICENSE.txt
|
73
|
+
- README.md
|
74
|
+
- Rakefile
|
75
|
+
- gemspec.yml
|
76
|
+
- lib/nikto.rb
|
77
|
+
- lib/nikto/command.rb
|
78
|
+
- lib/nikto/version.rb
|
79
|
+
- lib/nikto/xml.rb
|
80
|
+
- lib/nikto/xml/item.rb
|
81
|
+
- lib/nikto/xml/scan_details.rb
|
82
|
+
- lib/nikto/xml/statistics.rb
|
83
|
+
- ruby-nikto.gemspec
|
84
|
+
- spec/command_spec.rb
|
85
|
+
- spec/fixtures/nikto.xml
|
86
|
+
- spec/nikto_spec.rb
|
87
|
+
- spec/spec_helper.rb
|
88
|
+
- spec/xml/item_spec.rb
|
89
|
+
- spec/xml/scan_details_spec.rb
|
90
|
+
- spec/xml/statistics_spec.rb
|
91
|
+
- spec/xml_spec.rb
|
92
|
+
homepage: http://github.com/sophsec/ruby-nikto
|
93
|
+
licenses:
|
94
|
+
- MIT
|
95
|
+
metadata:
|
96
|
+
documentation_uri: https://rubydoc.info/gems/ruby-nikto
|
97
|
+
source_code_uri: https://github.com/postmodern/ruby-nikto
|
98
|
+
bug_tracker_uri: https://github.com/postmodern/ruby-nikto/issues
|
99
|
+
changelog_uri: https://github.com/postmodern/ruby-nikto/blob/master/ChangeLog.md
|
100
|
+
rubygems_mfa_required: 'true'
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
requirements:
|
116
|
+
- nikto >= 2.1.0
|
117
|
+
rubygems_version: 3.2.22
|
118
|
+
signing_key:
|
119
|
+
specification_version: 4
|
120
|
+
summary: A Ruby interface to Nikto.
|
121
|
+
test_files: []
|