ruby-nessus 0.1.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,92 @@
1
+ require 'ruby-nessus/Version1/port'
2
+
3
+ module Nessus
4
+ module Version1
5
+
6
+ class Event
7
+ # Event
8
+ attr_reader :event
9
+
10
+ # Return the total event count for a given host.
11
+ # @return [Integer]
12
+ # Return the total event count for a given host.
13
+ # @example
14
+ # host.event_count #=> 3456
15
+ def initialize(event)
16
+ @event = event
17
+ end
18
+
19
+ # Return the event port.
20
+ # @return [Object]
21
+ # Return the event port object or port string.
22
+ # @example
23
+ # event.port #=> "https (443/tcp)"
24
+ # event.port.number #=> 443
25
+ # event.port.service #=> "https"
26
+ # event.port.protocol #=> "tcp"
27
+ def port
28
+ @port ||= Port.parse(@event.at('port').inner_text)
29
+ end
30
+
31
+ # Return the event severity.
32
+ # @return [String]
33
+ # Return the event severity.
34
+ # @example
35
+ # event.severity #=> 3
36
+ # event.severity.in_words #=> "High Severity"
37
+ # @see String#in_words
38
+ def severity
39
+ @severity ||= @event.at('severity').inner_text.to_i
40
+ end
41
+
42
+ # Return the event object nessus plugin id
43
+ # @return [String]
44
+ # Return the event object nessus plugin id
45
+ # @example
46
+ # event.plugin_id #=> 3245
47
+ def plugin_id
48
+ @plugin_id ||= @event.at('pluginID').inner_text.to_i
49
+ end
50
+
51
+ # Return the event name (plugin_name)
52
+ # @return [String]
53
+ # Return the event name (plugin_name)
54
+ # @example
55
+ # event.plugin_name #=> "PHP < 5.2.4 Multiple Vulnerabilities"
56
+ # event.name #=> "PHP < 5.2.4 Multiple Vulnerabilities"
57
+ def plugin_name
58
+ s = @event.at('pluginName').inner_text
59
+
60
+ @plugin_name ||= unless s.empty?
61
+ @event.at('pluginName').inner_text || "N/A"
62
+ else
63
+ false
64
+ end
65
+
66
+ return @plugin_name
67
+ end
68
+ alias name plugin_name
69
+
70
+ # Return the event plugin output data
71
+ # @return [String]
72
+ # Return the event plugin output data
73
+ # @example
74
+ # event.output #=> "..."
75
+ # event.data #=> "..."
76
+ def data
77
+ d = "#{@event.at('data')}" || ""
78
+
79
+ @data ||= unless d.empty?
80
+ @event.at('data').inner_text || "N/A"
81
+ else
82
+ false
83
+ end
84
+ return @data
85
+ end
86
+ alias output data
87
+
88
+ end
89
+
90
+ end
91
+
92
+ end
@@ -0,0 +1,260 @@
1
+ module Nessus
2
+ module Version1
3
+
4
+ class Host
5
+ include Enumerable
6
+
7
+ # Host
8
+ attr_reader :host
9
+
10
+ # Creates A New Host Object
11
+ # @param [Object] Host Object
12
+ # @example
13
+ # Host.new(object)
14
+ def initialize(host)
15
+ @host = host
16
+ end
17
+
18
+ # Return the Host Object hostname.
19
+ # @return [String]
20
+ # The Host Object Hostname
21
+ # @example
22
+ # host.hostname #=> "127.0.0.1"
23
+ def hostname
24
+ @hostname ||= @host.at('HostName').inner_text
25
+ end
26
+ alias ip hostname
27
+
28
+ # Return the host scan start time.
29
+ # @return [DateTime]
30
+ # The Host Scan Start Time
31
+ # @example
32
+ # scan.scan_start_time #=> 'Fri Nov 11 23:36:54 1985'
33
+ def scan_start_time
34
+ if @host.at('startTime').inner_text.blank?
35
+ return false
36
+ else
37
+ @host_scan_time = DateTime.strptime(@host.at('startTime').inner_text, fmt='%a %b %d %H:%M:%S %Y')
38
+ end
39
+ end
40
+
41
+ # Return the host scan stop time.
42
+ # @return [DateTime]
43
+ # The Host Scan Stop Time
44
+ # @example
45
+ # scan.scan_start_time #=> 'Fri Nov 11 23:36:54 1985'
46
+ def scan_stop_time
47
+ if @host.at('stopTime').inner_text.blank?
48
+ return false
49
+ else
50
+ @host_scan_time = DateTime.strptime(@host.at('stopTime').inner_text, fmt='%a %b %d %H:%M:%S %Y')
51
+ end
52
+ end
53
+
54
+ # Return the host run time.
55
+ # @return [String]
56
+ # The Host Scan Run Time
57
+ # @example
58
+ # scan.scan_run_time #=> '2 hours 5 minutes and 16 seconds'
59
+ def scan_runtime
60
+ h = ("#{Time.parse(scan_stop_time.to_s).strftime('%H').to_i - Time.parse(scan_start_time.to_s).strftime('%H').to_i}").gsub('-', '')
61
+ m = ("#{Time.parse(scan_stop_time.to_s).strftime('%M').to_i - Time.parse(scan_start_time.to_s).strftime('%M').to_i}").gsub('-', '')
62
+ s = ("#{Time.parse(scan_stop_time.to_s).strftime('%S').to_i - Time.parse(scan_start_time.to_s).strftime('%S').to_i}").gsub('-', '')
63
+ return "#{h} hours #{m} minutes and #{s} seconds"
64
+ end
65
+
66
+ # Return the Host Netbios Name.
67
+ # @return [String]
68
+ # The Host Netbios Name
69
+ # @example
70
+ # host.netbios_name #=> "SOMENAME4243"
71
+ def netbios_name
72
+ @netbios_name ||= @host.at('netbios_name').inner_text
73
+ end
74
+
75
+ # Return the Host Mac Address.
76
+ # @return [String]
77
+ # Return the Host Mac Address
78
+ # @example
79
+ # host.mac_addr #=> "00:11:22:33:44:55"
80
+ def mac_addr
81
+ @mac_addr ||= @host.at('mac_addr').inner_text
82
+ end
83
+ alias mac_address mac_addr
84
+
85
+ # Return the Host DNS Name.
86
+ # @return [String]
87
+ # Return the Host DNS Name
88
+ # @example
89
+ # host.dns_name #=> "snorby.org"
90
+ def dns_name
91
+ @dns_name ||= @host.at('dns_name').inner_text
92
+ end
93
+
94
+ # Return the Host OS Name.
95
+ # @return [String]
96
+ # Return the Host OS Name
97
+ # @example
98
+ # host.dns_name #=> "Microsoft Windows 2000, Microsoft Windows Server 2003"
99
+ def os_name
100
+ @os_name ||= @host.at('os_name').inner_text
101
+ end
102
+ alias operating_system os_name
103
+
104
+ # Return the open ports for a given host object.
105
+ # @return [Integer]
106
+ # Return the open ports for a given host object.
107
+ # @example
108
+ # host.open_ports #=> 213
109
+ def open_ports
110
+ @scanned_ports ||= @host.at('num_ports').inner_text.to_i
111
+ end
112
+
113
+ # Returns All Informational Event Objects For A Given Host.
114
+ # @yield [prog] If a block is given, it will be passed the newly
115
+ # created Event object.
116
+ # @yieldparam [EVENT] prog The newly created Event object.
117
+ # @return [Integer]
118
+ # Return The Informational Event Count For A Given Host.
119
+ # @example
120
+ # host.informational_events do |info|
121
+ # puts info.port
122
+ # puts info.data if info.data
123
+ # end
124
+ def informational_events(&block)
125
+ unless @informational_events
126
+ @informational_events = []
127
+ @informational_event_count = 0
128
+
129
+ @host.xpath("ReportItem").each do |event|
130
+ next if event.at('severity').inner_text.to_i != 0
131
+ @informational_events << Event.new(event)
132
+ @informational_event_count += 1
133
+ end
134
+
135
+ end
136
+
137
+ @informational_events.each(&block)
138
+ return @informational_event_count
139
+ end
140
+
141
+ # Returns All Low Event Objects For A Given Host.
142
+ # @yield [prog] If a block is given, it will be passed the newly
143
+ # created Event object.
144
+ # @yieldparam [EVENT] prog The newly created Event object.
145
+ # @return [Integer]
146
+ # Return The Low Event Count For A Given Host.
147
+ # @example
148
+ # host.low_severity_events do |low|
149
+ # puts low.name if low.name
150
+ # end
151
+ def low_severity_events(&block)
152
+
153
+ @low_severity_count = @host.at('num_lo').inner_text.to_i
154
+
155
+ unless @low_severity_events
156
+ @low_severity_events = []
157
+
158
+ @host.xpath("ReportItem").each do |event|
159
+ next if event.at('severity').inner_text.to_i != 1
160
+ @low_severity_events << Event.new(event)
161
+ end
162
+
163
+ end
164
+
165
+ @low_severity_events.each(&block)
166
+ return @low_severity_count
167
+ end
168
+
169
+ # Returns All Medium Event Objects For A Given Host.
170
+ # @yield [prog] If a block is given, it will be passed the newly
171
+ # created Event object.
172
+ # @yieldparam [EVENT] prog The newly created Event object.
173
+ # @return [Integer]
174
+ # Return The Medium Event Count For A Given Host.
175
+ # @example
176
+ # host.medium_severity_events do |medium|
177
+ # puts medium.name if medium.name
178
+ # end
179
+ def medium_severity_events(&block)
180
+
181
+ @high_severity_count = @host.at('num_med').inner_text.to_i
182
+
183
+ unless @medium_severity_events
184
+ @medium_severity_events = []
185
+
186
+ @host.xpath("ReportItem").each do |event|
187
+ next if event.at('severity').inner_text.to_i != 2
188
+ @medium_severity_events << Event.new(event)
189
+ end
190
+
191
+ end
192
+
193
+ @medium_severity_events.each(&block)
194
+ return @high_severity_count
195
+ end
196
+
197
+ # Returns All High Event Objects For A Given Host.
198
+ # @yield [prog] If a block is given, it will be passed the newly
199
+ # created Event object.
200
+ # @yieldparam [EVENT] prog The newly created Event object.
201
+ # @return [Integer]
202
+ # Return The High Event Count For A Given Host.
203
+ # @example
204
+ # host.high_severity_events do |high|
205
+ # puts high.name if high.name
206
+ # end
207
+ def high_severity_events(&block)
208
+
209
+ @high_severity_count = @host.at('num_hi').inner_text.to_i
210
+
211
+ unless @high_severity_events
212
+ @high_severity_events = []
213
+
214
+ @host.xpath("ReportItem").each do |event|
215
+ next if event.at('severity').inner_text.to_i != 3
216
+ @high_severity_events << Event.new(event)
217
+ end
218
+
219
+ end
220
+
221
+ @high_severity_events.each(&block)
222
+ return @high_severity_count
223
+ end
224
+
225
+ # Return the total event count for a given host.
226
+ # @return [Integer]
227
+ # Return the total event count for a given host.
228
+ # @example
229
+ # host.event_count #=> 3456
230
+ def event_count
231
+ ((low_severity_events.to_i) + (medium_severity_events.to_i) + (high_severity_events.to_i)).to_i
232
+ end
233
+
234
+ # Creates a new Event object to be parser
235
+ # @yield [prog] If a block is given, it will be passed the newly
236
+ # created Event object.
237
+ # @yieldparam [EVENT] prog The newly created Event object.
238
+ # @example
239
+ # host.events do |event|
240
+ # puts event.name if event.name
241
+ # puts event.port
242
+ # end
243
+ def each_event(&block)
244
+ @host.xpath("ReportItem").each do |event|
245
+ block.call(Event.new(event)) if block
246
+ end
247
+ end
248
+
249
+ # Parses the events of the host.
250
+ # @return [Array<String>]
251
+ # The events of the host.
252
+ def events
253
+ Enumerator.new(self,:each_event).to_a
254
+ end
255
+
256
+ end
257
+
258
+ end
259
+
260
+ end
@@ -0,0 +1,91 @@
1
+ module Nessus
2
+ module Version1
3
+
4
+ class Port
5
+
6
+ # Port Service
7
+ attr_reader :service
8
+ # Port number
9
+ attr_reader :number
10
+ # Port Protocol
11
+ attr_reader :protocol
12
+ # Raw output string from nessus
13
+ attr_reader :raw_string
14
+
15
+ # Creates A New Port Object
16
+ # @param [String] service The Port Service.
17
+ # @param [Integer] number The Port number.
18
+ # @param [String] protocol The Port protocol.
19
+ # @param [String] raw output string from nessus.
20
+ # @example
21
+ # Port.new("ssh",22,"tcp", str)
22
+ def initialize(service,number,protocol,raw_string)
23
+ @service = service
24
+ @number = number
25
+ @protocol = protocol
26
+ @raw_string = raw_string
27
+ end
28
+
29
+ # Parse A passed port string and return a Port Object.
30
+ # @return [Object]
31
+ # New Port Object
32
+ # @example
33
+ # Port.parse(port)
34
+ def Port.parse(str)
35
+ begin
36
+ @full_port = str
37
+ components = str.match(/^([^\(]+)\((\d+)\/([^\)]+)\)/)
38
+
39
+ if components
40
+ return Port.new(components[1].strip, components[2].strip, components[3].strip, str)
41
+ else
42
+ return Port.new(false, false, false, str)
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+
49
+ # Return true iF port protocol Ii tcp.
50
+ # @return [Boolean]
51
+ # Return True If The Port Protocol Is TCP.
52
+ def tcp?
53
+ @protocol == 'tcp'
54
+ end
55
+
56
+ # Return true iF port protocol Ii udp.
57
+ # @return [Boolean]
58
+ # Return True If The Port Protocol Is UDP.
59
+ def udp?
60
+ @protocol == 'udp'
61
+ end
62
+
63
+ # Return the port as a string.
64
+ # @return [String]
65
+ # Return The Port As A String
66
+ # @example
67
+ # port.to_s #=> https (443/tcp)
68
+ def to_s
69
+ if @service && @number && @protocol
70
+ "#{@service} (#{@number}/#{@protocol})"
71
+ else
72
+ "#{@raw_string}"
73
+ end
74
+ end
75
+
76
+ # Return false if the port object number is nil
77
+ # @return [Boolean]
78
+ # Return false if the port object number is nil
79
+ def number
80
+ if @number
81
+ return @number
82
+ else
83
+ false
84
+ end
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+
91
+ end
@@ -0,0 +1,391 @@
1
+ require 'ruby-nessus/Version1/host'
2
+ require 'ruby-nessus/Version1/event'
3
+
4
+ module Nessus
5
+
6
+ # .Nessus Version 2 Schema
7
+ module Version1
8
+
9
+ # File to parse
10
+ attr_reader :file
11
+
12
+ class XML
13
+
14
+ include Enumerable
15
+
16
+ #
17
+ # Creates a new .Nessus (XML) object to be parser
18
+ #
19
+ # @param [String] file The Nessus xml results file to parse.
20
+ #
21
+ # @yield [prog] If a block is given, it will be passed the newly
22
+ # created XML object.
23
+ #
24
+ # @yieldparam [XML] prog The newly created XML object.
25
+ #
26
+ # @example
27
+ # Nessus::XML.new(nessus_scan_file) do |scan|
28
+ # scan.report_name
29
+ # end
30
+ #
31
+ def initialize(file)
32
+ @file = File.open(file)
33
+ @xml = Nokogiri::XML.parse(@file.read)
34
+ raise "Error: Not A Version 1.0 .Nessus file." unless @xml.at('NessusClientData')
35
+ end
36
+
37
+ #
38
+ # Return the nessus report title.
39
+ #
40
+ # @return [String]
41
+ # The Nessus Report Title
42
+ #
43
+ # @example
44
+ # scan.report_name #=> "My Super Cool Nessus Report"
45
+ #
46
+ def title
47
+ @report_name ||= @xml.xpath("//NessusClientData//Report//ReportName").inner_text.split(' - ').last
48
+ end
49
+
50
+ #
51
+ # Return the nessus report time.
52
+ #
53
+ # @return [String]
54
+ # The Nessus Report Time
55
+ #
56
+ # @example
57
+ # scan.report_time #=> "09/11/08 02:21:22 AM"
58
+ #
59
+ def time
60
+ datetime = @xml.xpath("//NessusClientData//Report//ReportName").inner_text.split(' - ').first
61
+ @report_time ||= DateTime.strptime(datetime, fmt='%y/%m/%d %I:%M:%S %p')
62
+ end
63
+
64
+ #
65
+ # Return the scan start time.
66
+ #
67
+ # @return [DateTime]
68
+ # The Nessus Scan Start Time
69
+ #
70
+ # @example
71
+ # scan.start_time #=> 'Fri Nov 11 23:36:54 1985'
72
+ #
73
+ def start_time
74
+ @start_time = DateTime.strptime(@xml.xpath("//NessusClientData//Report//StartTime").inner_text, fmt='%a %b %d %H:%M:%S %Y')
75
+ end
76
+
77
+ #
78
+ # Return the scan stop time.
79
+ #
80
+ # @return [DateTime]
81
+ # The Nessus Scan Stop Time
82
+ #
83
+ # @example
84
+ # scan.stop_time #=> 'Mon Nov 11 23:36:54 1985'
85
+ #
86
+ def stop_time
87
+ @stop_time = DateTime.strptime(@xml.xpath("//NessusClientData//Report//StopTime").inner_text, fmt='%a %b %d %H:%M:%S %Y')
88
+ end
89
+
90
+ #
91
+ # Return the scan run time.
92
+ #
93
+ # @return [String]
94
+ # The Nessus Scan Run Time
95
+ #
96
+ # @example
97
+ # scan.runtime #=> '2 hours 5 minutes and 16 seconds'
98
+ #
99
+ def runtime
100
+ h = ("#{Time.parse(stop_time.to_s).strftime('%H').to_i - Time.parse(start_time.to_s).strftime('%H').to_i}").gsub('-', '')
101
+ m = ("#{Time.parse(stop_time.to_s).strftime('%M').to_i - Time.parse(start_time.to_s).strftime('%M').to_i}").gsub('-', '')
102
+ s = ("#{Time.parse(stop_time.to_s).strftime('%S').to_i - Time.parse(start_time.to_s).strftime('%S').to_i}").gsub('-', '')
103
+ return "#{h} hours #{m} minutes and #{s} seconds"
104
+ end
105
+
106
+ #
107
+ # Return the nessus scan policy name. When creating a nessus policy this is usually the title field.
108
+ #
109
+ # @return [String]
110
+ # The Nessus Scan Policy Name
111
+ #
112
+ def policy_title
113
+ @policy_name ||= @xml.xpath("//NessusClientData//Report//policyName").inner_text
114
+ end
115
+
116
+ #
117
+ # Return the nessus scan policy comments. This is the description field when creating a new policy with the Nessus GUI client.
118
+ #
119
+ # @return [String]
120
+ # The Nessus Scan Policy Comments
121
+ #
122
+ def policy_notes
123
+ @policy_comments ||= @xml.xpath("//NessusClientData//Report//policyComments").inner_text
124
+ end
125
+
126
+ #
127
+ # Returns and array of the plugin ids userd for the passed .nessus scan.
128
+ #
129
+ # @return [Array]
130
+ # The Nessus Scan Plugin Ids
131
+ #
132
+ # @example
133
+ # scan.plugin_ids #=> [1234,2343,9742,5452,5343,2423,1233]
134
+ #
135
+ def plugin_ids
136
+ unless @plugin_ids
137
+ @plugin_ids = []
138
+
139
+ @xml.xpath("//PluginSelection").last.text.split(';').each do |id|
140
+ @plugin_ids << id
141
+ end
142
+ end
143
+
144
+ @plugin_ids
145
+ end
146
+
147
+ #
148
+ # Returns and array of the plugin names userd for the passed .nessus scan.
149
+ #
150
+ # @return [Array]
151
+ # The Nessus Scan Plugin Names
152
+ #
153
+ # @example
154
+ # scan.plugins #=> ["PHP < 5.2.1 Multiple Vulnerabilities", "PHP < 4.4.1 / 5.0.6 Multiple Vulnerabilities"]
155
+ #
156
+ def plugins
157
+ unless @plugins
158
+ # get elements with attribute:
159
+ @plugins = []
160
+
161
+ @xml.xpath("//pluginName").each do |x|
162
+ @plugins << x.inner_text unless x.inner_text.empty?
163
+ end
164
+
165
+ @plugins.uniq!
166
+ @plugins.sort!
167
+ end
168
+
169
+ return @plugins
170
+ end
171
+
172
+ #
173
+ # Creates a new Host object to be parser
174
+ #
175
+ # @yield [prog] If a block is given, it will be passed the newly
176
+ # created Host object.
177
+ #
178
+ # @yieldparam [XML] prog The newly created Host object.
179
+ #
180
+ # @example
181
+ # scan.hosts do |host|
182
+ # puts host.hostname
183
+ # end
184
+ #
185
+ def each_host(&block)
186
+ hosts = []
187
+ @xml.xpath("//ReportHost").each do |host|
188
+ hosts << host.at('HostName').inner_text if host.at('HostName').inner_text
189
+ block.call(Host.new(host)) if block
190
+ end
191
+ hosts
192
+ end
193
+
194
+ #
195
+ # Parses the hosts of the scan.
196
+ #
197
+ # @return [Array<String>]
198
+ # The Hosts of the scan.
199
+ #
200
+ def hosts
201
+ Enumerator.new(self,:each_host).to_a
202
+ end
203
+
204
+ #
205
+ # Return the nessus scan host count.
206
+ #
207
+ # @return [Integer]
208
+ # The Nessus Scan Host Count
209
+ #
210
+ # @example
211
+ # scan.host_count #=> 23
212
+ #
213
+ def host_count
214
+ hosts.size
215
+ end
216
+
217
+ #
218
+ # Retunrs an array of all unique ports.
219
+ #
220
+ # @return [Array]
221
+ #
222
+ # @example
223
+ # scan.unique_ports #=> 234
224
+ #
225
+ def unique_ports
226
+ unless @unique_ports
227
+ @unique_ports = []
228
+ @xml.xpath("//ReportItem//port").each do |port|
229
+ @unique_ports << port.inner_text
230
+ end
231
+ @unique_ports.uniq!
232
+ @unique_ports.sort!
233
+ end
234
+ end
235
+
236
+ #
237
+ # Return the informational severity count.
238
+ #
239
+ # @return [Integer]
240
+ # The Informational Severity Count
241
+ #
242
+ # @example
243
+ # scan.informational_severity_count #=> 1203
244
+ #
245
+ def open_ports_count
246
+ count_severity[:open_ports].to_i
247
+ end
248
+
249
+ #
250
+ # Return the High severity count.
251
+ #
252
+ # @return [Integer]
253
+ # The High Severity Count
254
+ #
255
+ # @example
256
+ # scan.high_severity_count #=> 10
257
+ #
258
+ def high_severity_count
259
+ count_severity[:high].to_i
260
+ end
261
+
262
+ #
263
+ # Return the Medium severity count.
264
+ #
265
+ # @return [Integer]
266
+ # The Medium Severity Count
267
+ #
268
+ # @example
269
+ # scan.medium_severity_count #=> 234
270
+ #
271
+ def medium_severity_count
272
+ count_severity[:medium].to_i
273
+ end
274
+
275
+ #
276
+ # Return the Low severity count.
277
+ #
278
+ # @return [Integer]
279
+ # The Low Severity Count
280
+ #
281
+ # @example
282
+ # scan.low_severity_count #=> 114
283
+ #
284
+ def low_severity_count
285
+ count_severity[:low].to_i
286
+ end
287
+
288
+ #
289
+ # Return the Total severity count. [high, medium, low, informational]
290
+ #
291
+ # @return [Integer]
292
+ # The Total Severity Count
293
+ #
294
+ # @example
295
+ # scan.total_event_count #=> 1561
296
+ #
297
+ def total_event_count
298
+ count_severity[:all].to_i
299
+ end
300
+
301
+ #
302
+ # Return the Total severity count.
303
+ #
304
+ # @param [String] severity the severity in which to calculate percentage for.
305
+ #
306
+ # @param [Boolean] round round the result to the nearest whole number.
307
+ #
308
+ # @raise [ExceptionClass] One of the following severity options must be passed. [high, medium, low, informational, all]
309
+ #
310
+ # @return [Integer]
311
+ # The Percentage Of Events For A Passed Severity
312
+ #
313
+ # @example
314
+ # scan.event_percentage_for("low", true) #=> 11%
315
+ #
316
+ def event_percentage_for(type, round_percentage=false)
317
+ @sc ||= count_severity
318
+ if %W(high medium low all).include?(type)
319
+ calc = ((@sc[:"#{type}"].to_f / @sc[:all].to_f) * 100)
320
+ if round_percentage
321
+ return "#{calc.round}"
322
+ else
323
+ return "#{calc}"
324
+ end
325
+ else
326
+ raise "Error: #{type} is not an acceptable severity. Possible options include: all, high, medium, low and informational."
327
+ end
328
+ end
329
+
330
+ #
331
+ # Creates a new Host object to be parser from a passed search param.
332
+ #
333
+ # @param [String] hostname the hostname to build a Host object for.
334
+ #
335
+ # @yield [prog] If a block is given, it will be passed the newly
336
+ # created Host object.
337
+ #
338
+ # @yieldparam [XML] prog The newly created Host object.
339
+ #
340
+ # @example
341
+ # scan.find_by_hostname('127.0.0.1') do |host|
342
+ # puts host.hostname
343
+ # end
344
+ #
345
+ def find_by_hostname(hostname, &block)
346
+ raise "Error: hostname can't be blank." if hostname.blank?
347
+ @xml.xpath('//ReportHost[HostName]').each do |host|
348
+ next unless host.inner_text.match(hostname)
349
+ block.call(Host.new(host)) if block
350
+ end
351
+ end
352
+
353
+ private
354
+
355
+ #
356
+ # Calculates an event hash of totals for severity counts.
357
+ #
358
+ # @return [hash]
359
+ # The Event Totals For Severity
360
+ #
361
+ def count_severity
362
+ unless @count
363
+ @count = {}
364
+ @open_ports = 0
365
+ @low = 0
366
+ @medium = 0
367
+ @high = 0
368
+
369
+ @xml.xpath("//ReportHost").each do |s|
370
+ @open_ports += s.at('num_ports').inner_text.to_i
371
+ @low += s.at('num_lo').inner_text.to_i
372
+ @medium += s.at('num_med').inner_text.to_i
373
+ @high += s.at('num_hi').inner_text.to_i
374
+ end
375
+
376
+ @count = { :open_ports => @open_ports,
377
+ :low => @low,
378
+ :medium => @medium,
379
+ :high => @high,
380
+ :all => (@low + @medium + @high) }
381
+ end
382
+
383
+ return @count
384
+ end
385
+
386
+ end
387
+
388
+
389
+ end
390
+
391
+ end