ruby-nessus 0.1.4 → 1.0.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,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