ruby-ncrack 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/.document +3 -0
- data/.editorconfig +11 -0
- data/.github/workflows/ruby.yml +31 -0
- data/.gitignore +9 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +10 -0
- data/Gemfile +16 -0
- data/LICENSE.txt +20 -0
- data/README.md +84 -0
- data/Rakefile +12 -0
- data/gemspec.yml +26 -0
- data/lib/ncrack/command.rb +108 -0
- data/lib/ncrack/version.rb +4 -0
- data/lib/ncrack/xml/address.rb +79 -0
- data/lib/ncrack/xml/credentials.rb +64 -0
- data/lib/ncrack/xml/port.rb +82 -0
- data/lib/ncrack/xml/service.rb +104 -0
- data/lib/ncrack/xml.rb +234 -0
- data/lib/ncrack.rb +2 -0
- data/ruby-ncrack.gemspec +58 -0
- data/spec/fixtures/ncrack.xml +13 -0
- data/spec/ncrack_spec.rb +8 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/xml/address_spec.rb +73 -0
- data/spec/xml/credentials_spec.rb +49 -0
- data/spec/xml/port_spec.rb +57 -0
- data/spec/xml/service_spec.rb +86 -0
- data/spec/xml_spec.rb +184 -0
- metadata +122 -0
data/lib/ncrack/xml.rb
ADDED
@@ -0,0 +1,234 @@
|
|
1
|
+
require 'ncrack/xml/service'
|
2
|
+
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
module Ncrack
|
6
|
+
#
|
7
|
+
# Represents an ncrack XML file or XML data.
|
8
|
+
#
|
9
|
+
# ## Examples
|
10
|
+
#
|
11
|
+
# require 'ncrack/xml'
|
12
|
+
#
|
13
|
+
# Ncrack::XML.open('ncrack.xml') do |xml|
|
14
|
+
# xml.each_service do |service|
|
15
|
+
# puts "#{service.address} #{service.port.number}/#{service.port.name}:"
|
16
|
+
#
|
17
|
+
# service.each_credentials.each do |credentials|
|
18
|
+
# puts " #{credentials}"
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
class XML
|
24
|
+
|
25
|
+
# The parsed XML document.
|
26
|
+
#
|
27
|
+
# @return [Nokogiri::XML::Node]
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
attr_reader :doc
|
31
|
+
|
32
|
+
# The path to the XML file.
|
33
|
+
#
|
34
|
+
# @return [String, nil]
|
35
|
+
attr_reader :path
|
36
|
+
|
37
|
+
#
|
38
|
+
# Creates a new XML object.
|
39
|
+
#
|
40
|
+
# @param [Nokogiri::XML] doc
|
41
|
+
# The parsed XML document.
|
42
|
+
#
|
43
|
+
# @param [String, nil] path
|
44
|
+
# The path to the XML file.
|
45
|
+
#
|
46
|
+
# @yield [xml]
|
47
|
+
# If a block is given, it will be passed the newly created XML
|
48
|
+
# parser.
|
49
|
+
#
|
50
|
+
# @yieldparam [XML] xml
|
51
|
+
# The newly created XML parser.
|
52
|
+
#
|
53
|
+
# @api private
|
54
|
+
#
|
55
|
+
def initialize(doc, path: nil)
|
56
|
+
@doc = doc
|
57
|
+
@path = File.expand_path(path) if path
|
58
|
+
|
59
|
+
yield self if block_given?
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# Parses the given XML String.
|
64
|
+
#
|
65
|
+
# @param [String] xml
|
66
|
+
# The XML String.
|
67
|
+
#
|
68
|
+
# @yield [xml]
|
69
|
+
# If a block is given, it will be passed the newly created XML
|
70
|
+
# parser.
|
71
|
+
#
|
72
|
+
# @yieldparam [XML] xml
|
73
|
+
# The newly created XML parser.
|
74
|
+
#
|
75
|
+
# @return [XML]
|
76
|
+
# The parsed XML.
|
77
|
+
#
|
78
|
+
# @api public
|
79
|
+
#
|
80
|
+
def self.parse(xml,&block)
|
81
|
+
new(Nokogiri::XML(xml),&block)
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
# Opens an parses an XML file.
|
86
|
+
#
|
87
|
+
# @param [String] path
|
88
|
+
# The path to the XML file.
|
89
|
+
#
|
90
|
+
# @yield [xml]
|
91
|
+
# If a block is given, it will be passed the newly created XML
|
92
|
+
# parser.
|
93
|
+
#
|
94
|
+
# @yieldparam [XML] xml
|
95
|
+
# The newly created XML parser.
|
96
|
+
#
|
97
|
+
# @return [XML]
|
98
|
+
# The parsed XML.
|
99
|
+
#
|
100
|
+
# @api public
|
101
|
+
#
|
102
|
+
def self.open(path,&block)
|
103
|
+
path = File.expand_path(path)
|
104
|
+
|
105
|
+
new(Nokogiri::XML(File.open(path)), path: path, &block)
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# The scanner that produced the XML (aka `ncrack`).
|
110
|
+
#
|
111
|
+
# @return [String]
|
112
|
+
# The value of the `scanner` attribute.
|
113
|
+
#
|
114
|
+
def scanner
|
115
|
+
@scanner ||= @doc.root['scanner']
|
116
|
+
end
|
117
|
+
|
118
|
+
#
|
119
|
+
# Additional command-line arguments passed to `ncrack`.
|
120
|
+
#
|
121
|
+
# @return [String]
|
122
|
+
# The value of the `args` attribute.
|
123
|
+
#
|
124
|
+
def args
|
125
|
+
@args ||= @doc.root['args']
|
126
|
+
end
|
127
|
+
|
128
|
+
#
|
129
|
+
# The start time.
|
130
|
+
#
|
131
|
+
# @return [Time]
|
132
|
+
# The parsed value of the `start` attribute.
|
133
|
+
#
|
134
|
+
def start
|
135
|
+
@start ||= Time.at(@doc.root['start'].to_i)
|
136
|
+
end
|
137
|
+
|
138
|
+
#
|
139
|
+
# The version of `ncrack`.
|
140
|
+
#
|
141
|
+
# @return [String]
|
142
|
+
# The value of the `version` attribute.
|
143
|
+
#
|
144
|
+
def version
|
145
|
+
@version ||= @doc.root['version']
|
146
|
+
end
|
147
|
+
|
148
|
+
#
|
149
|
+
# The version of the `ncrack` XML schema.
|
150
|
+
#
|
151
|
+
# @return [String]
|
152
|
+
# The value of the `xmloutputversion` attribute.
|
153
|
+
#
|
154
|
+
def xml_output_version
|
155
|
+
@xml_output_version ||= @doc.root['xmloutputversion']
|
156
|
+
end
|
157
|
+
|
158
|
+
#
|
159
|
+
# The verbosity level.
|
160
|
+
#
|
161
|
+
# @return [Integer]
|
162
|
+
# The parsed value of the `level` attribute of the `verbose` child
|
163
|
+
# element.
|
164
|
+
#
|
165
|
+
def verbose
|
166
|
+
@verbose ||= @doc.at_xpath('/ncrackrun/verbose')['level'].to_i
|
167
|
+
end
|
168
|
+
|
169
|
+
#
|
170
|
+
# The debugging level.
|
171
|
+
#
|
172
|
+
# @return [Integer]
|
173
|
+
# The parsed value of the `level` attribute of the `debugging` child
|
174
|
+
# element.
|
175
|
+
#
|
176
|
+
def debugging
|
177
|
+
@debugging ||= @doc.at_xpath('/ncrackrun/debugging')['level'].to_i
|
178
|
+
end
|
179
|
+
|
180
|
+
#
|
181
|
+
# Enumerates over every service.
|
182
|
+
#
|
183
|
+
# @yield [service]
|
184
|
+
# If a block is given, it will be passed every service object.
|
185
|
+
#
|
186
|
+
# @yieldparam [Service] service
|
187
|
+
# A service object.
|
188
|
+
#
|
189
|
+
# @return [Enumerator]
|
190
|
+
# If no block is given, an Enumerator object will be returned.
|
191
|
+
#
|
192
|
+
def each_service
|
193
|
+
return enum_for(__method__) unless block_given?
|
194
|
+
|
195
|
+
@doc.root.xpath('/ncrackrun/service').each do |node|
|
196
|
+
yield Service.new(node)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
#
|
201
|
+
# All service object.
|
202
|
+
#
|
203
|
+
# @return [Array<Service>]
|
204
|
+
#
|
205
|
+
def services
|
206
|
+
each_service.to_a
|
207
|
+
end
|
208
|
+
|
209
|
+
#
|
210
|
+
# The first service object.
|
211
|
+
#
|
212
|
+
# @return [Service, nik]
|
213
|
+
#
|
214
|
+
def service
|
215
|
+
each_service.first
|
216
|
+
end
|
217
|
+
|
218
|
+
#
|
219
|
+
# Converts the XML to a String.
|
220
|
+
#
|
221
|
+
# @return [String]
|
222
|
+
# The path to the XML if {#path} is set, or the XML if the XML was parsed
|
223
|
+
# from a String.
|
224
|
+
#
|
225
|
+
def to_s
|
226
|
+
if @path
|
227
|
+
@path
|
228
|
+
else
|
229
|
+
@doc.to_s
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
end
|
data/lib/ncrack.rb
ADDED
data/ruby-ncrack.gemspec
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
Gem::Specification.new do |gem|
|
4
|
+
gemspec = YAML.load_file('gemspec.yml')
|
5
|
+
|
6
|
+
gem.name = gemspec.fetch('name')
|
7
|
+
gem.version = gemspec.fetch('version') do
|
8
|
+
lib_dir = File.join(File.dirname(__FILE__),'lib')
|
9
|
+
$LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
|
10
|
+
|
11
|
+
require File.join('ncrack','version')
|
12
|
+
Ncrack::VERSION
|
13
|
+
end
|
14
|
+
|
15
|
+
gem.summary = gemspec['summary']
|
16
|
+
gem.description = gemspec['description']
|
17
|
+
gem.licenses = Array(gemspec['license'])
|
18
|
+
gem.authors = Array(gemspec['authors'])
|
19
|
+
gem.email = gemspec['email']
|
20
|
+
gem.homepage = gemspec['homepage']
|
21
|
+
gem.metadata = gemspec['metadata'] if gemspec['metadata']
|
22
|
+
|
23
|
+
glob = lambda { |patterns| gem.files & Dir[*patterns] }
|
24
|
+
|
25
|
+
gem.files = if gemspec['files'] then glob[gemspec['files']]
|
26
|
+
else `git ls-files`.split($/)
|
27
|
+
end
|
28
|
+
|
29
|
+
gem.executables = gemspec.fetch('executables') do
|
30
|
+
glob['bin/*'].map { |path| File.basename(path) }
|
31
|
+
end
|
32
|
+
|
33
|
+
gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
|
34
|
+
gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
|
35
|
+
|
36
|
+
gem.require_paths = Array(gemspec.fetch('require_paths') {
|
37
|
+
%w[ext lib].select { |dir| File.directory?(dir) }
|
38
|
+
})
|
39
|
+
|
40
|
+
gem.requirements = gemspec['requirements']
|
41
|
+
gem.required_ruby_version = gemspec['required_ruby_version']
|
42
|
+
gem.required_rubygems_version = gemspec['required_rubygems_version']
|
43
|
+
gem.post_install_message = gemspec['post_install_message']
|
44
|
+
|
45
|
+
split = lambda { |string| string.split(/,\s*/) }
|
46
|
+
|
47
|
+
if gemspec['dependencies']
|
48
|
+
gemspec['dependencies'].each do |name,versions|
|
49
|
+
gem.add_dependency(name,split[versions])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
if gemspec['development_dependencies']
|
54
|
+
gemspec['development_dependencies'].each do |name,versions|
|
55
|
+
gem.add_development_dependency(name,split[versions])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE ncrackrun>
|
3
|
+
<!-- Ncrack 0.7 scan initiated Mon Nov 29 10:27:35 2021 as: ncrack -v -m HTTP --user alice,eve,bob,root,admin --pass foo,bar,test,password,swordfish,god,hunter -g path=/protected_content -oX ncrack.xml http://localhost:4567 -->
|
4
|
+
<ncrackrun scanner="ncrack" args="ncrack -v -m HTTP --user alice,eve,bob,root,admin --pass foo,bar,test,password,swordfish,god,hunter -g path=/protected_content -oX ncrack.xml http://localhost:4567" start="1638210455" startstr="Mon Nov 29 10:27:35 2021" version="0.7" xmloutputversion="1.00">
|
5
|
+
<verbose level="1"/>
|
6
|
+
<debugging level="0"/>
|
7
|
+
<service starttime="1638210455" endtime="1638210455">
|
8
|
+
<address addr="127.0.0.1" addrtype="ipv4"/>
|
9
|
+
<port protocol="tcp" portid="4567" name="http"></port>
|
10
|
+
<credentials username="admin" password="swordfish"></credentials>
|
11
|
+
<credentials username="bob" password="hunter"></credentials>
|
12
|
+
</service>
|
13
|
+
</ncrackrun>
|
data/spec/ncrack_spec.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ncrack/xml/address'
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
describe Ncrack::XML::Address do
|
6
|
+
let(:fixtures_dir) { File.expand_path(File.join(__dir__,'..','fixtures')) }
|
7
|
+
let(:path) { File.join(fixtures_dir,'ncrack.xml') }
|
8
|
+
let(:xml) { File.read(path) }
|
9
|
+
let(:doc) { Nokogiri::XML(File.open(path)) }
|
10
|
+
let(:node) { doc.at_xpath('/ncrackrun/service/address') }
|
11
|
+
|
12
|
+
subject { described_class.new(node) }
|
13
|
+
|
14
|
+
describe "#addr" do
|
15
|
+
subject { super().addr }
|
16
|
+
|
17
|
+
it "must return a String" do
|
18
|
+
expect(subject).to be_kind_of(String)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "must return the 'addr' attribute" do
|
22
|
+
expect(subject).to eq(node['addr'])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#type" do
|
27
|
+
it "must return the 'addrtype' attribute as a Symbol" do
|
28
|
+
expect(subject.type).to eq(node['addrtype'].to_sym)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#ipv4?" do
|
33
|
+
context "when #type returns :ipv4" do
|
34
|
+
before { allow(subject).to receive(:type).and_return(:ipv4) }
|
35
|
+
|
36
|
+
it "must return true" do
|
37
|
+
expect(subject.ipv4?).to be(true)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "when #type does not return :ipv4" do
|
42
|
+
before { allow(subject).to receive(:type).and_return(:ipv6) }
|
43
|
+
|
44
|
+
it "must return false" do
|
45
|
+
expect(subject.ipv4?).to be(false)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#ipv6?" do
|
51
|
+
context "when #type returns :ipv6" do
|
52
|
+
before { allow(subject).to receive(:type).and_return(:ipv6) }
|
53
|
+
|
54
|
+
it "must return true" do
|
55
|
+
expect(subject.ipv6?).to be(true)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when #type does not return :ipv6" do
|
60
|
+
before { allow(subject).to receive(:type).and_return(:ipv4) }
|
61
|
+
|
62
|
+
it "must return false" do
|
63
|
+
expect(subject.ipv6?).to be(false)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#to_s" do
|
69
|
+
it "must return #addr" do
|
70
|
+
expect(subject.to_s).to eq(subject.addr)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ncrack/xml/credentials'
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
describe Ncrack::XML::Credentials do
|
6
|
+
let(:fixtures_dir) { File.expand_path(File.join(__dir__,'..','fixtures')) }
|
7
|
+
let(:path) { File.join(fixtures_dir,'ncrack.xml') }
|
8
|
+
let(:xml) { File.read(path) }
|
9
|
+
let(:doc) { Nokogiri::XML(File.open(path)) }
|
10
|
+
let(:node) { doc.at_xpath('/ncrackrun/service/credentials') }
|
11
|
+
|
12
|
+
subject { described_class.new(node) }
|
13
|
+
|
14
|
+
describe "#username" do
|
15
|
+
subject { super().username }
|
16
|
+
|
17
|
+
it "must return a String" do
|
18
|
+
expect(subject).to be_kind_of(String)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "must return the 'username' attribute" do
|
22
|
+
expect(subject).to eq(node['username'])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#password" do
|
27
|
+
subject { super().password }
|
28
|
+
|
29
|
+
it "must return a String" do
|
30
|
+
expect(subject).to be_kind_of(String)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "must return the 'password' attribute" do
|
34
|
+
expect(subject).to eq(node['password'])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#to_s" do
|
39
|
+
it "must return the 'username:password'" do
|
40
|
+
expect(subject.to_s).to eq("#{subject.username}:#{subject.password}")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#to_a" do
|
45
|
+
it "must return [username, password] tuple" do
|
46
|
+
expect(subject.to_a).to eq([subject.username, subject.password])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ncrack/xml/port'
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
describe Ncrack::XML::Port do
|
6
|
+
let(:fixtures_dir) { File.expand_path(File.join(__dir__,'..','fixtures')) }
|
7
|
+
let(:path) { File.join(fixtures_dir,'ncrack.xml') }
|
8
|
+
let(:xml) { File.read(path) }
|
9
|
+
let(:doc) { Nokogiri::XML(File.open(path)) }
|
10
|
+
let(:node) { doc.at_xpath('/ncrackrun/service/port') }
|
11
|
+
|
12
|
+
subject { described_class.new(node) }
|
13
|
+
|
14
|
+
describe "#protocol" do
|
15
|
+
subject { super().protocol }
|
16
|
+
|
17
|
+
it "must return the 'protocol' attribute as a Symbol" do
|
18
|
+
expect(subject).to eq(node['protocol'].to_sym)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#number" do
|
23
|
+
subject { super().number }
|
24
|
+
|
25
|
+
it "must return the 'portid' attribute as an Integer" do
|
26
|
+
expect(subject).to eq(node['portid'].to_i)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "must be > 0" do
|
30
|
+
expect(subject).to be > 0
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#name" do
|
35
|
+
subject { super().name }
|
36
|
+
|
37
|
+
it "must return a String" do
|
38
|
+
expect(subject).to be_kind_of(String)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "must return the 'name' attribute" do
|
42
|
+
expect(subject).to eq(node['name'])
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#to_i" do
|
47
|
+
it "must return #number" do
|
48
|
+
expect(subject.to_i).to eq(subject.number)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#to_s" do
|
53
|
+
it "must return the #name" do
|
54
|
+
expect(subject.to_s).to eq(subject.name)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ncrack/xml/service'
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
describe Ncrack::XML::Service do
|
6
|
+
let(:fixtures_dir) { File.expand_path(File.join(__dir__,'..','fixtures')) }
|
7
|
+
let(:path) { File.join(fixtures_dir,'ncrack.xml') }
|
8
|
+
let(:xml) { File.read(path) }
|
9
|
+
let(:doc) { Nokogiri::XML(File.open(path)) }
|
10
|
+
let(:node) { doc.at_xpath('/ncrackrun/service') }
|
11
|
+
|
12
|
+
subject { described_class.new(node) }
|
13
|
+
|
14
|
+
describe "#start_time" do
|
15
|
+
subject { super().start_time }
|
16
|
+
|
17
|
+
it "must return the 'starttime' attribute as a Time object" do
|
18
|
+
expect(subject).to eq(Time.at(node['starttime'].to_i))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#end_time" do
|
23
|
+
subject { super().end_time }
|
24
|
+
|
25
|
+
it "must return the 'endtime' attribute as a Time object" do
|
26
|
+
expect(subject).to eq(Time.at(node['endtime'].to_i))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#address" do
|
31
|
+
subject { super().address }
|
32
|
+
|
33
|
+
it "must return an Ncrack::XML::Address object" do
|
34
|
+
expect(subject).to be_kind_of(Ncrack::XML::Address)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#port" do
|
39
|
+
subject { super().port }
|
40
|
+
|
41
|
+
it "must return an Ncrack::XML::Port object" do
|
42
|
+
expect(subject).to be_kind_of(Ncrack::XML::Port)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
let(:credentials_count) { node.xpath('credentials').count }
|
47
|
+
|
48
|
+
describe "#each_credentials" do
|
49
|
+
context "when given a block" do
|
50
|
+
it "must yield each Nikto::XML::Credentials object" do
|
51
|
+
expect { |b|
|
52
|
+
subject.each_credentials(&b)
|
53
|
+
}.to yield_successive_args(*Array.new(credentials_count,Ncrack::XML::Credentials))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "when no block is given" do
|
58
|
+
subject { super().each_credentials.to_a }
|
59
|
+
|
60
|
+
it "must return an Enumerator of Ncrack::XML::Credentials objects" do
|
61
|
+
expect(subject.length).to be(credentials_count)
|
62
|
+
expect(subject).to all(be_kind_of(Ncrack::XML::Credentials))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "#credentials" do
|
68
|
+
subject { super().credentials }
|
69
|
+
|
70
|
+
it "must return an Array of #{described_class}::Service" do
|
71
|
+
expect(subject).to be_kind_of(Array)
|
72
|
+
expect(subject.length).to be(credentials_count)
|
73
|
+
expect(subject).to all(be_kind_of(Ncrack::XML::Credentials))
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#credential" do
|
78
|
+
let(:first_credentials) { subject.credentials.first }
|
79
|
+
let(:credential) { subject.credential }
|
80
|
+
|
81
|
+
it "must return the first #credentials" do
|
82
|
+
expect(credential.username).to eq(first_credentials.username)
|
83
|
+
expect(credential.password).to eq(first_credentials.password)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|